Portable Document Format(可移植文檔格式),或者PDF是一種文件格式澎胡,可以用于跨操作系統(tǒng)的呈現(xiàn)和文檔交換攻谁。盡管PDF最初是由Adobe發(fā)明的,但它現(xiàn)在是由國際標(biāo)準(zhǔn)化組織(ISO)維護的開放標(biāo)準(zhǔn)槐瑞。你可以通過使用PyPDF2包在Python中處理已先存在的PDF阁苞。
PyPDF2是一個純Python包那槽,可用于許多不同類型的PDF操作。
本文將帶你了解如何執(zhí)行以下操作:
從Python中提取PDF中的文檔信息?
旋轉(zhuǎn)頁面?
合并PDF?
拆分PDF?
添加水印?
加密PDF
pyPdf糟趾,PyPDF2和PyPDF4的歷史
最初的pyPdf軟件包于2005年發(fā)布义郑。pyPdf的最后一個正式版本是在2010年丈钙。大約一年后雏赦,一家名為Phasit的公司贊助了一個名為PyPDF2的pyPdf分支。該代碼編寫為向后與原始代碼兼容填大,并且用了好多年俏橘,效果一直很好,其最后一個版本是在2016年汉额。
有一個名為PyPDF3的軟件包簡短系列版本榨汤,然后該項目被重命名為PyPDF4收壕。所有這些項目都完全相同轨蛤,但pyPdf和PyPDF2 +之間的最大區(qū)別在于后者版本增加了Python 3支持祥山。Python 3的原始pyPdf有一個不同的Python 3分支,但是這個分支已經(jīng)多年沒有維護了澳窑。
雖然最近放棄了PyPDF2供常,但新的PyPDF4與PyPDF2沒有完全的向后兼容性栈暇。本文中的大多數(shù)示例都可以與PyPDF4完美配合,但也有一些不能煎源,這就是為什么PyPDF4在本文中沒有更多的特色手销。隨意用PyPDF4替換PyPDF2的導(dǎo)入图张,看看它是如何工作的埂淮。
pdfrw:一個替代的PDF操作包
Patrick Maupin創(chuàng)建了一個名為pdfrw的軟件包,它可以完成許多與PyPDF2相同的工作讲仰。除了加密的特殊情況外鄙陡,本文后面提到PyPDF2的所有操作,pdfrw均可以實現(xiàn)耙册。
pdfrw的最大區(qū)別在于它與ReportLab軟件包集成详拙,因此你可以使用一些或所有預(yù)先存在的PDF構(gòu)建一個新的PDF蔓同。
PyPDF2的安裝
如果使用Anaconda而不是常規(guī)Python斑粱,可以使用pip或conda安裝PyPDF2。以下是使用pip安裝PyPDF2的方法:
$pip install pypdf2
由于PyPDF2沒有任何依賴矿微,因此安裝非成写В快。
如何從Python中提取PDF文檔信息
我們可以使用PyPDF2從PDF中提取元數(shù)據(jù)和一些文本蒿辙,尤其是當(dāng)在預(yù)先存在的PDF文件上執(zhí)行某些類型的自動化時是非常有用的思灌。
以下是當(dāng)前可以提取的數(shù)據(jù)類型:
Author
Creator
Producer
Subject
Title
Number of page
可以在自己的電腦上隨便找一個PDF文件進(jìn)行嘗試操作恭取。下面是使用該PDF編寫一些代碼蜈垮,并了解如何訪問這些屬性:
fromPyPDF2importPdfFileReader
defextract_information(pdf_path):
withopen(pdf_path,'rb')asf:
pdf=PdfFileReader(f)
information=pdf.getDocumentInfo()
number_of_pages=pdf.getNumPages()
txt=f"""
? ? Information about {pdf_path}:
? ? Author: {information.author}
? ? Creator: {information.creator}
? ? Producer: {information.producer}
? ? Subject: {information.subject}
? ? Title: {information.title}
? ? Number of pages: {number_of_pages}
? ? """
print(txt)
returninformation
if__name__=='__main__':
path='xxxx.pdf'
extract_information(path)
首先從PyPDF2包導(dǎo)入PdfFileReader攒发。PdfFileReader是一個具有多種與PDF文件交互的方法的類惠猿。在此示例中,我們調(diào)用了.getDocumentInfo()姜凄,它將返回DocumentInformation的實例,包含了我們感興趣的大部分信息态秧。我們還可以在reader對象上調(diào)用.getNumPages(),讓它返回文檔中的頁數(shù)愤诱。
information這個變量具有多個實例屬性润讥,可以使用這些屬性從文檔中獲取所需的其余元數(shù)據(jù)楚殿。我們可以打印出該信息并將其返回以備將來使用脆粥。
雖然PyPDF2具有.extractText()影涉,可以在其頁面對象上使用提取文本(本例中未顯示)蟹倾,但它的效果不是很好鲜棠。有些PDF會返回文本,有些會返回空字符串柑爸。如果要從PDF中提取文本盒音,建議應(yīng)該看一下PDFMiner項目祥诽。PDFMiner更加強大雄坪,專門用于從PDF中提取文本。
小編給大家推薦一個學(xué)習(xí)氛圍超好的地方颇玷,python交流企鵝裙:【611+530+101】適合在校大學(xué)生就缆,小白竭宰,想轉(zhuǎn)行,想通過這個找工作的加入狞甚。裙里有學(xué)習(xí)資料哼审,有大神解答交流問題孕豹,每晚都有免費的直播課程
如何旋轉(zhuǎn)頁面励背?
有時候PDF是橫向模式而不是縱向模式叶眉,甚至是顛倒的。當(dāng)有人掃描文檔為PDF或電子郵件時离福,很可能會發(fā)生這種情況妖爷。我們可以打印出文檔并閱讀紙質(zhì)版本絮识,也可以使用Python的強大功能來旋轉(zhuǎn)有問題的頁面嗽上。
下面看一下如何使用PyPDF2旋轉(zhuǎn)文章的一些頁面:
fromPyPDF2importPdfFileReader,PdfFileWriter
defrotate_pages(pdf_path):
pdf_writer=PdfFileWriter()
pdf_reader=PdfFileReader(path)
# 順時針旋轉(zhuǎn)90度
page_1=pdf_reader.getPage(0).rotateClockwise(90)
pdf_writer.addPage(page_1)
# 逆時針旋轉(zhuǎn)90度
page_2=pdf_reader.getPage(1).rotateCounterClockwise(90)
pdf_writer.addPage(page_2)
# 在正常方向上添加一頁
pdf_writer.addPage(pdf_reader.getPage(2))
withopen('rotate_pages.pdf','wb')asfh:
pdf_writer.write(fh)
if__name__=='__main__':
path='新路徑.pdf'
rotate_pages(path)
上面除了pdfileReader之外兽愤,還導(dǎo)入了pdfileWriter,因為我們需要編寫一個新的pdf哲思。rotate_pages()獲取要修改的PDF的路徑棚赔。在這個函數(shù)中徘郭,需要創(chuàng)建一個可以命名為pdf-writer的writer對象和一個名為pdf-reader的reader對象残揉。
接下來抱环,可以使用.get page()獲取所需的頁面。上面開始輸入了第0頁濒憋,也就是第一頁何暇,調(diào)用page對象的.rotateClockwise()順時針旋轉(zhuǎn)方法并輸入90陶夜。然后同樣地,對于第二頁裆站,調(diào)用.rotateCounterLockwise()逆時針旋轉(zhuǎn)并輸入90条辟。
每次調(diào)用Rotation旋轉(zhuǎn)方法后,都會調(diào)用.addPage()宏胯,這將向writer對象添加頁面的旋轉(zhuǎn)版本羽嫡。最后一頁是第3頁,沒有對其進(jìn)行任何旋轉(zhuǎn)肩袍。最后,使用.write()把所有新頁寫入新的PDF氛赐。
如何合并PDF魂爪?
在許多情況下,我們希望將兩個或多個PDF合并到一個PDF中艰管。例如滓侍,現(xiàn)在可能有一個標(biāo)準(zhǔn)的封面,需要轉(zhuǎn)到許多類型的報告中牲芋。這時候就可以使用python來幫助完成這類工作撩笆。
下面是實現(xiàn)的代碼捺球,完成PDF合并的操作:
fromPyPDF2importPdfFileReader,PdfFileWriter
defmerge_pdfs(paths,output):
pdf_writer=PdfFileWriter()
forpathinpaths:
pdf_reader=PdfFileReader(path)
forpageinrange(pdf_reader.getNumPages()):
# 將每頁添加到writer對象
pdf_writer.addPage(pdf_reader.getPage(page))
# 寫入合并的pdf
withopen(output,'wb')asout:
pdf_writer.write(out)
if__name__=='__main__':
paths=['document1.pdf','document2.pdf']
merge_pdfs(paths,output='merged.pdf')
假如有一個要合并到一起的pdf列表時,可以直接使用merge_pdf函數(shù)完成夕冲。此函數(shù)采用了輸入路徑和輸出路徑作為參數(shù)氮兵。
首先遍歷輸入的paths,并為每個輸入創(chuàng)建一個PDF閱讀對象耘擂。然后遍歷PDF文件中的所有頁面胆剧,并使用.addpage()將這些頁面寫入writer對象。當(dāng)完成對列表中所有PDF的所有頁面的寫入后醉冤,將在末尾寫入新的結(jié)果中秩霍。
如果不想合并每個PDF的所有頁面,可以通過添加一系列要添加的頁面來稍微增強這個腳本蚁阳。挑戰(zhàn)一點的話铃绒,也可以使用Python的argparse模塊為這個函數(shù)創(chuàng)建一個命令行接口阿趁。
如何拆分PDF?
有時可能需要將PDF拆分為多個PDF莹规,對于包含大量掃描內(nèi)容的PDF來說尤其重要。以下是如何使用PyPDF2將PDF拆分為多個文件:
fromPyPDF2importPdfFileReader,PdfFileWriter
defsplit(path,name_of_split):
pdf=PdfFileReader(path)
forpageinrange(pdf.getNumPages()):
pdf_writer=PdfFileWriter()
pdf_writer.addPage(pdf.getPage(page))
output=f'{name_of_split}{page}.pdf'
withopen(output,'wb')asoutput_pdf:
pdf_writer.write(output_pdf)
if__name__=='__main__':
path='xxx.pdf'
split(path,'jupyter_page')
這個函數(shù)中再次創(chuàng)建了PDF的reaer對象鸡号,并對其所讀取的頁面進(jìn)行遍歷定血。對于PDF中的每個頁面赔癌,創(chuàng)建一個新的PDF的writer實例并向其添加單個頁面。然后澜沟,將該頁面寫入一個唯一命名的文件灾票。腳本運行完畢后,就可以將原始PDF的每個頁面拆分為單獨的PDF茫虽。
如何添加水涌浴?
水印是紙質(zhì)或者電子文檔上的圖像或圖案濒析,一些水印只能在特殊照明條件下才能看到正什。水印的重要性在于它可以保護你的知識產(chǎn)權(quán),例如圖像或PDF号杏。
我們可以使用Python和PyPDF2為文檔添加水印婴氮,而且是擁有僅包含水印圖像或文本的PDF。下面是向PDF添加水印方法:
fromPyPDF2importPdfFileWriter,PdfFileReader
defcreate_watermark(input_pdf,output,watermark):
watermark_obj=PdfFileReader(watermark)
watermark_page=watermark_obj.getPage(0)
pdf_reader=PdfFileReader(input_pdf)
pdf_writer=PdfFileWriter()
# 給所有頁面添加水印
forpageinrange(pdf_reader.getNumPages()):
page=pdf_reader.getPage(page)
page.mergePage(watermark_page)
pdf_writer.addPage(page)
withopen(output,'wb')asout:
pdf_writer.write(out)
if__name__=='__main__':
create_watermark(
input_pdf='Jupyter_Notebook_An_Introduction.pdf',
output='watermarked_notebook.pdf',
watermark='watermark.pdf')
上面create_watermark有三個參數(shù):
input_pdf:要加水印的PDF文件路徑
output:要保存PDF的水印版本的路徑
watermark:包含水印圖像或文本的PDF
在代碼中盾致,打開水印PDF并從文檔中抓取第一頁主经,因為這是水印應(yīng)該駐留的位置。然后使用input_pdf和通用pdf_writer對象創(chuàng)建PDF的writer對象绰上,以寫出帶水印的PDF旨怠。
下一步是遍歷input_pdf中的頁面,然后調(diào)用.mergePage()并以用上面讀取的水印對象watermark_page為參數(shù)蜈块,這樣會將watermark_page覆蓋在當(dāng)前頁面的頂部鉴腻,然后再將新合并的頁面添加到pdf_writer對象中迷扇。遍歷完成后,最后將新加水印的PDF寫入磁盤爽哎。
如何加密PDF蜓席?
PyPDF2目前僅支持將用戶密碼和所有者密碼添加到預(yù)先存在的PDF。在PDF版本中课锌,所有者密碼會提供PDF的管理員權(quán)限厨内,并允許設(shè)置文檔的權(quán)限,而用戶密碼只允許打開文檔渺贤。
實際上雏胃,PyPDF2是不允許設(shè)置文檔的任何權(quán)限的,即使它允許設(shè)置所有者密碼的情況下志鞍。但無論如何瞭亮,這是可以加密的方式,也將固有地加密PDF:
fromPyPDF2importPdfFileWriter,PdfFileReader
defadd_encryption(input_pdf,output_pdf,password):
pdf_writer=PdfFileWriter()
pdf_reader=PdfFileReader(input_pdf)
forpageinrange(pdf_reader.getNumPages()):
pdf_writer.addPage(pdf_reader.getPage(page))
pdf_writer.encrypt(user_pwd=password,owner_pwd=None,
use_128bit=True)
withopen(output_pdf,'wb')asfh:
pdf_writer.write(fh)
if__name__=='__main__':
add_encryption(input_pdf='reportlab-sample.pdf',
output_pdf='reportlab-encrypted.pdf',
password='twofish')
add_encryption以輸入輸出PDF路徑和要添加到PDF的密碼為參數(shù)固棚。由于需要加密整個輸入PDF统翩,因此需要遍歷其所有頁面并將其添加到writer編寫器。最后一步是調(diào)用.encrypt()此洲,以用戶密碼厂汗,所有者密碼以及是否應(yīng)該添加128位加密為參數(shù)。默認(rèn)情況下呜师,要啟用128位加密娶桦。如果將其設(shè)置為False,則將應(yīng)用40位加密匣掸。
結(jié)論
PyPDF2包非常有用趟紊,可以使用PyPDF2自動執(zhí)行腳本完成PDF文檔的批量操作氮双。本文介紹了如何從PDF中提取元數(shù)據(jù)碰酝,旋轉(zhuǎn)頁面,合并和拆分PDF戴差,添加水印送爸,以及添加加密的操作。
同時暖释,還要關(guān)注較新的PyPDF4包袭厂,因為它很快就會取代PyPDF2。也可以看看pdfrw包球匕,它也可以執(zhí)行許多與PyPDF2相同的操作纹磺。