PDF文件格式
如今凌节,可移植文檔格式(PDF)屬于最常用的數(shù)據(jù)格式。在1990年洒试,PDF文檔的結(jié)構(gòu)由Adobe定義倍奢。PDF格式的思想是,對于通信過程中涉及的雙方(創(chuàng)建者垒棋,作者或發(fā)送者以及接收者)而言卒煞,傳輸?shù)臄?shù)據(jù)/文檔看起來完全相同。
工具和庫
適用于Python的PDF工具叼架,模塊和庫的可用解決方案范圍有些混亂畔裕,需要花一點時間弄清楚什么是什么,以及哪些項目需要連續(xù)維護乖订。根據(jù)我們的研究扮饶,以下是最新的候選人:
PyPDF2:一個Python庫,用于提取文檔信息和內(nèi)容乍构,逐頁拆分文檔甜无,合并文檔,裁剪頁面并添加水印哥遮。PyPDF2支持未加密和加密的文檔岂丘。
PDFMiner:完全用Python編寫,適用于Python 2.4眠饮。對于Python 3奥帘,請使用克隆的包PDFMiner.six。這兩個軟件包都允許您解析君仆,分析和轉(zhuǎn)換PDF文檔翩概。這包括對PDF 1.7以及CJK語言(中文,日文和韓文)的支持返咱,以及各種字體類型(Type1,TrueType牍鞠,Type3和CID)咖摹。
pdflib for Python:Poppler庫的擴展,為它提供了Python綁定难述。它使您可以解析萤晴,分析和轉(zhuǎn)換PDF文檔吐句。不要將其與具有相同名稱的商業(yè)吊墜相混淆。
PyFPDF:一個在Python下生成PDF文檔的庫店读。從FPDF PHP庫移植而來嗦枢,這是著名的PDFlib擴展替換,其中包含許多示例屯断,腳本和派生類文虏。
PDFTables:一項商業(yè)服務,提供從PDF文檔附帶的表格中提取的內(nèi)容殖演。提供一個API氧秘,以便PDFTables可以用作SAAS。
PyX -Python圖形包:PyX是用于創(chuàng)建PostScript趴久,PDF和SVG文件的Python包丸相。它結(jié)合了PostScript繪圖模型的抽象和TeX / LaTeX接口。這些基元可以構(gòu)建復雜的任務彼棍,例如以可發(fā)布的質(zhì)量創(chuàng)建2D和3D繪圖灭忠。
ReportLab:一個雄心勃勃的,具有行業(yè)實力的圖書館座硕,主要致力于精確創(chuàng)建PDF文檔弛作。免費提供開放源代碼版本和名為ReportLab PLUS的商業(yè)增強版本。
PyMuPDF(又稱“ fitz”):MuPDF的Python綁定坎吻,這是一種輕量級的PDF和XPS查看器缆蝉。該庫可以訪問PDF,XPS瘦真,OpenXPS刊头,epub,漫畫和小說書格式的文件诸尽,并且以其最佳性能和高渲染質(zhì)量而聞名原杂。
pdfrw:一個基于Python的純PDF解析器,用于讀寫PDF您机。它忠實地再現(xiàn)矢量格式而無需光柵化穿肄。與ReportLab結(jié)合使用時,它有助于在使用ReportLab創(chuàng)建的新PDF中重用現(xiàn)有PDF的一部分际看。
圖書館 | 用于 |
---|---|
PyPDF2 | 讀 |
PyMuPDF | 讀 |
pdflib | 讀 |
PDF表格 | 讀 |
PDFMiner.six | 讀 |
PDF查詢 | 讀 |
pdfrw | 讀咸产,寫/創(chuàng)作 |
PyFPDF | 寫/創(chuàng)作 |
我們將重點介紹PyPDF2和PyMuPDF,并說明如何以最簡單的方式提取文本和圖像仲闽。為了了解PyPDF2的用法脑溢,官方文檔和許多其他資源提供的示例的組合對您有所幫助。相比之下赖欣,官方PyMuPDF文檔更加清晰屑彻,并且使用該庫的速度也大大加快验庙。
使用PyPDF2提取文本
$ pip3 install PyPDF2
清單1首先導入了PdfFileReader
該類。接下來社牲,使用該類打開文檔粪薛,并使用getDocumentInfo()
方法提取文檔信息,使用提取頁數(shù)getDocumentInfo()
以及第一頁的內(nèi)容搏恤。
請注意违寿,PyPDF2從0開始計數(shù)頁面,這就是該調(diào)用pdf.getPage(0)
檢索文檔第一頁的原因挑社。最終陨界,提取的信息被打印到stdout
。
清單1:提取文檔信息和內(nèi)容痛阻。
#!/usr/bin/python
from PyPDF2 import PdfFileReader
pdf_document = "example.pdf"
with open(pdf_document, "rb") as filehandle:
pdf = PdfFileReader(filehandle)
info = pdf.getDocumentInfo()
pages = pdf.getNumPages()
print (info)
print ("number of pages: %i" % pages)
page1 = pdf.getPage(0)
print(page1)
print(page1.extractText())
如上面的圖1所示菌瘪,提取的文本是連續(xù)打印的。沒有段落或句子分隔阱当。如PyPDF2文檔中所述俏扩,所有文本數(shù)據(jù)都按照在頁面內(nèi)容流中提供的順序返回,并且依靠它可能會導致一些意外弊添。這主要取決于PDF文檔的內(nèi)部結(jié)構(gòu)录淡,以及PDF編寫器過程如何生成PDF指令流。
使用PyMuPDF提取文本
可從PyPi網(wǎng)站上獲取PyMuPDF油坝,并在終端中使用以下命令安裝軟件包:
$ pip3 install PyMuPDF
顯示文檔信息嫉戚,打印頁數(shù)以及提取PDF文檔的文本的方式與PyPDF2相似(請參見清單2)。要導入的模塊名為fitz
澈圈,并返回到PyMuPDF的先前名稱彬檀。
清單2:使用PyMuPDF從PDF文檔中提取內(nèi)容。
#!/usr/bin/python
import fitz
pdf_document = "example.pdf"
doc = fitz.open(pdf_document)
print ("number of pages: %i" % doc.pageCount)
print(doc.metadata)
page1 = doc.loadPage(0)
page1text = page1.getText("text")
print(page1text)
PyMuPDF的優(yōu)點是可以保持原始文檔結(jié)構(gòu)完整-帶有換行符的整個段落都保留在PDF文檔中(參見圖2)瞬女。
使用PyMuPDF從PDF提取圖像
PyMuPDF使用該方法簡化了從PDF文檔提取圖像的過程getPageImageList()
窍帝。清單3基于PyMuPDF Wiki頁面上的示例,并逐頁地將PDF中的所有圖像提取并保存為PNG文件诽偷。如果圖像具有CMYK色彩空間坤学,則將首先將其轉(zhuǎn)換為RGB。
清單3:提取圖像
#!/usr/bin/python
import fitz
pdf_document = fitz.open("file.pdf")
for current_page in range(len(pdf_document)):
for image in pdf_document.getPageImageList(current_page):
xref = image[0]
pix = fitz.Pixmap(pdf_document, xref)
if pix.n < 5: # this is GRAY or RGB
pix.writePNG("page%s-%s.png" % (current_page, xref))
else: # CMYK: convert to RGB first
pix1 = fitz.Pixmap(fitz.csRGB, pix)
pix1.writePNG("page%s-%s.png" % (current_page, xref))
pix1 = None
pix = None
在400頁PDF上運行此Python腳本报慕,它在不到3秒的時間內(nèi)提取了117張圖像深浮,這真是了不起。單個圖像以PNG格式存儲眠冈。為了保持原始圖像的格式和大小略号,而不是轉(zhuǎn)換為PNG,請查看PyMuPDF Wiki中腳本的擴展版本洋闽。
使用PyPDF2將PDF拆分為頁面
對于此示例玄柠,首先需要同時導入PdfFileReader
和和PdfFileWriter
類。然后诫舅,我們打開PDF文件羽利,創(chuàng)建一個閱讀器對象,并使用閱讀器對象的getNumPages
方法遍歷所有頁面刊懈。
在for
循環(huán)內(nèi)部这弧,我們創(chuàng)建的新實例PdfFileWriter
,該實例尚不包含任何頁面虚汛。然后匾浪,使用pdfWriter.addPage()
方法將當前頁面添加到我們的writer對象。此方法接受一個頁面對象卷哩,我們使用該PdfFileReader.getPage()
方法獲取該對象蛋辈。
下一步是創(chuàng)建一個唯一的文件名,我們使用原始文件名加上單詞“ page”以及頁碼來完成将谊。我們在當前頁碼上加1冷溶,因為PyPDF2會計算從零開始的頁碼。
最后尊浓,我們以“寫二進制”模式(mode wb
)打開新文件名逞频,并使用該類的write()
方法pdfWriter
將提取的頁面保存到磁盤。
清單4:將PDF拆分為單個頁面栋齿。
#!/usr/bin/python
from PyPDF2 import PdfFileReader, PdfFileWriter
pdf_document = "example.pdf"
pdf = PdfFileReader(pdf_document)
for page in range(pdf.getNumPages()):
pdf_writer = PdfFileWriter()
current_page = pdf.getPage(page)
pdf_writer.addPage(current_page)
outputFilename = "example-page-{}.pdf".format(page + 1)
with open(outputFilename, "wb") as out:
pdf_writer.write(out)
print("created", outputFilename)
查找所有包含文本的頁面
這個用例非常實用苗胀,并且工作方式類似于pdfgrep
。該腳本使用PyMuPDF返回包含給定搜索字符串的所有頁碼瓦堵。頁面一頁接一頁地加載基协,借助該searchFor()
方法,將檢測到搜索字符串的所有出現(xiàn)情況谷丸。如果匹配則在上面印有相應的信息stdout
堡掏。
清單5:搜索給定的文本。
#!/usr/bin/python
import fitz
filename = "example.pdf"
search_term = "invoice"
pdf_document = fitz.open(filename):
for current_page in range(len(pdf_document)):
page = pdf_document.loadPage(current_page)
if page.searchFor(search_term):
print("%s found on page %i" % (search_term, current_page))
下面的圖5顯示了一本400頁的書中“ Debian GNU / Linux”一詞的搜索結(jié)果刨疼。
結(jié)論
此處顯示的處理PDF方法非常強大泉唁。使用相對較少的代碼行數(shù),很容易獲得結(jié)果揩慕。