1. 程式人生 > >Python操作PDF-文字和圖片提取(使用PyPDF2和PyMuPDF)

Python操作PDF-文字和圖片提取(使用PyPDF2和PyMuPDF)

### PDF檔案格式 如今,可移植文件格式(PDF)屬於最常用的資料格式。在1990年,PDF文件的結構由Adobe定義。PDF格式的思想是,對於通訊過程中涉及的雙方(建立者,作者或傳送者以及接收者)而言,傳輸的資料/文件看起來完全相同。 ### 工具和庫 適用於Python的PDF工具,模組和庫的可用解決方案範圍有些混亂,需要花一點時間弄清楚什麼是什麼,以及哪些專案需要連續維護。根據我們的研究,以下是最新的候選人: * [PyPDF2](https://pypi.org/project/PyPDF2/):一個Python庫,用於提取文件資訊和內容,逐頁拆分文件,合併文件,裁剪頁面並新增水印。PyPDF2支援未加密和加密的文件。 * [PDFMiner](https://euske.github.io/pdfminer/index.html):完全用Python編寫,適用於Python 2.4。對於Python 3,請使用克隆的包[PDFMiner.six](https://github.com/pdfminer/pdfminer.six)。這兩個軟體包都允許您解析,分析和轉換PDF文件。這包括對PDF 1.7以及CJK語言(中文,日文和韓文)的支援,以及各種字型型別(Type1,TrueType,Type3和CID)。 * [pdflib](https://github.com/alephdata/pdflib) for Python:[Poppler](https://poppler.freedesktop.org/)庫的擴充套件,為它提供了Python繫結。它使您可以解析,分析和轉換PDF文件。不要將其與具有相同名稱的[商業吊墜](https://www.pdflib.com/)相混淆。 * [PyFPDF](https://pyfpdf.readthedocs.io/en/latest/):一個在Python下生成PDF文件的庫。從[FPDF](http://www.fpdf.org/) PHP庫移植而來,這是著名的PDFlib擴充套件替換,其中包含許多示例,指令碼和派生類。 * [PDFTables](https://pdftables.com/):一項商業服務,提供從PDF文件附帶的表格中提取的內容。提供一個API,以便PDFTables可以用作SAAS。 * [PyX](http://pyx.sourceforge.net/index.html) -Python圖形包:PyX是用於建立PostScript,PDF和SVG檔案的Python包。它結合了PostScript繪圖模型的抽象和TeX / LaTeX介面。這些基元可以構建複雜的任務,例如以可釋出的質量建立2D和3D繪圖。 * [ReportLab](https://www.reportlab.com/):一個雄心勃勃的,具有行業實力的圖書館,主要致力於精確建立PDF文件。免費提供開放原始碼版本和名為ReportLab PLUS的商業增強版本。 * [PyMuPDF](https://github.com/pymupdf/PyMuPDF)(又稱“ fitz”):MuPDF的Python繫結,這是一種輕量級的PDF和XPS檢視器。該庫可以訪問PDF,XPS,OpenXPS,epub,漫畫和小說書格式的檔案,並且以其最佳效能和高渲染質量而聞名。 * [pdfrw](https://pypi.org/project/pdfrw/):一個基於Python的純PDF解析器,用於讀寫PDF。它忠實地再現向量格式而無需光柵化。與ReportLab結合使用時,它有助於在使用ReportLab建立的新PDF中重用現有PDF的一部分。 | 圖書館 | 用於 | | --- | --- | | PyPDF2 | 讀 | | PyMuPDF |讀 | | pdflib | 讀 | | PDF表格 | 讀 | | PDFMiner.six | 讀 | | PDF查詢 | 讀 | | pdfrw | 讀,寫/創作 | | PyFPDF | 寫/創作 | 我們將重點介紹PyPDF2和PyMuPDF,並說明如何以最簡單的方式提取文字和影象。為了瞭解PyPDF2的用法,官方文件和許多其他資源提供的示例的組合對您有所幫助。相比之下,官方PyMuPDF文件更加清晰,並且使用該庫的速度也大大加快。 ### 使用PyPDF2提取文字 ``` $ pip3 install PyPDF2 ``` *清單1首先*匯入了`PdfFileReader`該類。接下來,使用該類開啟文件,並使用`getDocumentInfo()`方法提取文件資訊,使用提取頁數`getDocumentInfo()`以及第一頁的內容。 請注意,PyPDF2從0開始計數頁面,這就是該呼叫`pdf.getPage(0)`檢索文件第一頁的原因。最終,提取的資訊被列印到`stdout`。 *清單1:提取文件資訊和內容。* ``` #!/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()) ``` ![](https://upload-images.jianshu.io/upload_images/468490-63ce99f311c17287.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 如上面的*圖1*所示,提取的文字是連續列印的。沒有段落或句子分隔。如PyPDF2文件中所述,所有文字資料都按照在頁面內容流中提供的順序返回,並且依靠它可能會導致一些意外。這主要取決於PDF文件的內部結構,以及PDF編寫器過程如何生成PDF指令流。 ### 使用PyMuPDF提取文字 可從PyPi網站上獲取PyMuPDF,並在終端中使用以下命令安裝軟體包: ``` $ pip3 install PyMuPDF ``` 顯示文件資訊,列印頁數以及提取PDF文件的文字的方式與PyPDF2相似(請參見*清單2*)。要匯入的模組名為`fitz`,並返回到PyMuPDF的先前名稱。 *清單2:使用PyMuPDF從PDF文件中提取內容。* ``` #!/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的優點是可以保持原始文件結構完整-帶有換行符的整個段落都保留在PDF文件中(參見*圖2*)。 ![](https://upload-images.jianshu.io/upload_images/468490-f967f68347b4c124.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### 使用PyMuPDF從PDF提取影象 PyMuPDF使用該方法簡化了從PDF文件提取影象的過程`getPageImageList()`。*清單3*基於PyMuPDF Wiki頁面上的示例,並逐頁地將PDF中的所有影象提取並儲存為PNG檔案。如果影象具有CMYK色彩空間,則將首先將其轉換為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秒的時間內提取了117張影象,這真是了不起。單個影象以PNG格式儲存。為了保持原始影象的格式和大小,而不是轉換為PNG,請檢視[PyMuPDF Wiki中](https://github.com/pymupdf/PyMuPDF/wiki)指令碼的擴充套件版本。 ![圖3:提取的影象](https://upload-images.jianshu.io/upload_images/468490-fd24cb80a3197188.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### 使用PyPDF2將PDF拆分為頁面 對於此示例,首先需要同時匯入`PdfFileReader`和和`PdfFileWriter`類。然後,我們開啟PDF檔案,建立一個閱讀器物件,並使用閱讀器物件的`getNumPages`方法遍歷所有頁面。 在`for`迴圈內部,我們建立的新例項`PdfFileWriter`,該例項尚不包含任何頁面。然後,使用`pdfWriter.addPage()`方法將當前頁面新增到我們的writer物件。此方法接受一個頁面物件,我們使用該`PdfFileReader.getPage()`方法獲取該物件。 下一步是建立一個唯一的檔名,我們使用原始檔名加上單詞“ 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) ``` ![](https://upload-images.jianshu.io/upload_images/468490-ed3f5dea5f07196d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### 查詢所有包含文字的頁面 這個用例非常實用,並且工作方式類似於`pdfgrep`。該指令碼使用PyMuPDF返回包含給定搜尋字串的所有頁碼。頁面一頁接一頁地載入,藉助該`searchFor()`方法,將檢測到搜尋字串的所有出現情況。如果匹配則在上面印有相應的資訊`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”一詞的搜尋結果。 ![](https://upload-images.jianshu.io/upload_images/468490-9610b98d8c4f42f5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) ### 結論 此處顯示的處理PDF方法非常強大。使用相對較少的程式碼行數,很容易獲得