Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
者:Mike Driscoll
翻譯:季洋
校對(duì):丁楠雅
本文約4000字,建議閱讀10分鐘。
本文介紹了在提取出想要的數(shù)據(jù)之后,如何將數(shù)據(jù)導(dǎo)出成其他格式的方法。
有很多時(shí)候你會(huì)想用Python從PDF中提取數(shù)據(jù),然后將其導(dǎo)出成其他格式。不幸的是,并沒有多少Python包可以很好的執(zhí)行這部分工作。在這篇貼子中,我們將探討多個(gè)不同的Python包,并學(xué)習(xí)如何從PDF中提取某些圖片。盡管在Python中沒有一個(gè)完整的解決方案,你還是應(yīng)該能夠運(yùn)用這里的技能開始上手。提取出想要的數(shù)據(jù)之后,我們還將研究如何將數(shù)據(jù)導(dǎo)出成其他格式。
讓我們從如何提取文本開始學(xué)起!
最被大家所熟知的可能是一個(gè)叫做PDFMiner的包。PDFMiner包大約從Python 2.4版本就存在了。它的主要目的是從PDF中提取文本。實(shí)際上,PDFMiner可以告訴你某文本在分頁上具體的位置和字體信息。對(duì)于Python 2.4到2.7版本,你可以參考以下網(wǎng)站來了解PDFMiner的更多信息:
GitHub – https://github.com/euske/pdfminerPyPI – https://pypi.python.org/pypi/pdfminer/Webpage – https://euske.github.io/pdfminer/
PDFMiner是不兼容于Python 3的。幸運(yùn)的是,PDFMiner家族的一個(gè)分支PDFMiner.six在Python 3上完全能勝任同樣的功能。
你可以在以下網(wǎng)站上找到:
https://github.com/pdfminer/pdfminer.six
關(guān)于PDFMiner的安裝說明已經(jīng)比較過時(shí)了。其實(shí)你可以用pip命令來安裝它:
如果你要在Python 3上安裝PDFMiner(這也許就是你現(xiàn)在正在做的),你需要這樣安裝:
PDFMiner的相關(guān)文檔很少。你將很大可能地需要使用Google和Stack Overflow兩個(gè)查詢工具來弄清楚如何在這篇貼子的涵蓋內(nèi)容之外有效地使用PDFMiner。
有時(shí)你會(huì)想要提取PDF文件中的所有文本。PDFMiner包提供了一些不同的方法使你能夠做到這一點(diǎn)。我們先來探討一些編程的方法。讓我們?cè)囍鴱囊粋€(gè)國稅局W9表單中讀取所有的文本。
你可以從這里得到表單副本:
https://www.irs.gov/pub/irs-pdf/fw9.pdf
保存完這個(gè)PDF文件之后,你可以參考以下代碼:
當(dāng)你直接使用PDFMiner包時(shí),往往會(huì)有點(diǎn)繁瑣。這里,我們從PDFMiner的不同模塊中引入多個(gè)不同的類。由于這些類都沒有文檔說明,也沒有實(shí)現(xiàn)其文檔字符串屬性,我將不會(huì)深入講解它們做了什么。如果你真的好奇的話,盡管可以深入地研究它們的源代碼。無論如何,我認(rèn)為我們可以大致照以上代碼行事。
我們做的第一件事就是創(chuàng)建一個(gè)資源管理器的實(shí)例。然后通過Python的輸入輸出(io)模塊創(chuàng)建一個(gè)似文件對(duì)象。如果你使用的是Python 2,你應(yīng)該使用StringIO模塊。接下來的步驟是創(chuàng)建一個(gè)轉(zhuǎn)換器。在這個(gè)例子里,我們選擇使用TextConverter,如果你想要的話,你還可以使用HTMLConverter或XMLConverter。最后,我們創(chuàng)建一個(gè)PDF解釋器對(duì)象,攜帶著我們的資源管理器和轉(zhuǎn)換器對(duì)象,來提取文本。
最后一步是打開PDF文件并且循環(huán)遍歷每一頁。結(jié)尾部分,我們抓取所有的文本,關(guān)閉不同的信息處理器,同時(shí)打印文本到標(biāo)準(zhǔn)輸出(stdout)。
通常我們并不需要從一個(gè)多頁文檔中抓取所有的文本。你一般會(huì)想要處理文檔的某些部分。那么,讓我們改寫代碼以便它提取文本呈分頁的格式。這將允許我們?cè)跈z查文本時(shí),一次一頁地進(jìn)行:
在這個(gè)例子中,我們創(chuàng)建了一個(gè)生成器函數(shù)按頁生成(yield)了文本。extract_text函數(shù)按頁打印出文本。此處我們可以加入一些分析邏輯來得到我們想要的分析結(jié)果。或者我們可以僅是將文本(或HTML或XML)存入不同的文件中以便分析。
你可能注意到這些文本沒有按你期望的順序排列。因此你需要思考一些方法來分析出你感興趣的文本。
PDFMiner的好處就是你可以很方便地按文本、HTML或XML格式來“導(dǎo)出”PDF文件。
你也可以使用PDFMiner的命令行工具,pdf2txt.py和dumppdf.py,來為你執(zhí)行導(dǎo)出工作。如果你不想試圖自己弄明白PDFMiner。根據(jù)pdf2txt.py 的源代碼,它可以被用來導(dǎo)出PDF成純文本、HTML、XML或“標(biāo)簽”格式。
通過pdf2txt.py導(dǎo)出文本
伴隨著PDFMiner一起的pdf2txt.py命令行工具會(huì)從一個(gè)PDF文件中提取文本并且默認(rèn)將其打印至標(biāo)準(zhǔn)輸出(stdout)。它不能識(shí)別文字圖片,就像PDFMiner不支持光學(xué)字符識(shí)別(OCR)一樣。讓我們嘗試用最簡單的方法來使用它,那就是僅僅傳遞給它一個(gè)PDF文件的路徑。我們會(huì)使用w9.pdf文件。打開一個(gè)終端并且定位到你存放PDF文件的位置,或修改一下命令指向待處理文件:
如果你執(zhí)行這條命令,它將打印出所有的文本到標(biāo)準(zhǔn)輸出(stdout)。你也可以使pdf2txt.py 將文本寫入文件成文本、HTML、XML或“帶標(biāo)簽PDF”格式。XML格式將給出關(guān)于PDF的大部分信息,因?yàn)樗嗣恳粋€(gè)字母在文件中的位置以及字體信息。不推薦使用HTML格式,因?yàn)閜df2txt生成的標(biāo)記往往會(huì)很丑。以下是教你如何生成不同格式輸出的方法:
第一條命令將創(chuàng)建一個(gè)HTML文件,而第二條將創(chuàng)建一個(gè)XML文件。
最終的結(jié)果看上去有點(diǎn)怪,但是它并不太糟糕。XML格式的輸出極其冗長,因此我不能將它完整地在這里重現(xiàn),以下是一小段示例:
Tim McNamara覺得PDFMiner使用起來太過愚蠢和費(fèi)力,因此他寫了一個(gè)圍繞它的包裝器叫做slate,以使它更簡單地從PDF中提取文本。不幸的是,它和Python 3不兼容。如果你想試用,你可能需要easy_install以便于安裝distribute包,如下:
我不能使用pip 正確安裝這個(gè)包。然而一旦安裝了它,你將能夠使用pip來安裝slate:
注意最新的版本是0.5.2,而pip未必能拿到這個(gè)版本。如果拿不到,那么你可以從GitHub上直接獲取slate安裝:
現(xiàn)在我們已經(jīng)準(zhǔn)備好寫一些代碼來從PDF中提取文本了:
正如你能看到的,讓slate分析一個(gè)PDF文件,你只需要引進(jìn)slate然后創(chuàng)建一個(gè)它的PDF類的實(shí)例。PDF類其實(shí)是Python內(nèi)置類list的一個(gè)子類,所以它僅是返回了一列/可遍歷的文本頁。如果PDF文件設(shè)有密碼,你可以傳入一個(gè)密碼參數(shù)。不管怎樣,一旦文件被分析,我們只要打印出每一頁的文本即可。
我非常喜歡slate,它用起來更簡單。不幸的是,這個(gè)包也幾乎沒有什么相關(guān)文檔。在瀏覽過它的源碼之后,它看起來只支持純文本提取。
導(dǎo)出你的數(shù)據(jù)
現(xiàn)在我們得到了一些文本,我們會(huì)花費(fèi)一些時(shí)間來學(xué)習(xí)如何導(dǎo)出數(shù)據(jù)成各種不同的格式。具體來說,我們將學(xué)習(xí)如何以如下方法導(dǎo)出文本:
讓我們開始吧!
可擴(kuò)展標(biāo)記語言(XML)格式是最為人所熟知的輸入輸出格式之一。它被廣泛運(yùn)用于互聯(lián)網(wǎng)中的許多不同的事物。正如我們已經(jīng)在本貼中看到的,PDFMiner也支持XML作為它的輸出之一。
話雖這么說,讓我們創(chuàng)建我們自己的XML生成工具。如下是一個(gè)簡單的例子:
這段代碼將使用Python內(nèi)置的XML庫,minidom和ElementTree。我們也引入PDFMiner生成器代碼以用于每次抓取一頁文本。在這個(gè)例子中,我們用PDF的文件名創(chuàng)建了我們頂層的元素。然后在它的下層增加了一個(gè)頁(Pages)元素。下一步是for循環(huán),在此循環(huán)中我們從PDF中提取每一頁然后保存想要的信息。此處你可以加入一個(gè)特定的分析程序,其中你可以將頁分成句子或者單詞,從而分析出更有趣的信息。比如,你可能只想得到有某個(gè)特定名字或日期/時(shí)間戳的句子。你可以運(yùn)用Python的正則表達(dá)式來找出這類東西,或者僅是檢查子字符串在句子中的存在。
對(duì)于這個(gè)例子,我們僅僅是提取了每一頁的前100個(gè)字符并將其存入一個(gè)XML的子元素(SubElement)中。接下來的一段代碼可以簡化成僅是寫出XML文件。然而,ElementTree不會(huì)做任何事來使得XML易讀。它最后看上去有點(diǎn)像壓縮的JavaScript似的一塊巨型文本。所以我們?cè)趯懭胛募笆褂胢inidom 通過空格來“美化”XML,而不是將整塊文本寫入磁盤。最終看上去像這樣:
上面是漂亮干凈的XML,同時(shí)它也是易讀的。錦上添花的是,你可以運(yùn)用你在PyPDF2章節(jié)中所學(xué)到的知識(shí)從PDF中提取元數(shù)據(jù)(metadata),然后將其也加入到XML中。
JavaScript對(duì)象注釋, 或者JSON, 是一種易讀易寫的輕量級(jí)的數(shù)據(jù)交換格式。Python包含一個(gè)json 模塊于它的標(biāo)準(zhǔn)庫中,從而允許你用編程方式來讀寫JSON。讓我們運(yùn)用從前一章節(jié)學(xué)到的內(nèi)容來創(chuàng)建一個(gè)導(dǎo)出器腳本來輸出JSON而不是XML:
這里,我們引入所需要的不同的庫,包括PDFMiner模塊。然后創(chuàng)建一個(gè)函數(shù),以PDF文件的輸入路徑和JSON文件的輸出路徑為參數(shù)。在Python中JSON基本上就是一個(gè)字典,所以我們創(chuàng)建一對(duì)簡單的頂層的鍵:Filename和Pages。Pages鍵對(duì)應(yīng)一個(gè)空的表單。接著,我們循環(huán)遍歷PDF的每一頁并且提取每一頁的前100個(gè)字符。然后創(chuàng)建一個(gè)字典變量以頁號(hào)作為鍵100個(gè)字符作為值并將其添加到頂層的頁表單中。最后,我們利用json 模塊的dump 命令生成文件。
文件的內(nèi)容最終看上去像這樣:
又一次,我們得到了易讀的輸出。你也可以通過PDF的元數(shù)據(jù)(metadata)來加強(qiáng)這個(gè)例子,如果你樂意的話。請(qǐng)注意輸出將會(huì)改變,它依賴于你想從每一頁或文檔中分析出什么樣的結(jié)果。
現(xiàn)在讓我們來快速看一下怎樣導(dǎo)出CSV文件。
CSV是 **comma separated values** (逗號(hào)分隔值)的縮寫。它是一種漂亮的標(biāo)準(zhǔn)格式,并且已經(jīng)存在了很長時(shí)間。CSV的優(yōu)點(diǎn)就是Microsoft Excel和 LibreOffice都能夠自動(dòng)地以漂亮的電子表格的方式將它們打開。你也可以在一個(gè)文本編輯器中打開CSV文件,如果你樂意看到它的原始值的話。
Python有一個(gè)內(nèi)置的csv 模塊,你可以用它來讀寫CSV文件。在這里我們將用它從我們由PDF中提取的文本來創(chuàng)建一個(gè)CSV。讓我們看一下代碼:
這個(gè)例子中,我們引入了Python的csv庫。除此以外,引入的庫和前一個(gè)例子相同。在函數(shù)中,我們利用CSV文件路徑創(chuàng)建了一個(gè)CSV文件處理器。然后用文件處理器作為唯一的參數(shù)初始化了一個(gè)CSV寫入器對(duì)象。接著像之前一樣遍歷了PDF頁。這里唯一的不同就是我們將前100個(gè)字符分割成了單個(gè)的詞。這將允許我們擁有一些真實(shí)的數(shù)據(jù)來加入到CSV中。如果不這樣做,那么每一行將只會(huì)有一個(gè)元素在其中,那就不算一個(gè)真正的CSV文件了。最后,我們將一列單詞寫入CSV文件中。
這就是得到的結(jié)果:
我認(rèn)為這個(gè)例子同JSON或XML的例子相比讀起來難了點(diǎn),但是它不算太難。現(xiàn)在讓我們繼續(xù)來看一下怎樣才能將圖片從PDF中提取出來。
不幸的是,并不存在Python包可以真正地做到從PDF中提取圖片。我找到的最接近的東西是有一個(gè)叫minecart的項(xiàng)目宣稱可以做到這一點(diǎn),但是它只在Python 2.7上有效。我沒法使其運(yùn)行于我的PDF樣本。在Ned Batchelder的博客上有一篇文章談到了一點(diǎn)兒如何從PDF中提取JPG圖片。代碼如下:
這同樣對(duì)我使用的PDF文件無效。有一些人在留言中宣稱代碼對(duì)他們的一些PDF文件有效,同時(shí)也有一些留言例舉了修改后的代碼。Stack Overflow網(wǎng)站上有關(guān)于這個(gè)的各種代碼,其中一些這樣或那樣地使用了PyPDF2。但沒有一個(gè)對(duì)我有效。
我的建議是使用一個(gè)類似于Poppler 的工具來提取圖片。Poppler有一個(gè)工具叫做pdfimages,你可以同Python的subprocess模塊一起來使用。以下是你如何在沒有Python的情況下使用它:
請(qǐng)確保images文件夾(或你想新建的任何輸出文件夾)已經(jīng)被創(chuàng)建,因?yàn)閜dfimages不會(huì)為你創(chuàng)建它。
讓我們寫一個(gè)Python腳本來執(zhí)行同樣的命令,請(qǐng)確保輸出文件夾已經(jīng)存在:
在這個(gè)例子中,我們引入了subprocess和os模塊。如果輸出路徑不存在,我們會(huì)嘗試創(chuàng)建它。然后我們運(yùn)用subprocess的call函數(shù)來執(zhí)行pdfimages命令。使用call函數(shù)是因?yàn)樗鼘⒌鹊?pdfimages命令完全執(zhí)行完才返回。你可以代之以Popen,但是那將基本上在后臺(tái)運(yùn)行命令進(jìn)程。最后,我們打印出輸出路徑下的細(xì)節(jié),以確定所有的圖片都被提取進(jìn)了其中。
還有一些網(wǎng)絡(luò)上的其它文章引用了一個(gè)叫做Wand 的庫,你也許可以試一試。它是一個(gè)ImageMagick的包裝器。還有一個(gè)值得關(guān)注的是綁定了Poppler的Python叫做pypoppler,雖然我沒有能夠找到任何和這個(gè)包相關(guān)的提取圖片的例子。
這篇文章網(wǎng)羅了很多信息。我們學(xué)習(xí)了一些可以用來從PDF中提取文本的包,如PDFMiner或Slate。我們還學(xué)習(xí)了如何運(yùn)用Python的內(nèi)置庫來導(dǎo)出文本到XML、JSON和CSV。最后,我們研究了一下從PDF中導(dǎo)出圖片這個(gè)棘手的問題。盡管Python目前沒有任何出色的庫可以完成這個(gè)工作,你可以采用其它工具的變通方案,例如Poppler的pdfimage工具模塊。
原文標(biāo)題:
Exporting Data From PDFs With Python
原文鏈接:
https://dzone.com/articles/exporting-data-from-pdfs-with-python
譯者簡介
季洋,蘇州某IT公司技術(shù)總監(jiān),從業(yè)20年,現(xiàn)在主要負(fù)責(zé)Java項(xiàng)目的方案和管理工作。對(duì)大數(shù)據(jù)、數(shù)據(jù)挖掘和分析項(xiàng)目躍躍欲試卻苦于沒有機(jī)會(huì)和數(shù)據(jù)。目前正在摸索和學(xué)習(xí)中,也報(bào)了一些線上課程,希望對(duì)數(shù)據(jù)建模的應(yīng)用場景有進(jìn)一步的了解。不能成為巨人,只希望可以站在巨人的肩膀上了解數(shù)據(jù)科學(xué)這個(gè)有趣的世界。
— 完 —
關(guān)注清華-青島數(shù)據(jù)科學(xué)研究院官方微信公眾平臺(tái)“THU數(shù)據(jù)派”及姊妹號(hào)“數(shù)據(jù)派THU”獲取更多講座福利及優(yōu)質(zhì)內(nèi)容。
y_web.py(更新)
tml2pdf
Selenium 通過使用 WebDriver 支持市場上所有主流瀏覽器的自動(dòng)化。 Webdriver 是一個(gè) API 和協(xié)議,它定義了一個(gè)語言中立的接口,用于控制 web 瀏覽器的行為。 每個(gè)瀏覽器都有一個(gè)特定的 WebDriver 實(shí)現(xiàn),稱為驅(qū)動(dòng)程序。 驅(qū)動(dòng)程序是負(fù)責(zé)委派給瀏覽器的組件,并處理與 Selenium 和瀏覽器之間的通信。
這種分離是有意識(shí)地努力讓瀏覽器供應(yīng)商為其瀏覽器的實(shí)現(xiàn)負(fù)責(zé)的一部分。 Selenium 在可能的情況下使用這些第三方驅(qū)動(dòng)程序, 但是在這些驅(qū)動(dòng)程序不存在的情況下,它也提供了由項(xiàng)目自己維護(hù)的驅(qū)動(dòng)程序。
Selenium 框架通過一個(gè)面向用戶的界面將所有這些部分連接在一起, 該界面允許透明地使用不同的瀏覽器后端, 從而實(shí)現(xiàn)跨瀏覽器和跨平臺(tái)自動(dòng)化。
# selenium 驅(qū)動(dòng)
https://selenium-python.readthedocs.io/installation.html#drivers
https://selenium-python.readthedocs.io/api.html
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.16.1</version>
</dependency>
// 獲取 java 版本
String version=System.getProperty("java.specification.version");
// 獲取系統(tǒng)類型
String platform=System.getProperty("os.name", "");
platform=platform.toLowerCase().contains("window") ? "win" : "linux";
// 當(dāng)前程序目錄
String current=System.getProperty("user.dir");
System.out.println("current:" + current);
// firefox 運(yùn)行參數(shù)配置
FirefoxOptions options=new FirefoxOptions();
// 無頭模式
options.addArguments("--headless");
// 最大化
options.addArguments("--start-maximized");
FirefoxDriver browser=new FirefoxDriver(options);
Path url=Paths.get(current, "..", "index.html");
System.out.println("url:" + url.toString());
// NOTE 要使用 file 協(xié)議
browser.get(String.format("file://%s", url.toString()));
// 打印設(shè)置
PrintOptions print=new PrintOptions();
Pdf pdf=browser.print(print);
// pdf base64 內(nèi)容
String content=pdf.getContent();
// 解碼內(nèi)容
Base64.Decoder decoder=Base64.getDecoder();
byte[] buffer=decoder.decode(content);
try {
// 將 byte 寫入文件
Path file=Paths.get(String.format("java%s_%s.pdf", version, platform));
Files.write(file, buffer);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
browser.quit();
}
selenium/java11_linux.pdf · yjihrp/linux-html2pdf-demo - Gitee.com
selenium/java11_win.pdf · yjihrp/linux-html2pdf-demo - Gitee.com
測試結(jié)果
下一篇 6-LINUX HTML 轉(zhuǎn) PDF-selenium-python
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。