手把手教你如何用Python從PDF檔案中匯出資料(附連結)
有很多時候你會想用Python從PDF中提取資料,然後將其匯出成其他格式。不幸的是,並沒有多少Python包可以很好的執行這部分工作。在這篇貼子中,我們將探討多個不同的Python包,並學習如何從PDF中提取某些圖片。儘管在Python中沒有一個完整的解決方案,你還是應該能夠運用這裡的技能開始上手。提取出想要的資料之後,我們還將研究如何將資料匯出成其他格式。
讓我們從如何提取文字開始學起!
使用PDFMiner提取文字
最被大家所熟知的可能是一個叫做PDFMiner的包。PDFMiner包大約從Python 2.4版本就存在了。它的主要目的是從PDF中提取文字。實際上,PDFMiner可以告訴你某文字在分頁上具體的位置和字型資訊。對於Python 2.4到2.7版本,你可以參考以下網站來了解PDFMiner的更多資訊:
GitHub – https://github.com/euske/pdfminer PyPI – https://pypi.python.org/pypi/pdfminer/ Webpage – https://euske.github.io/pdfminer/
PDFMiner是不兼容於Python 3的。幸運的是,PDFMiner家族的一個分支PDFMiner.six在Python 3上完全能勝任同樣的功能。
你可以在以下網站上找到:
https://github.com/pdfminer/pdfminer.six
關於PDFMiner的安裝說明已經比較過時了。其實你可以用pip命令來安裝它:
如果你要在Python 3上安裝PDFMiner(這也許就是你現在正在做的),你需要這樣安裝:
PDFMiner的相關文件很少。你將很大可能地需要使用Google和Stack Overflow兩個查詢工具來弄清楚如何在這篇貼子的涵蓋內容之外有效地使用PDFMiner。
提取所有文字
有時你會想要提取PDF檔案中的所有文字。PDFMiner包提供了一些不同的方法使你能夠做到這一點。我們先來探討一些程式設計的方法。讓我們試著從一個國稅局W9表單中讀取所有的文字。
你可以從這裡得到表單副本:
https://www.irs.gov/pub/irs-pdf/fw9.pdf
儲存完這個PDF檔案之後,你可以參考以下程式碼:
當你直接使用PDFMiner包時,往往會有點繁瑣。這裡,我們從PDFMiner的不同模組中引入多個不同的類。由於這些類都沒有文件說明,也沒有實現其文件字串屬性,我將不會深入講解它們做了什麼。如果你真的好奇的話,儘管可以深入地研究它們的原始碼。無論如何,我認為我們可以大致照以上程式碼行事。
我們做的第一件事就是建立一個資源管理器的例項。然後通過Python的輸入輸出(io)模組建立一個似檔案物件。如果你使用的是Python 2,你應該使用StringIO模組。接下來的步驟是建立一個轉換器。在這個例子裡,我們選擇使用TextConverter,如果你想要的話,你還可以使用HTMLConverter或XMLConverter。最後,我們建立一個PDF直譯器物件,攜帶著我們的資源管理器和轉換器物件,來提取文字。
最後一步是開啟PDF檔案並且迴圈遍歷每一頁。結尾部分,我們抓取所有的文字,關閉不同的資訊處理器,同時列印文字到標準輸出(stdout)。
按頁提取文字
通常我們並不需要從一個多頁文件中抓取所有的文字。你一般會想要處理文件的某些部分。那麼,讓我們改寫程式碼以便它提取文字呈分頁的格式。這將允許我們在檢查文字時,一次一頁地進行:
在這個例子中,我們建立了一個生成器函式按頁 生成(yield) 了文字。extract_text函式按頁打印出文字。此處我們可以加入一些分析邏輯來得到我們想要的分析結果。或者我們可以僅是將文字(或HTML或XML)存入不同的檔案中以便分析。
你可能注意到這些文字沒有按你期望的順序排列。因此你需要思考一些方法來分析出你感興趣的文字。
PDFMiner的好處就是你可以很方便地按文字、HTML或XML格式來“匯出”PDF檔案。
你也可以使用PDFMiner的命令列工具, pdf2txt.py 和 dumppdf.py ,來為你執行匯出工作。如果你不想試圖自己弄明白PDFMiner。根據 pdf2txt.py 的原始碼,它可以被用來匯出PDF成純文字、HTML、XML或“標籤”格式。
通過pdf2txt.py匯出文字
伴隨著PDFMiner一起的pdf2txt.py命令列工具會從一個PDF檔案中提取文字並且預設將其列印至標準輸出(stdout)。它不能識別文字圖片,就像PDFMiner不支援光學字元識別(OCR)一樣。讓我們嘗試用最簡單的方法來使用它,那就是僅僅傳遞給它一個PDF檔案的路徑。我們會使用w9.pdf檔案。 開啟一個終端並且定位到你存放PDF檔案的位置,或修改一下命令指向待處理檔案:
如果你執行這條命令,它將打印出所有的文字到標準輸出(stdout)。你也可以使pdf2txt.py 將文字寫入檔案成文字、HTML、XML或“帶標籤PDF”格式。XML格式將給出關於PDF的大部分資訊,因為它包含了每一個字母在檔案中的位置以及字型資訊。不推薦使用HTML格式,因為pdf2txt生成的標記往往會很醜。以下是教你如何生成不同格式輸出的方法:
第一條命令將建立一個HTML檔案,而第二條將建立一個XML檔案。
最終的結果看上去有點怪,但是它並不太糟糕。XML格式的輸出極其冗長,因此我不能將它完整地在這裡重現,以下是一小段示例:
使用Slate提取文字
Tim McNamara覺得PDFMiner使用起來太過愚蠢和費力,因此他寫了一個圍繞它的包裝器叫做slate,以使它更簡單地從PDF中提取文字。不幸的是,它和Python 3不相容。如果你想試用,你可能需要easy_install以便於安裝distribute包,如下:
我不能使用pip 正確安裝這個包。然而一旦安裝了它,你將能夠使用pip來安裝slate:
注意最新的版本是0.5.2,而pip未必能拿到這個版本。如果拿不到,那麼你可以從GitHub上直接獲取slate安裝:
現在我們已經準備好寫一些程式碼來從PDF中提取文字了:
正如你能看到的,讓slate分析一個PDF檔案,你只需要引進slate然後建立一個它的PDF類的例項。PDF類其實是Python內建類list的一個子類,所以它僅是返回了一列/可遍歷的文字頁。如果PDF檔案設有密碼,你可以傳入一個密碼引數。不管怎樣,一旦檔案被分析,我們只要打印出每一頁的文字即可。
我非常喜歡slate,它用起來更簡單。不幸的是,這個包也幾乎沒有什麼相關文件。在瀏覽過它的原始碼之後,它看起來只支援純文字提取。
匯出你的資料
現在我們得到了一些文字,我們會花費一些時間來學習如何匯出資料成各種不同的格式。具體來說,我們將學習如何以如下方法匯出文字:
讓我們開始吧!
匯出成XML
可擴充套件標記語言(XML)格式是最為人所熟知的輸入輸出格式之一。它被廣泛運用於網際網路中的許多不同的事物。正如我們已經在本貼中看到的,PDFMiner也支援XML作為它的輸出之一。
話雖這麼說,讓我們建立我們自己的XML生成工具。如下是一個簡單的例子:
這段程式碼將使用Python內建的XML庫, minidom 和 ElementTree 。我們也引入PDFMiner生成器程式碼以用於每次抓取一頁文字。在這個例子中,我們用PDF的檔名建立了我們頂層的元素。然後在它的下層增加了一個頁(Pages) 元素。下一步是for迴圈,在此迴圈中我們從PDF中提取每一頁然後儲存想要的資訊。此處你可以加入一個特定的分析程式,其中你可以將頁分成句子或者單詞,從而分析出更有趣的資訊。比如,你可能只想得到有某個特定名字或日期/時間戳的句子。你可以運用Python的正則表示式來找出這類東西,或者僅是檢查子字串在句子中的存在。
對於這個例子,我們僅僅是提取了每一頁的前100個字元並將其存入一個XML的 子元素(SubElement) 中。接下來的一段程式碼可以簡化成僅是寫出XML檔案。然而,ElementTree不會做任何事來使得XML易讀。它最後看上去有點像壓縮的JavaScript似的一塊巨型文字。所以我們在寫入檔案之前使用minidom 通過空格來“美化”XML,而不是將整塊文字寫入磁碟。最終看上去像這樣:
上面是漂亮乾淨的XML,同時它也是易讀的。錦上添花的是,你可以運用你在PyPDF2章節中所學到的知識從PDF中提取元資料(metadata),然後將其也加入到XML中。
匯出成JSON
JavaScript物件註釋, 或者JSON, 是一種易讀易寫的輕量級的資料交換格式。Python包含一個json 模組於它的標準庫中,從而允許你用程式設計方式來讀寫JSON。讓我們運用從前一章節學到的內容來建立一個匯出器指令碼來輸出JSON而不是XML:
這裡,我們引入所需要的不同的庫,包括PDFMiner模組。然後建立一個函式,以PDF檔案的輸入路徑和JSON檔案的輸出路徑為引數。在Python中JSON基本上就是一個字典,所以我們建立一對簡單的頂層的鍵:Filename和Pages。Pages鍵對應一個空的表單。接著,我們迴圈遍歷PDF的每一頁並且提取每一頁的前100個字元。然後建立一個字典變數以頁號作為鍵100個字元作為值並將其新增到頂層的頁表單中。最後,我們利用json 模組的dump 命令生成檔案。
檔案的內容最終看上去像這樣:
又一次,我們得到了易讀的輸出。你也可以通過PDF的元資料(metadata)來加強這個例子,如果你樂意的話。請注意輸出將會改變,它依賴於你想從每一頁或文件中分析出什麼樣的結果。
現在讓我們來快速看一下怎樣匯出CSV檔案。
匯出成CSV
CSV是 **comma separated values** (逗號分隔值)的縮寫。它是一種漂亮的標準格式,並且已經存在了很長時間。CSV的優點就是Microsoft Excel和 LibreOffice都能夠自動地以漂亮的電子表格的方式將它們開啟。你也可以在一個文字編輯器中開啟CSV檔案,如果你樂意看到它的原始值的話。
Python有一個內建的csv 模組,你可以用它來讀寫CSV檔案。在這裡我們將用它從我們由PDF中提取的文字來建立一個CSV。讓我們看一下程式碼:
這個例子中,我們引入了Python的csv庫。除此以外,引入的庫和前一個例子相同。在函式中,我們利用CSV檔案路徑建立了一個CSV檔案處理器。然後用檔案處理器作為唯一的引數初始化了一個CSV寫入器物件。接著像之前一樣遍歷了PDF頁。這裡唯一的不同就是我們將前100個字元分割成了單個的詞。這將允許我們擁有一些真實的資料來加入到CSV中。如果不這樣做,那麼每一行將只會有一個元素在其中,那就不算一個真正的CSV檔案了。最後,我們將一列單詞寫入CSV檔案中。
這就是得到的結果:
我認為這個例子同JSON或XML的例子相比讀起來難了點,但是它不算太難。現在讓我們繼續來看一下怎樣才能將圖片從PDF中提取出來。
從PDF中提取圖片
不幸的是,並不存在Python包可以真正地做到從PDF中提取圖片。我找到的最接近的東西是有一個叫 minecart 的專案宣稱可以做到這一點,但是它只在Python 2.7上有效。我沒法使其運行於我的PDF樣本。在NedBatchelder的部落格上有一篇文章談到了一點兒如何從PDF中提取JPG圖片。程式碼如下:
這同樣對我使用的PDF檔案無效。有一些人在留言中宣稱程式碼對他們的一些PDF檔案有效,同時也有一些留言例舉了修改後的程式碼。Stack Overflow網站上有關於這個的各種程式碼,其中一些這樣或那樣地使用了PyPDF2。但沒有一個對我有效。
我的建議是使用一個類似於 Poppler 的工具來提取圖片。Poppler有一個工具叫做 pdfimages,你可以同Python的subprocess模組一起來使用。以下是你如何在沒有Python的情況下使用它:
請確保images資料夾(或你想新建的任何輸出資料夾)已經被建立,因為pdfimages不會為你建立它。
讓我們寫一個Python指令碼來執行同樣的命令,請確保輸出資料夾已經存在:
在這個例子中,我們引入了subprocess和os模組。如果輸出路徑不存在,我們會嘗試建立它。然後我們運用subprocess的call函式來執行pdfimages命令。使用call函式是因為它將等到 pdfimages命令完全執行完才返回。你可以代之以Popen,但是那將基本上在後臺執行命令程序。最後,我們打印出輸出路徑下的細節,以確定所有的圖片都被提取進了其中。
還有一些網路上的其它文章引用了一個叫做 Wand 的庫,你也許可以試一試。它是一個ImageMagick的包裝器。還有一個值得關注的是綁定了Poppler的Python叫做 pypoppler , 雖然我沒有能夠找到任何和這個包相關的提取圖片的例子。
總結
這篇文章網羅了很多資訊。我們學習了一些可以用來從PDF中提取文字的包,如PDFMiner或Slate。我們還學習瞭如何運用Python的內建庫來匯出文字到XML、JSON和CSV。最後,我們研究了一下從PDF中匯出圖片這個棘手的問題。儘管Python目前沒有任何出色的庫可以完成這個工作,你可以採用其它工具的變通方案,例如Poppler的pdfimage工具模組。
原文標題:
Exporting Data From PDFs With Python
原文連結:
https://dzone.com/articles/exporting-data-from-pdfs-with-python