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

PDF文件格式

如今,可移植文檔格式(PDF)屬于最常用的數(shù)據(jù)格式。在1990年,PDF文檔的結(jié)構(gòu)由Adobe定義。PDF格式的思想是,對(duì)于通信過程中涉及的雙方(創(chuàng)建者,作者或發(fā)送者以及接收者)而言,傳輸?shù)臄?shù)據(jù)/文檔看起來完全相同。

工具和庫

適用于Python的PDF工具,模塊和庫的可用解決方案范圍有些混亂,需要花一點(diǎn)時(shí)間弄清楚什么是什么,以及哪些項(xiàng)目需要連續(xù)維護(hù)。根據(jù)我們的研究,以下是最新的候選人:

  • PyPDF2:一個(gè)Python庫,用于提取文檔信息和內(nèi)容,逐頁拆分文檔,合并文檔,裁剪頁面并添加水印。PyPDF2支持未加密和加密的文檔。

  • PDFMiner:完全用Python編寫,適用于Python 2.4。對(duì)于Python 3,請(qǐng)使用克隆的包PDFMiner.six。這兩個(gè)軟件包都允許您解析,分析和轉(zhuǎn)換PDF文檔。這包括對(duì)PDF 1.7以及CJK語言(中文,日文和韓文)的支持,以及各種字體類型(Type1,TrueType,Type3和CID)。

  • pdflib for Python:Poppler庫的擴(kuò)展,為它提供了Python綁定。它使您可以解析,分析和轉(zhuǎn)換PDF文檔。不要將其與具有相同名稱的商業(yè)吊墜相混淆。

  • PyFPDF:一個(gè)在Python下生成PDF文檔的庫。從FPDF PHP庫移植而來,這是著名的PDFlib擴(kuò)展替換,其中包含許多示例,腳本和派生類。

  • PDFTables:一項(xiàng)商業(yè)服務(wù),提供從PDF文檔附帶的表格中提取的內(nèi)容。提供一個(gè)API,以便PDFTables可以用作SAAS。

  • PyX -Python圖形包:PyX是用于創(chuàng)建PostScript,PDF和SVG文件的Python包。它結(jié)合了PostScript繪圖模型的抽象和TeX / LaTeX接口。這些基元可以構(gòu)建復(fù)雜的任務(wù),例如以可發(fā)布的質(zhì)量創(chuàng)建2D和3D繪圖。

  • ReportLab:一個(gè)雄心勃勃的,具有行業(yè)實(shí)力的圖書館,主要致力于精確創(chuàng)建PDF文檔。免費(fèi)提供開放源代碼版本和名為ReportLab PLUS的商業(yè)增強(qiáng)版本。

  • PyMuPDF(又稱“ fitz”):MuPDF的Python綁定,這是一種輕量級(jí)的PDF和XPS查看器。該庫可以訪問PDF,XPS,OpenXPS,epub,漫畫和小說書格式的文件,并且以其最佳性能和高渲染質(zhì)量而聞名。

  • pdfrw:一個(gè)基于Python的純PDF解析器,用于讀寫PDF。它忠實(shí)地再現(xiàn)矢量格式而無需光柵化。與ReportLab結(jié)合使用時(shí),它有助于在使用ReportLab創(chuàng)建的新PDF中重用現(xiàn)有PDF的一部分。

圖書館 用于
PyPDF2
PyMuPDF
pdflib
PDF表格
PDFMiner.six
PDF查詢
pdfrw 讀,寫/創(chuàng)作
PyFPDF 寫/創(chuàng)作

我們將重點(diǎn)介紹PyPDF2和PyMuPDF,并說明如何以最簡(jiǎn)單的方式提取文本和圖像。為了了解PyPDF2的用法,官方文檔和許多其他資源提供的示例的組合對(duì)您有所幫助。相比之下,官方PyMuPDF文檔更加清晰,并且使用該庫的速度也大大加快。

使用PyPDF2提取文本

$ pip3 install PyPDF2

清單1首先導(dǎo)入了PdfFileReader該類。接下來,使用該類打開文檔,并使用getDocumentInfo()方法提取文檔信息,使用提取頁數(shù)getDocumentInfo()以及第一頁的內(nèi)容。

請(qǐng)注意,PyPDF2從0開始計(jì)數(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)容流中提供的順序返回,并且依靠它可能會(huì)導(dǎo)致一些意外。這主要取決于PDF文檔的內(nèi)部結(jié)構(gòu),以及PDF編寫器過程如何生成PDF指令流。

使用PyMuPDF提取文本

可從PyPi網(wǎng)站上獲取PyMuPDF,并在終端中使用以下命令安裝軟件包:

$ pip3 install PyMuPDF

顯示文檔信息,打印頁數(shù)以及提取PDF文檔的文本的方式與PyPDF2相似(請(qǐng)參見清單2)。要導(dǎo)入的模塊名為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)點(diǎn)是可以保持原始文檔結(jié)構(gòu)完整-帶有換行符的整個(gè)段落都保留在PDF文檔中(參見圖2)。

使用PyMuPDF從PDF提取圖像

PyMuPDF使用該方法簡(jiǎn)化了從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頁P(yáng)DF上運(yùn)行此Python腳本,它在不到3秒的時(shí)間內(nèi)提取了117張圖像,這真是了不起。單個(gè)圖像以PNG格式存儲(chǔ)。為了保持原始圖像的格式和大小,而不是轉(zhuǎn)換為PNG,請(qǐng)查看PyMuPDF Wiki中腳本的擴(kuò)展版本。

圖3:提取的圖像

使用PyPDF2將PDF拆分為頁面

對(duì)于此示例,首先需要同時(shí)導(dǎo)入PdfFileReader和和PdfFileWriter類。然后,我們打開PDF文件,創(chuàng)建一個(gè)閱讀器對(duì)象,并使用閱讀器對(duì)象的getNumPages方法遍歷所有頁面。

for循環(huán)內(nèi)部,我們創(chuàng)建的新實(shí)例PdfFileWriter,該實(shí)例尚不包含任何頁面。然后,使用pdfWriter.addPage()方法將當(dāng)前頁面添加到我們的writer對(duì)象。此方法接受一個(gè)頁面對(duì)象,我們使用該PdfFileReader.getPage()方法獲取該對(duì)象。

下一步是創(chuàng)建一個(gè)唯一的文件名,我們使用原始文件名加上單詞“ page”以及頁碼來完成。我們?cè)诋?dāng)前頁碼上加1,因?yàn)镻yPDF2會(huì)計(jì)算從零開始的頁碼。

最后,我們以“寫二進(jìn)制”模式(mode wb)打開新文件名,并使用該類的write()方法pdfWriter將提取的頁面保存到磁盤。

清單4:將PDF拆分為單個(gè)頁面。

#!/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)

查找所有包含文本的頁面

這個(gè)用例非常實(shí)用,并且工作方式類似于pdfgrep。該腳本使用PyMuPDF返回包含給定搜索字符串的所有頁碼。頁面一頁接一頁地加載,借助該searchFor()方法,將檢測(cè)到搜索字符串的所有出現(xiàn)情況。如果匹配則在上面印有相應(yīng)的信息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方法非常強(qiáng)大。使用相對(duì)較少的代碼行數(shù),很容易獲得結(jié)果。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容