用Python處理PDF

  • 2019 年 10 月 8 日
  • 筆記

本文1146字,預計閱讀需8分鐘;

PDF作為可移植文檔格式(Portable Document Format),在日常生活中經常接觸到,最近處理一些數據更是頻繁接觸一些需要批量處理pdf文件的需求,因此便想整理一下自己實踐的用Python處理PDF格式數據的筆記。本文會保持更新。PDF處理的高頻需求有:讀取、寫入、格式轉換(pdf提取文本寫入txt、根據url寫入pdf等) 、批處理(多個pdf合併為1個、切分pdf)等等。查了下相關資料,Python操作PDF的庫有(只是應用的話肯定不至於造輪子從二進位數據開始讀):pdfminer、pdfminer3k、PyPDF、PyPDF2、pdf2htmlex、pdf2image、pdf2xlsx等。

可用的pdf庫

用pdf2合併和切分PDF

比較幾個庫之後打算先從PyPDF2快速實現一些功能。其官方文檔為PyPDF2 Documentation[1],根據文檔,PDF2庫包含了 PdfFileReader PdfFileMerger PageObject PdfFileWriter 四個常用的主要的調用類,意思也很明確。先用pip install PyPDF2安裝庫。

批量合併pdf

import osfrom PyPDF2 import PdfFileReader, PdfFileWriter #導入需要的類(庫)wp='D:/doc_of_pdf/' #work_path  #合併同一個文件夾下的pdf文件flst=[] #獲得pdf文件路徑for root, dirs, files in os.walk(wp):    flst=filesflst=[wp+f for f in flst]out_pdf=PdfFileWriter()for pf in flst:    in_pdf=PdfFileReader(open(pf, 'rb')) #二進位打開    page_count=in_pdf.getNumPages() #輸入pdf的頁數    for pc in range(page_count):         out_pdf.addPage(in_pdf.getPage(pc)) #逐頁循環with open(wp+'合併筆記_1-3章.pdf','wb') as wf:    out_pdf.write(wf)#out_pdf.getNumPages()

執行前後對比

切分pdf為多個pdf

#將一個pdf文件根據一定規則切分為多個  sc_pdf=PdfFileReader(open(flst[0], 'rb')) #對第一章筆記進行處理count_sc=sc_pdf.getNumPages()#每7頁切分為1個PDF文件out_pdf=PdfFileWriter() #用以輸出pdffor c in range(count_sc):    if c%7==0 and c>0:        with open(wp+'切分_{0}.pdf'.format(c),'wb') as wf:            out_pdf.write(wf)        out_pdf=PdfFileWriter() #重建一個空對象    else:        out_pdf.addPage(sc_pdf.getPage(c))

切分測試結果截圖

通過上面的實踐,可以看到實現這幾個需求高頻使用到的方法就是新建一個Reader或Writer對象,通過.getNumPages()獲取一共的頁碼,通過.getPage(page)獲取特定頁,.addPage()寫入頁碼。

圖片轉PDF

需要用到額外的PIL庫:處理圖片的神器。

#單張圖片轉pdffrom PIL import Imagefrom PyPDF2 import PdfFileReader, PdfFileWriterimg = Image.open('D:/docOfStu/pypdf2-mindmap-01.JPG')img.save('D:/docOfStu/pypdf2-mindmap-01.pdf', 'PDF') #通過PIL庫保存為pdf格式  #多張圖片轉pdfilst=['D:/docOfStu/pypdf2-mindmap-01.jpg','D:/docOfStu/pypdf2-mindmap-02.jpg'] #圖片列表 # for root, dirs, files in os.walk(wpt): ilst=files  #也可以通過os.walk(wpt) 讀取文件夾wpt下所有圖片out_pdf=PdfFileWriter()for f in ilst:    img = Image.open(f)    fw=f.replace('.jpg','.pdf')    img.save(fw)    out_pdf.appendPagesFromReader(PdfFileReader(open(fw,'rb'))) #也可拆這句為 sc_pdf=PdfFileReader(open(fw,'rb')); out_pdf.addPage(sc_pdf.getPage(0))out_pdf.write(open('D:/docOfStu/pypdf2-mindmap-04.pdf','wb'))

圖片轉pdf對比效果

頁面處理

過濾pdf中的的特定頁面,只保留特定頁面;另一方面,給pdf文件添加特定頁面;

#過濾pdf的特定頁面,只保留特定頁面;  from PyPDF2 import PdfFileReader, PdfFileWriter  with open('zz-pdf.pdf', 'rb') as rf: #需去除特定頁面的pdf    in_pdf=PdfFileReader(rf)      out_pdf=PdfFileWriter()    add_pages=[1] #從0開始計數     for i in range(in_pdf.getNumPages()):        if i in add_pages:            with open('pdf-marker.pdf','rb') as mf:                out_pdf.addPage(PdfFileReader(mf).getPage(0)) #取特定的一頁        out_pdf.addPage(in_pdf.getPage(i))    out_pdf.write(open('zz-pdf-marker.pdf','wb'))    #將特定頁面添加到pdf文件里  m_pdf=PdfFileMerger() m_pdf.merge(0,'zz-pdf.pdf',pages=(0,2)) #提前確定初始化的時候有多少頁m_pdf.merge(1,'ipynb2pdf.pdf',pages=(0,1)) #可以省略用open打開的操作m_pdf.write(open('zz-pdf-marker-7.pdf','wb'))  with open('zz-pdf.pdf', 'rb') as rf: #另一種寫法    #in_pdf=PdfFileReader(rf)    m_pdf=PdfFileMerger()     m_pdf.merge(0,rf,pages=(0,2))    with open('ipynb2pdf.pdf','rb') as f:        m_pdf.merge(1,f,pages=(0,1))        m_pdf.write(open('zz-pdf-marker-6.pdf','wb'))

程式碼同步更新於:https://github.com/QLWeilcf/ Stack_lcf/blob/master/pdfProccWithpy.ipynb

References

[1] PyPDF2 Documentation: https://pythonhosted.org/PyPDF2/ [2] QLWeilcf_pdfProccWithpy.ipynb: https://github.com/QLWeilcf/Stack_lcf/blob/master/pdfProccWithpy.ipynb [3] PyPDF2 Documentation: https://pythonhosted.org/PyPDF2/ [4] pdfminer: https://pypi.org/project/pdfminer/