PDF(Portable Document Format)是一種便攜文檔格式,它基于PostScripty這種腳本語言。
??
PDF文檔操作
PDF(Portable Document Format)是一種便攜文檔格式,它基于PostScripty這種腳本語言,它是第一個獨立于設備的頁面描述語言。pdf格式是與平臺無關,獨立于底層操作系統和渲染引擎。由于PDF文檔遵循標準格式,相關生態建設完善,應用廣泛,非常值得花費時間討論使用python進行操作。
?
python中能夠操作pdf格式文檔的庫有:
?
◆PyMuPDF
◆pikepdf
◆pdfplumber
◆ReportLab
◆borb
主攻方向稍有不同,大致分類是:
?
◆pikepdf專注對已經存在的PDF的操作,例如分割、合并、旋轉等
◆pdfplumber專注PDF內容提取,例如文本(位置、字體及顏色等)和形狀(矩形、直線、曲線),此外還能夠解析表格
◆ReportLab專注PDF頁面內容(文本、圖、表等)的創建
◆PyMuPDF和borb同時支持讀、寫及PDF頁面操作,功能最為全面
◆borb是較新的庫,功能也較為完善,但經過筆者試用,對于中文的支持不好
PyMuPDF的基本功能全面,非常適應用于批處理PDF。使用python來操作PDF/WORD/EXCEL/PPT等類文檔,應該有如下的期望:
◆進行創作是非常不稱手的。為何不用Office提供的工具軟件進行編輯創作呢。因此,不能夠指望這類庫以及python提供非常全面完善的能力
◆能夠在原來文檔的基礎上,進行批量化的一些操作。例如,可以基于某個模板,批量得制作邀請函,只要簡單得修改姓名即可。或者根據數據庫中的內容,在模板的基礎上,定期形成周報、月報類固定格式的文檔
◆能夠在原來文檔的基礎上,增加、刪除以及調整圖片、文字與頁面布局
所以,下述代碼均從已經存在的內容入手進行演示:
?
01.
圖片處理
timport os
import fitzprint(fitz.__doc__)def export2png(filename,pageno):"""將pdf文件指定頁(從0開始算)導出為PNG圖片文件Args:filename (string): PDF文件名pageno (int): 頁號(從0開始)"""with fitz.open(filename) as doc:page = doc[pageno]pix = page.get_pixmap() pix.save("page-%i.png" % pageno)def export2svg(filename,pageno):"""將pdf文件指定頁(從0開始算)導出為SVG矢量圖Args:filename (string): PDF文件名pageno (int): 頁號(從0開始)"""with fitz.open(filename) as doc:page = doc[pageno]svg = page.get_svg_image(matrix=fitz.Identity)output = open("page-%i.svg" % pageno,'w')output.write(svg)output.close()def figs2pdf(filename,startdir):"""將指定目錄下的所有圖片文件合并成為PDF文件Args:filename (string): 未來要生成的PDF文件名稱startdir (string): 圖片所在目錄"""doc = fitz.open()# 列出目錄下所有文件imglist = os.listdir(startdir) imglist.sort() for _, f in enumerate(imglist):# 遍歷并且打開每個圖片文件img = fitz.open(os.path.join(startdir, f))# 計算圖片大小rect = img[0].rectpdfbytes = img.convert_to_pdf()img.close()# 將圖片文件貼合到PDF頁上imgPDF = fitz.open("pdf", pdfbytes) page = doc.new_page(width = rect.width,height = rect.height) page.show_pdf_page(rect, imgPDF, 0)# 保存到目標PDF中doc.save(filename) def convert(inputfile,outputfile):"""對圖片格式進行轉換Args:inputfile (string): 源圖片outputfile (string): 目標圖片"""pix = fitz.Pixmap(inputfile)pix.save(outputfile) pdfname = r'd:\test\sed.pdf'figs2pdf(r'd:\test\demo.pdf',r'D:\test\all\figures')export2png(pdfname,10)
export2svg(pdfname,10)convert(r"D:\test\all\serial1\000000.gif",r'd:\test\0.psd')
convert(r"D:\test\all\serial1\000000.jpg",r'd:\est\1.png')
上述代碼演示了合并圖片與分解PDF到圖片,轉換圖片格式等功能。
?其中figs2pdf函數完成了從指定目錄的多個圖片合成一個PDF文件的常用功能。相對復雜一些。
?pymupdf也提供了逆向生成圖片的方法。
?export2png將指定PDF文件的指定頁轉換成為PNG文件,效果比截圖好
?export2svg將指定PDF文件的指定頁轉換成為svg文件,而SVG文件是矢量圖、能夠編輯,這個功能更是強大
?convert函數能夠將多種圖片格式進行轉換。代碼演示了轉換成為psd與png格式。當然這些功能是pymupdf贈送的功能,不能夠與pillow等專業庫相比
下面的代碼演示如何從pdf中提取文字,以及獲得PDF文檔中的各類鏈接。
import fitzdef showmeta(filename):"""顯示PDF的基本信息Args:filename (string): 要打開的PDF文件名稱"""print(fitz.__doc__)doc = fitz.open(filename)print(doc.page_count)print(doc.metadata)def showlinks(filename):"""顯示PDF中的所有超鏈Args:filename (string): 要打開的PDF文件名稱"""with fitz.open(filename) as doc:for page in doc:for link in page.links():# 顯示一個列表if link["kind"] == fitz.LINK_GOTO:print("Jump to page", link["page"] + 1)elif link["kind"] in (fitz.LINK_GOTOR, fitz.LINK_LAUNCH):print("Open or launch file", link["file"])elif link["kind"] == fitz.LINK_URI:print("Open URI", link["uri"])def showtext(filename, pageno, option='text'):"""顯示pdf中的文字Args:filename (string): 要打開的PDF文件名稱pageno (int): 頁號option (選項): 可能是'text','block'等Returns:list: 所有的文字列表"""with fitz.open(filename) as doc:page = doc[pageno]return page.get_text(option)def searchtext(filename, pageno, searchstr):"""在pdf中搜尋文字Args:filename (string): 要打開的PDF文件名稱pageno (int): 頁號searchstr (string): 要搜索的內容Returns:list: 匹配文字所在的區域列表。"""with fitz.open(filename) as doc:page = doc[pageno]areas = page.search_for(searchstr)return areaspdfname = r'd:\test\阿里技術地圖.pdf'print(showtext(pdfname, 9))
areas = searchtext(pdfname, 1, '數據挖掘')
for rect in areas:print(rect)
showlinks(pdfname)
以上代碼中:
?showtext需要傳遞相關的選項。pymupdf可以提取多種類型的文字。具體可以參考
?searchtext函數的返回與通常的預期不同,返回的是多個區域所形成的列表。主要用途是為了相關的工具軟件顯示用,例如可以高亮等。如果用這個函數只是期待返回具體的文字內容的話,不妨直接獲得文字,然后再使用字符串的搜索功能。
?showlinks函數直接獲得了所有頁上所有的鏈接。大部分鏈接是內部的跳轉,也有使用編輯軟件加入的外部超鏈。文字內的包含的URL使用pymupdf是找不到的,必須自己寫函數對字符串進行語議分析才能夠獲得,這個也是pymupdf不完善的地方。
除了上述對PDF本身的操作外,還有從PDF到DOCX文檔的雙向轉換需要。由DOCX文檔轉PDF文檔非常容易,直接在WORD中選擇打印或者導出即可,沒有什么可以討論的。但是反過來稍微困難些,可以考慮以下方法:
?直接用WORD打開PDF,然后另存為DOCX文檔。
?使用pdf2docx轉化
?使用python-office轉化
pdf2docx是一個輕量級的第三方庫,對中文的支持不錯,本身是基于pymupdf庫發展起來的,它的安裝過程如下。
pip install pdf2docx
# upgrade
pip install --upgrade pdf2docx
《阿里的技術地圖》這個PDF可以從網上下載到,內容比較豐富,值得一看。如果想要轉換成為WORD文檔,示例代碼如下。
from pdf2docx import Converterinputfilename = r'd:\test\阿里技術地圖.pdf'
outputfilename = r'd:\test\demo.docx'cv = Converter(inputfilename)
# 將PDF全部內容轉換成為DOCX
cv.convert(outputfilename)
cv.close()cv = Converter(inputfilename)
# 將PDF部分頁轉換為DOCX
cv.convert(outputfilename,start=3,end=5)
cv.close()cv = Converter(inputfilename)
# 將PDF個別頁轉換為DOCX
cv.convert(outputfilename,pages=[10,16,8])
cv.close()
這個庫轉換速度不是太快,還提供了多進程的功能,但實際使用時會有BUG出現,不建議使用。
?
?
END