【python辦公自動化】將Word文本和Pdf表格數據提取並整合到同一個Exeel下的多sheet中

1. 背景及前期準備

1.1 背景介紹

在參加比賽過程中,需要獲取江蘇省科學技術獎近十年的數據,因此需要在官網上獲取相應的數據,再查找數據的過程中發現,官網中給出的數據,並不是完整的可以直接拿來用的

比如:

① 2018-2019年的人員及項目名單是pdf的形式給出,

② 2015、2017年的內容直接附在發佈的公告後面(純文字的)

③ 2008-2011、 2014、2016年的內容是以doc的形式給出

④ 2012-2013年的可以找到xls形式數據

因此需要將數據進行整合,數據最後的表現形式就是每一年的數據,都提取整合到Excel表中。

具體要求:

① 將doc、pdf和網頁裏面的文字數據提取到Excel表格中,表格的名稱爲:xxx年年度江蘇省科學技術獎.xlsx

② 將一、二、三等獎數據分別放置在該表格下的三個sheet中,sheet的名稱爲:一等獎、二等獎、三等獎

1.2 需要安裝的庫

這裏用到python自帶的庫:os庫(系統文件創建)、re(字符數據匹配)、glob(文件路徑選擇)

用到的python第三方庫有:pandas(數據處理的)、pdfplumber(pdf表格數據提取)、python-docx(doc文本數據提取)

安裝上訴第三方庫,推薦使用鏡像安裝,安裝的指令如下

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pandas pdfplumber python-docx

2. 數據處理

2.1 數據提取

① 因爲獲取的doc形式的數據,使用python-docx庫無法直接處理,所以將doc形式的數據轉到新建的docx文件中

② 網頁的文本數據,直接複製粘貼到docx文件中

③ xls數據直接轉化爲目標格式的xlsx數據

④ pdf數據直接提取表格數據

2.2 具體過程

2.2.1 docx數據的處理

難點:

① 目標數據的提取

② 一二三等獎的數據劃分

③ 將數據寫入同一個Excel表格的不同sheet中並命名

前面的數據提取已經將所有待處理的doc數據都轉化爲docx數據,這裏進行數據提取,docx文件中的數據格式如下:
在這裏插入圖片描述
通過觀察發現,docx中列舉出的數據是有一定的數據格式的,因此可以將數據讀取之後用正則表達式進行目標數據的匹配

這裏以2016年的數據進行試錯,代碼如下

import re
from docx import Document
import pandas as pd

doc = Document('2016年度江蘇省科學技術獎.docx')
content = ''
for paragraph in doc.paragraphs:
  content += paragraph.text

print(content[:1000])

→ 輸出的結果爲:(可以發現數據直接存在着空格,爲了方便匹配數據,需要將空格先去掉)
在這裏插入圖片描述
接着進行空格的替換處理

s = content[:1000].replace('  ','')
print(s)

→ 輸出的結果爲:(之前的空格已經被剔除了)
在這裏插入圖片描述
★★★★★難點1: 提取目標字段的數據,這一步需要有一定正則匹配數據的功底,代碼如下,提取的數據格式可以直接轉化爲用來生成DataFrame的數據

infos = re.findall(r'(\d+).(.*?)完成單位:(.*?)主要完成人:(\D+)',content)
data = pd.DataFrame(infos, columns = ['序號','項目名稱','完成單位','完成人'])

→ 輸出的結果爲:(直接查看data變量的值,這裏只列舉部分)
在這裏插入圖片描述
★★★★難點2: 因爲一、二、三等獎都是整個DataFrame中,因此困難在於找到數據的分割點,好在這裏公佈的數據是每個獎項進行排序,都是從1開始,因此只要找到1的位置並獲取對應的索引即可,然後獲取一、二、三等獎

split_row = data[data['序號'].isin(['1'])].index.tolist()
print(split_row)
data_1 = data.iloc[:split_row[1]]
data_2 = data.iloc[split_row[1]:split_row[2]]
data_3 = data.iloc[split_row[2]:]

→ 輸出的結果爲:(數據提取就是基於1所在的索引位置進行切片)

[0, 30, 78]

★★★ 難點3: 多DataFrame數據寫入同一個Excel表格中,這裏處理的方式屬於先命名每一個sheet的名稱,然後進行遍歷數據寫入,代碼如下

ls = ['一等獎','二等獎','三等獎']
writer = pd.ExcelWriter('demo.xlsx')
for i in range(3):
    eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
writer.save()
writer.close()

→ 輸出的結果爲:(數據已經按要求整理好了,唯一需要手動清理的就是最後一行的多出來的一點數據)
在這裏插入圖片描述

2.2.2 docx數據的處理完整代碼

保留數據接口,可以使用glob進行文件路徑的獲取,然後遍歷循環進行所有文件數據的轉化,可以查看之前的使用glob整合多個Excel文件

import re
from docx import Document
import pandas as pd

def filter_docx_data(file_name):
    doc = Document(f'{file_name}.docx')
    content = ''
    for paragraph in doc.paragraphs:
      content += paragraph.text
    # print(content[:1000])
    content = content.replace('\xa0','')
    infos = re.findall(r'(\d+).(.*?)完成單位:(.*?)主要完成人:(\D+)',content)
    data = pd.DataFrame(infos, columns = ['序號','項目名稱','完成單位','完成人'])
    # print(data.head())
    split_row = data[data['序號'].isin(['1'])].index.tolist()
    # print(split_row)
    data_1 = data.iloc[:split_row[1]]
    data_2 = data.iloc[split_row[1]:split_row[2]]
    data_3 = data.iloc[split_row[2]:]
    
    ls = ['一等獎','二等獎','三等獎']
    writer = pd.ExcelWriter(f'filtered_data/{file_name}.xlsx')
    for i in range(3):
        eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
    writer.save()
    writer.close()
    
if __name__ == '__main__':

  filter_docx_data('2016年度江蘇省科學技術獎')
  

2.2.3 pdf數據的處理及完整代碼

查看一下pdf的數據樣式,文件中的數據如下:
在這裏插入圖片描述
針對表格數據的提取,這裏使用到了pdfplumber模塊,首先提取數據,這裏進行第一頁的表格數據的提取代碼如下

import pdfplumber
import pandas as pd
import os

with pdfplumber.open("2018年度江蘇省科學技術獎.pdf") as pdf:
     page_num = len(pdf.pages)
     data= pdf.pages[0].extract_table()
     print(data)

→ 輸出的結果爲:(可以發現pdf第一頁表格的第一行是標題欄,對應提取表格的第一個元素,因此就可以獲取第一個元素作爲DataFrame數據的列標題)
在這裏插入圖片描述
接下來的處理就有點和docx數據的處理類似了,轉化爲DataFrame數據後進行一、二、三等獎的提取,最後再存入Excel中。

但是這裏有個小細節的問題,2018年pdf的列舉獲獎名單的方式和2019年的不一樣,其中2018年的是按照docx數據一樣,一二三等獎都是以1開頭,但是2019年的是隻有一個1,其餘的二三等獎的序號都是基於一等獎序號的累加,因此這裏需要着重注意一下,代碼如下

import pdfplumber
import pandas as pd
import os

#這一步是創建一個文件夾,將處理好的數據文件放置在其中
if not os.path.exists('filtered_data'):
    os.mkdir('filtered_data')

def filtering_data_2018(file_name):
    data_list = []
    with pdfplumber.open(f"{file_name}.pdf") as pdf:
        page_num = len(pdf.pages)
        data_columns = pdf.pages[0].extract_table()[0]
        for i in range(page_num):
            data_page = pdf.pages[i].extract_table()[1:]
            data_list.extend(data_page)
    
        data = pd.DataFrame(data_list,columns = data_columns)
        split_row = data[data['序號'].isin(['1'])].index.tolist()
        print(split_row)
        data_1 = data.iloc[:split_row[1]]
        data_2 = data.iloc[split_row[1]:split_row[2]]
        data_3 = data.iloc[split_row[2]:]
        
        ls = ['一等獎','二等獎','三等獎']
        writer = pd.ExcelWriter(f'filtered_data/{file_name}.xlsx')
        for i in range(3):
            eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
        writer.save()
        writer.close()

def filtering_data_2019(file_name):
    data_list = []
    with pdfplumber.open(f"{file_name}.pdf") as pdf:
        page_num = len(pdf.pages)
        data_columns = pdf.pages[0].extract_table()[0]
        for i in range(page_num):
            data_page = pdf.pages[i].extract_table()[1:]
            data_list.extend(data_page)
    
        data = pd.DataFrame(data_list,columns = data_columns)
        split_row = data[data['序號'].isin(['46','129'])].index.tolist()
        print(split_row)
        data_1 = data.iloc[:split_row[0]]
        data_2 = data.iloc[split_row[0]:split_row[1]]
        data_3 = data.iloc[split_row[1]:]
        
        ls = ['一等獎','二等獎','三等獎']
        writer = pd.ExcelWriter(f'filtered_data/{file_name}.xlsx')
        for i in range(3):
            eval(f'data_{i+1}').to_excel(writer,sheet_name = ls[i], index = False)
        writer.save()
        writer.close()

if __name__ == '__main__':
    filtering_data_2018('2018年度江蘇省科學技術獎')
    filtering_data_2019('2019年度江蘇省科學技術獎')

關於xls數據的處理,就不介紹了,本來數據整理的格式就是很好,只需要將表格的數據複製粘貼到對應的sheet中命名,最後另存爲xlsx數據即可(只是爲了和之前生成文件的格式一致)

3. 最終結果

數據處理完畢後,就會在創建的filtered_data文件夾下,如下圖
在這裏插入圖片描述
代碼測試所需要的文件已經全部上傳到資源

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章