Python:解析PDF文本及表格——pdfminer、tabula、pdfplumber 的用法及對比


pdf 是個異常坑爹的東西,有很多處理 pdf 的庫,但是沒有完美的。

一、pdfminer3k

pdfminer3k 是 pdfminer 的 python3 版本,主要用於讀取 pdf 中的文本。

網上有很多 pdfminer3k 的代碼示例,看過以后,只想吐槽一下,太復雜了,有違 python 的簡潔。

from pdfminer.pdfparser import PDFParser, PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LAParams, LTTextBox
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed

path = "test.pdf"

# 用文件對象來創建一個pdf文檔分析器
praser = PDFParser(open(path, 'rb'))
# 創建一個PDF文檔
doc = PDFDocument()
# 連接分析器 與文檔對象
praser.set_document(doc)
doc.set_parser(praser)

# 提供初始化密碼
# 如果沒有密碼 就創建一個空的字符串
doc.initialize()

# 檢測文檔是否提供txt轉換,不提供就忽略
if not doc.is_extractable:
    raise PDFTextExtractionNotAllowed
else:
    # 創建PDf 資源管理器 來管理共享資源
    rsrcmgr = PDFResourceManager()
    # 創建一個PDF設備對象
    laparams = LAParams()
    device = PDFPageAggregator(rsrcmgr, laparams=laparams)
    # 創建一個PDF解釋器對象
    interpreter = PDFPageInterpreter(rsrcmgr, device)

    # 循環遍歷列表,每次處理一個page的內容
    for page in doc.get_pages():
        interpreter.process_page(page)                        
        # 接受該頁面的LTPage對象
        layout = device.get_result()
        # 這里layout是一個LTPage對象,里面存放着這個 page 解析出的各種對象
        # 包括 LTTextBox, LTFigure, LTImage, LTTextBoxHorizontal 等                            
        for x in layout:
            if isinstance(x, LTTextBox):
                print(x.get_text().strip())

 

pdfminer 對於表格的處理非常的不友好,能提取出文字,但是沒有格式:

pdf表格截圖:

代碼運行結果:

 

想把這個結果還原成表格可不容易,加的規則太多必然導致通用性的下降。

 

二、tabula-py

tabula 是專門用來提取PDF表格數據的,同時支持PDF導出為CSV、Excel格式,但是這工具是用 java 寫的,依賴 java7/8。tabula-py 就是對它做了一層 python 的封裝,所以也依賴 java7/8。

代碼很簡單:

import tabula

path = 'test.pdf'

df = tabula.read_pdf(path, encoding='gbk', pages='all')
for indexs in df.index:
    print(df.loc[indexs].values)

# tabula.convert_into(path, os.path.splitext(path)[0]+'.csv', pages='all')

雖然號稱是專業處理 pdf 中的表格的,但實際效果也不咋地。還是 pdfminer 中使用的 pdf,運行結果如下:

這結果真的很尷尬啊,表頭識別就錯了,還有 pdf 中有兩張表,我沒發現怎么區分表。

 

三、pdfplumber

pdfplumber 是按頁來處理 pdf 的,可以獲得頁面的所有文字,並且提供的單獨的方法用於提取表格。

import pdfplumber

path = 'test.pdf'
pdf = pdfplumber.open(path)

for page in pdf.pages:
    # 獲取當前頁面的全部文本信息,包括表格中的文字
    # print(page.extract_text())                        

    for table in page.extract_tables():
        # print(table)
        for row in table:
            print(row)
        print('---------- 分割線 ----------')

pdf.close()

得到的 table 是個 string 類型的二維數組,這里為了跟 tabula 比較,按行輸出顯示。

可以看到,跟 tabula 相比,首先是可以區分表格,其次,准確率也提高了很多,表頭的識別完全正確。對於表格中有換行的,識別還不是很正確,但至少列的划分沒問題,所以還是能處理的。

import pdfplumber
import re

path = 'test1.pdf'
pdf = pdfplumber.open(path)

for page in pdf.pages:
    print(page.extract_text())
    for pdf_table in page.extract_tables():
        table = []
        cells = []
        for row in pdf_table:
            if not any(row):
                # 如果一行全為空,則視為一條記錄結束
                if any(cells):
                    table.append(cells)
                    cells = []
            elif all(row):
                # 如果一行全不為空,則本條為新行,上一條結束
                if any(cells):
                    table.append(cells)
                    cells = []
                table.append(row)
            else:
                if len(cells) == 0:
                    cells = row
                else:
                    for i in range(len(row)):
                        if row[i] is not None:
                            cells[i] = row[i] if cells[i] is None else cells[i] + row[i]
        for row in table:
            print([re.sub('\s+', '', cell) if cell is not None else None for cell in row])
        print('---------- 分割線 ----------')

pdf.close()

經過處理后,運行得到結果:

這結果已經完全正確了,而用 tabula,即便是經過處理也是無法得到這樣的結果的。當然對於不同的 pdf,可能需要不同的處理,實際情況還是要自己分析。

pdfplumber 也有處理不准確的時候,主要表現在缺列:

我找了另一個 pdf,表格部分截圖如下:

解析結果如下:

4列變成了兩列,另外,如果表格有合並單元格的情況,也會有這種問題,我挑這個表格展示是因為比較特殊,沒有合並單元格也缺列了。這應該跟 pdf 生成的時候有關。

但其實數據是獲取完整的,並沒有丟,只是被認為是非表格了。輸出 page.extract_text() 如下:

 

然后,我又用 tabula 試了下,結果如下:

列是齊了,但是,表頭呢???

 

pdfplumber 還提供了圖形Debug功能,可以獲得PDF頁面的截圖,並且用方框框起識別到的文字或表格,幫助判斷PDF的識別情況,並且進行配置的調整。要使用這個功能,還需要安裝ImageMagick。因為沒有用到,所以暫時沒有去細究。

 

四、后記

我們在做爬蟲的時候,難免會遇到 pdf 需要解析,主要還是針對文本和表格的數據提取。而 python 處理 pdf 的庫實在是太多太多了,比如還有 pypdf2,網上資料也比較多,但是我試了,讀出來是亂碼,沒有仔細的讀源碼所以這個問題也沒有解決。

而我對比較常用的3個庫比較后覺得,還是 pdfplumber 比較好用,對表格的支持最好。

 


相關博文推薦:

Python:讀取 .doc、.docx 兩種 Word 文件簡述及“Word 未能引發事件”錯誤

ref:https://www.cnblogs.com/gl1573/p/10064438.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM