用Python玩轉(zhuǎn)PDF的各種騷操作


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相同的操作纹磺。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市亮曹,隨后出現(xiàn)的幾起案子橄杨,更是在濱河造成了極大的恐慌秘症,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件式矫,死亡現(xiàn)場離奇詭異乡摹,居然都是意外死亡,警方通過查閱死者的電腦和手機采转,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門聪廉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人故慈,你說我怎么就攤上這事板熊。” “怎么了察绷?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵邻邮,是天一觀的道長。 經(jīng)常有香客問我克婶,道長筒严,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任情萤,我火速辦了婚禮鸭蛙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘筋岛。我一直安慰自己娶视,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布睁宰。 她就那樣靜靜地躺著肪获,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柒傻。 梳的紋絲不亂的頭發(fā)上孝赫,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音红符,去河邊找鬼青柄。 笑死,一個胖子當(dāng)著我的面吹牛预侯,可吹牛的內(nèi)容都是我干的致开。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼萎馅,長吁一口氣:“原來是場噩夢啊……” “哼双戳!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起糜芳,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤飒货,失蹤者是張志新(化名)和其女友劉穎千诬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體膏斤,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡徐绑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了莫辨。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片傲茄。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沮榜,靈堂內(nèi)的尸體忽然破棺而出盘榨,到底是詐尸還是另有隱情,我是刑警寧澤蟆融,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布草巡,位于F島的核電站,受9級特大地震影響型酥,放射性物質(zhì)發(fā)生泄漏山憨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一弥喉、第九天 我趴在偏房一處隱蔽的房頂上張望郁竟。 院中可真熱鬧,春花似錦由境、人聲如沸棚亩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讥蟆。三九已至,卻和暖如春纺阔,著一層夾襖步出監(jiān)牢的瞬間瘸彤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工州弟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钧栖,地道東北人低零。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓婆翔,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掏婶。 傳聞我的和親對象是個殘疾皇子啃奴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容