數據整合
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文件夾下,如下圖
代碼測試所需要的文件已經全部上傳到資源