python读取pdf表格_【Python 库】解析PDF文本及表格——pdfminer、tabula、pdfplumber 的用法及对比...
pdf 是個異常坑爹的東西,有很多處理 pdf 的庫,但是沒有完美的。
一、pdfminer3k
pdfminer3k 是 pdfminer 的 python3 版本,主要用于讀取 pdf 中的文本。
網(wǎng)上有很多 pdfminer3k 的代碼示例,看過以后,只想吐槽一下,太復(fù)雜了,有違 python 的簡潔。
from pdfminer.pdfparser importPDFParser, PDFDocumentfrom pdfminer.pdfinterp importPDFResourceManager, PDFPageInterpreterfrom pdfminer.converter importPDFPageAggregatorfrom pdfminer.layout importLAParams, LTTextBoxfrom pdfminer.pdfinterp importPDFTextExtractionNotAllowed
path= "test.pdf"
#用文件對象來創(chuàng)建一個pdf文檔分析器
praser = PDFParser(open(path, 'rb'))#創(chuàng)建一個PDF文檔
doc =PDFDocument()#連接分析器 與文檔對象
praser.set_document(doc)
doc.set_parser(praser)#提供初始化密碼#如果沒有密碼 就創(chuàng)建一個空的字符串
doc.initialize()#檢測文檔是否提供txt轉(zhuǎn)換,不提供就忽略
if notdoc.is_extractable:raisePDFTextExtractionNotAllowedelse:#創(chuàng)建PDf 資源管理器 來管理共享資源
rsrcmgr =PDFResourceManager()#創(chuàng)建一個PDF設(shè)備對象
laparams =LAParams()
device= PDFPageAggregator(rsrcmgr, laparams=laparams)#創(chuàng)建一個PDF解釋器對象
interpreter =PDFPageInterpreter(rsrcmgr, device)#循環(huán)遍歷列表,每次處理一個page的內(nèi)容
for page indoc.get_pages():
interpreter.process_page(page)#接受該頁面的LTPage對象
layout =device.get_result()#這里layout是一個LTPage對象,里面存放著這個 page 解析出的各種對象
#包括 LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等
for x inlayout:ifisinstance(x, LTTextBox):print(x.get_text().strip())
pdfminer 對于表格的處理非常的不友好,能提取出文字,但是沒有格式:
pdf表格截圖:
代碼運行結(jié)果:
想把這個結(jié)果還原成表格可不容易,加的規(guī)則太多必然導(dǎo)致通用性的下降。
二、tabula-py
tabula 是專門用來提取PDF表格數(shù)據(jù)的,同時支持PDF導(dǎo)出為CSV、Excel格式,但是這工具是用 java 寫的,依賴 java7/8。tabula-py 就是對它做了一層 python 的封裝,所以也依賴 java7/8。
代碼很簡單:
importtabula
path= 'test.pdf'df= tabula.read_pdf(path, encoding='gbk', pages='all')for indexs indf.index:print(df.loc[indexs].values)#tabula.convert_into(path, os.path.splitext(path)[0]+'.csv', pages='all')
雖然號稱是專業(yè)處理 pdf 中的表格的,但實際效果也不咋地。還是 pdfminer 中使用的 pdf,運行結(jié)果如下:
這結(jié)果真的很尷尬啊,表頭識別就錯了,還有 pdf 中有兩張表,我沒發(fā)現(xiàn)怎么區(qū)分表。
三、pdfplumber
pdfplumber 是按頁來處理 pdf 的,可以獲得頁面的所有文字,并且提供的單獨的方法用于提取表格。
importpdfplumber
path= 'test.pdf'pdf=pdfplumber.open(path)for page inpdf.pages:#獲取當(dāng)前頁面的全部文本信息,包括表格中的文字
#print(page.extract_text())
for table inpage.extract_tables():#print(table)
for row intable:print(row)print('---------- 分割線 ----------')
pdf.close()
得到的 table 是個 string 類型的二維數(shù)組,這里為了跟 tabula 比較,按行輸出顯示。
可以看到,跟 tabula 相比,首先是可以區(qū)分表格,其次,準(zhǔn)確率也提高了很多,表頭的識別完全正確。對于表格中有換行的,識別還不是很正確,但至少列的劃分沒問題,所以還是能處理的。
importpdfplumberimportre
path= 'test1.pdf'pdf=pdfplumber.open(path)for page inpdf.pages:print(page.extract_text())for pdf_table inpage.extract_tables():
table=[]
cells=[]for row inpdf_table:if notany(row):#如果一行全為空,則視為一條記錄結(jié)束
ifany(cells):
table.append(cells)
cells=[]elifall(row):#如果一行全不為空,則本條為新行,上一條結(jié)束
ifany(cells):
table.append(cells)
cells=[]
table.append(row)else:if len(cells) ==0:
cells=rowelse:for i inrange(len(row)):if row[i] is notNone:
cells[i]= row[i] if cells[i] is None else cells[i] +row[i]for row intable:print([re.sub('\s+', '', cell) if cell is not None else None for cell inrow])print('---------- 分割線 ----------')
pdf.close()
經(jīng)過處理后,運行得到結(jié)果:
這結(jié)果已經(jīng)完全正確了,而用 tabula,即便是經(jīng)過處理也是無法得到這樣的結(jié)果的。當(dāng)然對于不同的 pdf,可能需要不同的處理,實際情況還是要自己分析。
pdfplumber 也有處理不準(zhǔn)確的時候,主要表現(xiàn)在缺列:
我找了另一個 pdf,表格部分截圖如下:
解析結(jié)果如下:
4列變成了兩列,另外,如果表格有合并單元格的情況,也會有這種問題,我挑這個表格展示是因為比較特殊,沒有合并單元格也缺列了。這應(yīng)該跟 pdf 生成的時候有關(guān)。
但其實數(shù)據(jù)是獲取完整的,并沒有丟,只是被認(rèn)為是非表格了。輸出 page.extract_text() 如下:
然后,我又用 tabula 試了下,結(jié)果如下:
列是齊了,但是,表頭呢???
pdfplumber 還提供了圖形Debug功能,可以獲得PDF頁面的截圖,并且用方框框起識別到的文字或表格,幫助判斷PDF的識別情況,并且進行配置的調(diào)整。要使用這個功能,還需要安裝ImageMagick。因為沒有用到,所以暫時沒有去細(xì)究。
四、后記
我們在做爬蟲的時候,難免會遇到 pdf 需要解析,主要還是針對文本和表格的數(shù)據(jù)提取。而 python 處理 pdf 的庫實在是太多太多了,比如還有 pypdf2,網(wǎng)上資料也比較多,但是我試了,讀出來是亂碼,沒有仔細(xì)的讀源碼所以這個問題也沒有解決。
而我對比較常用的3個庫比較后覺得,還是 pdfplumber 比較好用,對表格的支持最好。
相關(guān)博文推薦:
總結(jié)
以上是生活随笔為你收集整理的python读取pdf表格_【Python 库】解析PDF文本及表格——pdfminer、tabula、pdfplumber 的用法及对比...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现图形旋转_python轻
- 下一篇: websocket python爬虫_p