大家好,我是小張~,今天文章與自動化辦公相關,目前個人認為 Python 庫中處理 PDF 比較不錯的有三個,分別是 PyPDF2,Pdfplumer 和 PDFminer;
今天教學內容主要聚焦於 PyPDF2 ,藉助它對 PDF 實現以下基本操作
- 1,將單個 PDF 拆解為多個 PDF 檔案 ;
- 2,將多個 PDF 合併為一個 PDF 檔案 ;
- 3,將 PDF 中某頁進行旋轉 ;
- 4,對 PDF 新增水印 ;
- 5,對 PDF 加密 ;
- 6,對 PDF 進行解密;
- 6,取得 PDF 基本訊息,例如作者、標題、頁數等;
PyPDF2 歷史
正文開始之前,說一下 PyPDF2 的發展歷史 ,PyPDF 的前身是 pyPDf 包在2005年釋出,該包的最後一個版本釋出於2010年,後來大約經過一年左右, 名為 Phasit 的公司贊助 PyPdf 的一個分支後來命名為 PyPDF2,兩個版本功能都基本一樣,最大區別就是 PyPDF2 中 加入了支援 Python3 屬性;
PyPDF2 近期也沒有再更新了,最近一個版本釋出在2016年,但使用熱度依然沒有消退;雖然後面又出現了 PyPDF3、PyPDF4 等不同版本,但這些包並沒有對 PyPDF2 功能向後完全相容,使用者受歡迎程度當然也不如 PyPDF2
PyPDF2 安裝
與其它Python 庫一樣,安裝可透過 pip 或 conda 工具
1 | pip install pypdf2 |
PDF 訊息選取
使用 PyPDF2 可以從 PDF 中選取到一些元資料和文字訊息,對 PDF 有個大致了解
用 PyPDF2 能夠選取的資料如下
- 作者;
- 建立者;
- 製作者;
- Subject;
- 標題;
- 頁數;
這裡我下載了官網提供的 PDF 樣本《Seige_of_Vicksburg_Sample_OCR》一共六頁,作為測試資料
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from PyPDF2 import PdfFileReader # # pdf 檔案 pdf_path = "D:/Data/自動化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf" with open(pdf_path,'rb') as f: pdf = PdfFileReader(f) infomation = pdf.getDocumentInfo() number_of_pages = pdf.getNumPages() txt = f'''{pdf_path} information: Author : {infomation.author}, Creator : {infomation.creator}, Producer : {infomation.producer}, Subject : {infomation.subject}, Title : {infomation.title}, Number of pages : {number_of_pages} ''' print(txt) |
下面為列印結果
1 2 3 4 5 6 7 | D:/Data/自動化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf information: Author : DSI, Creator : LuraDocument PDF Compressor Server 5.5.46.38, Producer : LuraDocument PDF v2.38, Subject : None, Title : Binder1.pdf, Number of pages : 6 |
在上面範例中用到了 PdfFileReader 類,用於與 pdf 檔案互動;呼叫該類中的 getDocumentInfo() 方法回傳一個 DocumentInformation 的例項,該例項中儲存著我們需要的訊息;對 reader 物件呼叫 getNumPages 方法也可以回傳檔案頁數;
個人看法,這裡面的資料也就 頁數 有點價值,當批量統計時該方法很適用
PDF 頁面旋轉
PyPDF2 中 pdf 每一頁都是以 page 物件存在,回傳某一頁的例項可透過 reader 物件中的 get_Page(page_index) 方法,其中 page_index 表示索引
對某一頁旋轉,有兩種方式
- rotateClockwise(90),順時針旋轉90度;
- rotateCounterClockwise(90),逆時針旋轉 90 度;
下面程式碼表示將目標 PDF 中第一頁順時針方向旋轉 90 度,第二頁以逆時針方向旋轉 90 度,其它頁位置角度不變;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | from PyPDF2 import PdfFileReader,PdfFileWriter pdf_writer = PdfFileWriter() pdf_reader = PdfFileReader(pdf_path) # Rotate page 90 degrees to the right page_1 = pdf_reader.getPage(0).rotateClockwise(90) pdf_writer.addPage(page_1) # Rotate page 90 degrees to the left page_2 = pdf_reader.getPage(1).rotateCounterClockwise(90) pdf_writer.addPage(page_2) # 之後的正常寫出 for i in range(2,pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(i)) with open(pdf_path, 'wb') as fh: pdf_writer.write(fh) |
結果如下
程式碼中同時用到了
寫到這裡,說實話其實 頁面旋轉 這個功能沒基本沒什麼作用,加在這裡只是想充當一些字數,哈哈哈
單個 PDF 拆解成多個PDF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | from PyPDF2 import PdfFileReader,PdfFileWriter # # pdf 檔案 pdf_path = "D:/Data/自動化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf" save_path = 'D:/Data/自動化辦公/PDF/' # Split Pages of PDF pdf_reader = PdfFileReader(pdf_path) for i in range(0,pdf_reader.getNumPages()): pdf_writer = PdfFileWriter() pdf_writer.addPage(pdf_reader.getPage(i)) # Every page write to a path with open(save_path+'{}.pdf'.format(str(i)), 'wb') as fh: pdf_writer.write(fh) print('{} Save Sucessfully ! '.format(str(i))) |
程式碼將 PDF 原檔案中的每一頁拆解到每一個PDF檔案,其中檔名用頁索引來命名;
透過拆解也可以選取到 pdf 檔案中固定頁碼範圍,例如我只想選取 pdf 中的 2-5 頁,其它部分不要,那麼程式碼將寫成下面形式
1 2 3 4 5 6 7 8 | pdf_writer = PdfFileWriter() pdf_reader = PdfFileReader(pdf_path) for i in range(1,5): # pdf_writer = PdfFileWriter() pdf_writer.addPage(pdf_reader.getPage(i)) # Every page write to a path with open(save_path+'2_5.pdf', 'wb') as fh: pdf_writer.write(fh) |
多個 PDF 檔案合併為單個
pdf 拆解與合併方向雖然相反,但用到的類、原理都是一樣的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | from PyPDF2 import PdfFileReader,PdfFileWriter p1_pdf = "D:/Data/自動化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf" p2_pdf = "D:/Data/自動化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf" merge_pdf = 'D:/Data/自動化辦公/PDF/merge.pdf' p1_reader = PdfFileReader(p1_pdf) p2_reader = PdfFileReader(p2_pdf) merge = PdfFileWriter() # Write p1 for i in range(0,p1_reader.getNumPages()): merge.addPage(p1_reader.getPage(i)) # Write p2 for j in range(0,p2_reader.getNumPages()): merge.addPage(p2_reader.getPage(j)) # Write out with open(merge_pdf,'wb') as f: merge.write(f) |
執行結果如下
PDF 新增水印
在今天列舉的這麼多功能中,我想這個功能是最有用,批量新增水印主要用到 page 物件中的 margePage() 方法,透過將兩個頁面合併來達到新增水印的效果
因為 PyPDF2 只能操作 pdf 物件,因此在新增水印之前,需要將準備新增的水印存放到一個 pdf 檔案中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from PyPDF2 import PdfFileReader,PdfFileWriter watermark = 'D:/Data/自動化辦公/PDF/watermark.pdf' input_pdf = 'D:/Data/自動化辦公/PDF/merge.pdf' output = 'D:/Data/自動化辦公/PDF/merge_watermark.pdf' watermark_obj = PdfFileReader(watermark) watermark_page = watermark_obj.getPage(0) pdf_reader = PdfFileReader(input_pdf) pdf_writer = PdfFileWriter() # Watermark all the pages for page in range(pdf_reader.getNumPages()): page = pdf_reader.getPage(page) page.mergePage(watermark_page) pdf_writer.addPage(page) with open(output, 'wb') as out: pdf_writer.write(out) |
效果如下,從左到右,依次為原圖、水印、新增水印後的原圖 [外鏈圖像轉存失敗,源站可能有防盜鏈機制,建議將圖像儲存下來直接上傳(img-XP0ELXsk-1615825692823)(https://images.zeroingpython.top/img/image-20210314005417135.png)]
上面效果不好是因為製作水印時沒有考慮到頁面佈局問題,所以合併時出現一部分缺失;
用以上程式碼新增水印的好處是,可以對 pdf 指定頁田間水印,例如說只對奇數頁新增偶數頁不管,不但彈性強而且高效,當然也可以對多個檔案進行批量操作
PDF加密解密
pdf加密
對一份 pdf 檔案,如果我們不想讓其他人能夠讀取裡面的內容,可以透過 pypdf2 對它設定密碼,如果只是單個檔案的話,建議最好自己找個工具受手動操作一下會高效一點,但若是多個檔案,非常建議用下面方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | watermark = 'D:/Data/自動化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf' input_pdf = 'D:/Data/自動化辦公/PDF/merge.pdf' output = 'D:/Data/自動化辦公/PDF/merge_watermark1.pdf' watermark_obj = PdfFileReader(watermark) watermark_page = watermark_obj.getPage(0) pdf_reader = PdfFileReader(input_pdf) pdf_writer = PdfFileWriter() # Watermark all the pages for page in range(pdf_reader.getNumPages()): page = pdf_reader.getPage(page) page.mergePage(watermark_page) pdf_writer.addPage(page) pdf_writer.encrypt(user_pwd='123456', use_128bit=True) with open(output, 'wb') as out: pdf_writer.write(out) |
主要用到 encrypt 函式,需要注意三個引數
-
user_pwd,str,使用者密碼,用來限制開啟讀取檔案;
-
owner_pwd,str,比使用者密碼更高一級,提供時可讓開啟檔案不受任何限制,不指定時預設owner_pwd 與 user_pwd 相同;
-
use_128bit 布林值,用來表示是否使用128位作為密碼,False 時代表用 40 位密碼,預設為True;
pdf解密
解密是在讀取檔案時用的,用到 decrypt() 函式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | rom PyPDF2 import PdfFileWriter, PdfFileReader input_pdf='reportlab-encrypted.pdf' output_pdf='reportlab.pdf' password='twofish' pdf_writer = PdfFileWriter() pdf_reader = PdfFileReader(input_pdf) pdf_reader = pdf_reader.decrypt(password) for page in range(pdf_reader.getNumPages()): pdf_writer.addPage(pdf_reader.getPage(page)) with open(output_pdf, 'wb') as fh: pdf_writer.write(fh) |
上面範例中解密原理是 透過將一個加密檔案進行讀取,並寫入到一個非加密 pdf 中
小結
本文介紹了 PyPDF2 庫的基本用法,藉助它加上程式碼例項實現了一些基本操作;但在這裡提醒一下,所有上面這些操作只適用於批量操作場景,如果物件是單個檔案的話建議用常規做法,過於炫技的話只會浪費時間
關於 pdf 內的圖文內容選取、寫入本文並沒有涉獵,源於 pypdf2 對於這方面並不擅長,而 Pdfplumber 和 PDFminer 在文字選取方面要好得多,工欲善其事,必先利其器;在之後的教學中我將會介紹一下這方面的內容,期待大家的關注!
好了以上就是本篇內容的全部內容,最後感謝大家的閱讀,我們下期見~