大家好,我是小張~娃承,今天文章與自動(dòng)化辦公相關(guān)奏夫,目前個(gè)人認(rèn)為 Python 庫(kù)中處理 PDF 比較不錯(cuò)的有三個(gè),分別是 PyPDF2历筝,Pdfplumer 和 PDFminer酗昼;
今天教程內(nèi)容主要聚焦于 PyPDF2 ,借助它對(duì) PDF 實(shí)現(xiàn)以下基本操作
1梳猪,將單個(gè) PDF 拆分為多個(gè) PDF 文件 麻削;
2,將多個(gè) PDF 合并為一個(gè) PDF 文件 春弥;
3碟婆,將 PDF 中某頁(yè)進(jìn)行旋轉(zhuǎn) ;
4惕稻,對(duì) PDF 添加水印 ;
5竖共,對(duì) PDF 加密 ;
6俺祠,對(duì) PDF 進(jìn)行解密公给;
6,獲取 PDF 基本信息蜘渣,例如作者淌铐、標(biāo)題、頁(yè)數(shù)等蔫缸;
PyPDF2 歷史
正文開(kāi)始之前腿准,說(shuō)一下 PyPDF2 的發(fā)展歷史 ,PyPDF 的前身是 pyPDf 包在2005年發(fā)布,該包的最后一個(gè)版本發(fā)布于2010年吐葱,后來(lái)大約經(jīng)過(guò)一年左右街望, 名為 Phasit 的公司贊助 PyPdf 的一個(gè)分支后來(lái)命名為 PyPDF2,兩個(gè)版本功能都基本一樣弟跑,最大區(qū)別就是 PyPDF2 中 加入了支持 Python3 特性灾前;
PyPDF2 近期也沒(méi)有再更新了,最近一個(gè)版本發(fā)布在2016年孟辑,但使用熱度依然沒(méi)有消退哎甲;雖然后面又出現(xiàn)了 PyPDF3、PyPDF4 等不同版本饲嗽,但這些包并沒(méi)有對(duì) PyPDF2 功能向后完全兼容炭玫,用戶受歡迎程度當(dāng)然也不如 PyPDF2
PyPDF2 安裝
與其它Python 庫(kù)一樣,安裝可通過(guò) pip 或 conda 工具
pip install pypdf2
PDF 信息提取
使用 PyPDF2 可以從 PDF 中提取到一些元數(shù)據(jù)和文本信息貌虾,對(duì) PDF 有個(gè)大致了解
用 PyPDF2 能夠提取的數(shù)據(jù)如下
作者吞加;
創(chuàng)建者;
制作者酝惧;
Subject昭伸;
標(biāo)題物舒;
頁(yè)數(shù);
這里我下載了官網(wǎng)提供的 PDF 樣本《Seige_of_Vicksburg_Sample_OCR》一共六頁(yè)杨何,作為測(cè)試數(shù)據(jù)
from PyPDF2 import PdfFileReader
# # pdf 文檔
pdf_path = "D:/Data/自動(dòng)化辦公/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)
下面為打印結(jié)果
D:/Data/自動(dòng)化辦公/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 文件交互哩陕;調(diào)用該類中的 getDocumentInfo() 方法返回一個(gè) DocumentInformation 的實(shí)例,該實(shí)例中存儲(chǔ)著我們需要的信息赫舒;對(duì) reader 對(duì)象調(diào)用 getNumPages 方法也可以返回文檔頁(yè)數(shù)悍及;
個(gè)人看法,這里面的數(shù)據(jù)也就 頁(yè)數(shù) 有點(diǎn)價(jià)值接癌,當(dāng)批量統(tǒng)計(jì)時(shí)該方法很適用
PDF 頁(yè)面旋轉(zhuǎn)
PyPDF2 中 pdf 每一頁(yè)都是以 page 對(duì)象存在心赶,返回某一頁(yè)的實(shí)例可通過(guò) reader 對(duì)象中的 get_Page(page_index) 方法,其中 page_index 表示索引
對(duì)某一頁(yè)旋轉(zhuǎn)缺猛,有兩種方式
rotateClockwise(90)缨叫,順時(shí)針旋轉(zhuǎn)90度;
rotateCounterClockwise(90)荔燎,逆時(shí)針旋轉(zhuǎn) 90 度耻姥;
下面代碼表示將目標(biāo) PDF 中第一頁(yè)順時(shí)針?lè)较蛐D(zhuǎn) 90 度,第二頁(yè)以逆時(shí)針?lè)较蛐D(zhuǎn) 90 度有咨,其它頁(yè)位置角度不變琐簇;
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)
# 之后的正常寫(xiě)出
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)
結(jié)果如下
代碼中同時(shí)用到了PdfFileReader,PdfFileWriter
這兩個(gè)類,頁(yè)面旋轉(zhuǎn)并不是在原有 PDF 基礎(chǔ)上進(jìn)行操作而是在內(nèi)存處創(chuàng)建了一個(gè)新的PDF流對(duì)象座享,將操作后的每一頁(yè)通過(guò) addPage() 方法加入到這個(gè)對(duì)象中婉商,之后將內(nèi)存中的這個(gè)對(duì)象寫(xiě)入到文件中似忧;
寫(xiě)到這里,說(shuō)實(shí)話其實(shí) 頁(yè)面旋轉(zhuǎn) 這個(gè)功能沒(méi)基本沒(méi)什么作用据某,加在這里只是想充當(dāng)一些字?jǐn)?shù)橡娄,哈哈哈
單個(gè) PDF 拆分成多個(gè)PDF
from PyPDF2 import PdfFileReader,PdfFileWriter
# # pdf 文檔
pdf_path = "D:/Data/自動(dòng)化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf"
save_path = 'D:/Data/自動(dòng)化辦公/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 !\n'.format(str(i)))
代碼將 PDF 原文件中的每一頁(yè)拆分到每一個(gè)PDF文件,其中文件名用頁(yè)索引來(lái)命名癣籽;
通過(guò)拆分也可以提取到 pdf 文件中固定頁(yè)碼范圍挽唉,例如我只想提取 pdf 中的 2-5 頁(yè),其它部分不要筷狼,那么代碼將寫(xiě)成下面形式
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)
多個(gè) PDF 文件合并為單個(gè)
pdf 拆分與合并方向雖然相反瓶籽,但用到的類、原理都是一樣的
PdfFileReader
讀取每個(gè)pdf埂材,并遞歸獲取每一頁(yè)page 對(duì)象塑顺, PdfFileWrite
新建一個(gè)流對(duì)象,把前面內(nèi)存中讀取到的 page 對(duì)象按順序?qū)懭氲竭@個(gè)流對(duì)象中俏险,最后寫(xiě)入到磁盤(pán)文件
···
from PyPDF2 import PdfFileReader,PdfFileWriter
p1_pdf = "D:/Data/自動(dòng)化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf"
p2_pdf = "D:/Data/自動(dòng)化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf"
merge_pdf = 'D:/Data/自動(dòng)化辦公/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)
···
運(yùn)行結(jié)果如下
PDF 添加水印
在今天列舉的這么多功能中严拒,我想這個(gè)功能是最有用,批量添加水印主要用到 page 對(duì)象中的 margePage() 方法竖独,通過(guò)將兩個(gè)頁(yè)面合并來(lái)達(dá)到添加水印的效果
因?yàn)?PyPDF2 只能操作 pdf 對(duì)象裤唠,因此在添加水印之前,需要將準(zhǔn)備添加的水印存放到一個(gè) pdf 文件中
···
from PyPDF2 import PdfFileReader,PdfFileWriter
watermark = 'D:/Data/自動(dòng)化辦公/PDF/watermark.pdf'
input_pdf = 'D:/Data/自動(dòng)化辦公/PDF/merge.pdf'
output = 'D:/Data/自動(dòng)化辦公/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)
···
上面效果不好是因?yàn)橹谱魉r(shí)沒(méi)有考慮到頁(yè)面布局問(wèn)題刊侯,所以合并時(shí)出現(xiàn)一部分缺失;
用以上代碼添加水印的好處是锉走,可以對(duì) pdf 指定頁(yè)田間水印滨彻,比如說(shuō)只對(duì)奇數(shù)頁(yè)添加偶數(shù)頁(yè)不管,不但靈活性強(qiáng)而且高效挠日,當(dāng)然也可以對(duì)多個(gè)文件進(jìn)行批量操作
PDF加密解密
pdf加密
對(duì)一份 pdf 文件疮绷,如果我們不想讓其他人能夠讀取里面的內(nèi)容,可以通過(guò) pypdf2 對(duì)它設(shè)置密碼嚣潜,如果只是單個(gè)文件的話冬骚,建議最好自己找個(gè)工具受手動(dòng)操作一下會(huì)高效一點(diǎn),但若是多個(gè)文件,非常建議用下面方法
···
watermark = 'D:/Data/自動(dòng)化辦公/PDF/Seige_of_Vicksburg_Sample_OCR.pdf'
input_pdf = 'D:/Data/自動(dòng)化辦公/PDF/merge.pdf'
output = 'D:/Data/自動(dòng)化辦公/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 函數(shù)只冻,需要注意三個(gè)參數(shù)
user_pwd庇麦,str,用戶密碼喜德,用來(lái)限制打開(kāi)讀取文件山橄;
owner_pwd,str舍悯,比用戶密碼更高一級(jí)航棱,提供時(shí)可讓打開(kāi)文件不受任何限制,不指定時(shí)默認(rèn)owner_pwd 與 user_pwd 相同萌衬;
use_128bit 布爾值饮醇,用來(lái)表示是否使用128位作為密碼,F(xiàn)alse 時(shí)代表用 40 位密碼秕豫,默認(rèn)為T(mén)rue朴艰;
pdf解密
解密是在讀取文件時(shí)用的,用到 decrypt() 函數(shù)
from 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)
上面例子中解密原理是 通過(guò)將一個(gè)加密文件進(jìn)行讀取混移,并寫(xiě)入到一個(gè)非加密 pdf 中
小結(jié)
本文介紹了 PyPDF2 庫(kù)的基本用法祠墅,借助它加上代碼實(shí)例實(shí)現(xiàn)了一些基本操作;但在這里提醒一下歌径,所有上面這些操作只適用于批量操作場(chǎng)景毁嗦,如果對(duì)象是單個(gè)文件的話建議用常規(guī)做法,過(guò)于炫技的話只會(huì)浪費(fèi)時(shí)間
關(guān)于 pdf 內(nèi)的圖文內(nèi)容提取沮脖、寫(xiě)入本文并沒(méi)有涉獵金矛,源于 pypdf2 對(duì)于這方面并不擅長(zhǎng)芯急,而 Pdfplumber 和 PDFminer 在文本提取方面要好得多勺届,工欲善其事,必先利其器娶耍;在之后的教程中我將會(huì)介紹一下這方面的內(nèi)容免姿,期待大家的關(guān)注!
好了以上就是本篇內(nèi)容的全部?jī)?nèi)容榕酒,最后感謝大家的閱讀胚膊,我們下期見(jiàn)~