需求
公司的PDF年報中有各種各樣的表格,需要對其中的某些具體的小標題下的表格解析出來,也就是所謂的數據結構化。
解決方案
通過看別人寫的博客,發現python裡面有關PDF解析的通常有以下四種:
- pdfminer,擅長僅僅是文字的解析,本小白試過了,是把表格解析成普通的文本,還經常會伴隨一些莫名奇妙的不認識的符號。這個方案pass掉
- pdf2html,看例是把pdf解析成html,但是html的標籤並沒有規律,解析一個還行,但是本小白是許多的pdf文檔下小標題的表格,這個方案直接pass掉
- tabula,這個是我看過的前輩寫的博客中使用最多的,本人用過了。對於簡單的表格,也就是單元格中沒有換行的,表頭表尾形式不復雜的,這個方案的值得推薦。電腦需要有Java的環境。
- pdfplumber,這個是看了知乎上的一個大佬的發現,並且自己安裝成功之後,發現最小眾,但是最符合我的需求的解決方案。前提是是需要安裝ImageMagick的
實施解決
本人一共使用了兩種方案解決了我的需求,分別是tabula和pdfplumber
先做前期的工作
1,將PDF文件轉化為JPG格式,進行搜索關鍵字,查看想要的表格的頁碼比如下圖中的風險管理狀況的得分表:
風險管理狀況
代碼如下:
#pdf 拆分為jpg
from pdf2image import convert_from_path,convert_from_bytes
import tempfile
import pdf2image
def pdf2image(I_path,O_path):
with tempfile.TemporaryDirectory() as path:
images_from_path = convert_from_path(I_path,output_folder=O_path,fmt='jpg')
I_path="/Users/gaohua/Desktop/33.PDF"
O_path="/Users/gaohua/Desktop/33"
pdf2image(I_path,O_path)
#文檔重命名
import os
path="/Users/gaohua/Desktop/33"
def rename_file(path):
for file in os.listdir(path):
os.rename(os.path.join(path,file),os.path.join(path,file[-5:]))
rename_file(path)
from aip import AipOcr
def baidu_aip(APP_ID,API_KEY,SECRET_KEY):
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
return(client)
APP_ID = '11659928'
API_KEY = 'Ogkg6buRucGnKtfeoamjg7rT'
SECRET_KEY = 'OlCLKVhaYMyqYwzvlaQ5uVgfUxzOlkcr'
client=baidu_aip(APP_ID,API_KEY,SECRET_KEY)
def get_file_content(path):
with open(path,'rb') as fp:
return fp.read()
def find_page(path,key_words):
for file in os.listdir(path)[1:-1]:
result = client.basicGeneral(get_file_content(os.path.join(path,file)))
for item in result["words_result"]:
# print(item["words"])#輸出解析的pdf文字
if key_words in item["words"]:
return (file.strip('.jpg'))
調用函數的輸出如下
key_words="風險管理狀況"
page=find_page(path,key_words)
print(page)
會輸出相應的頁碼
首先就是第一種方法:tabula
具體的操作方法如下:
import tabula
# Read pdf into DataFrame
df = tabula.read_pdf("/Users/gaohua/Desktop/33.pdf",pages=str(page))
df
這個直接返回的是一個數據幀,所以就直接是結構化的數據啦!
輸出結果是這樣的:
這樣的話,我們就已經完成了我們的需求啦!後續的關於寫入的Excel中中的話,在下就部多言啦!可以移步熊貓或者為pywin32哦!
雖然塔布拉是很方便,但是它的輸出是真的不方便,而且還需要裝的的的java的環境,JAVA的環境變量不好搞
有時候還會輸出亂七八糟的東西,比如有時候會輸出繁體的中文,我就遇到過...
所以保險起見
這裡再給出第二個解決方案:
再次就是二個解決方案pdfplumber
import pdfplumber
pdf = pdfplumber.open("/Users/gaohua/Desktop/33.pdf")
p0 = pdf.pages[int(page)-1]#注意此處的pages是一個列表,索引是從0開始的
table = p0.extract_table()
import pandas as pd
df = pd.DataFrame(table[1:], columns=table[0])
df
輸出如下:
雖然為了展示對比的方便,這裡都是用了同樣的一個表格,但是方案2的解決真的要比1好
別問我為啥知道2比1好,你試試用1去解析一些帶有文字格式的表格,帶有複雜的表頭的表格,你就知道啦!我在這裡並沒有在瞎說,而且還得裝的的java的,後者只裝一個的ImageMagick的就行,而且ImageMagick的很有用的
總結
本次一共總和運用了百度OCR的接口,百度AIP這個東西嘛!這簡直就是男人的寶庫!自己去看看就知道啦!
還有就是使用了PDF格式的解析的包
但是還是有不足的哦,就是這兩個解決方案都是針對於比較乖巧的表格的,就是橫線和豎線都比較完整的表格的,像下面的這種表格:
閱讀更多 訊宜捷科技 的文章