Python玩转PDF的各种骚操作


Posted in Python onMay 06, 2019

Portable Document Format(可移植文档格式),或者PDF是一种文件格式,可以用于跨操作系统的呈现和文档交换。尽管PDF最初是由Adobe发明的,但它现在是由国际标准化组织(ISO)维护的开放标准。你可以通过使用PyPDF2包在Python中处理已先存在的PDF。

PyPDF2是一个纯Python包,可用于许多不同类型的PDF操作。

本文将带你了解如何执行以下操作:

从Python中提取PDF中的文档信息

  • 旋转页面
  • 合并PDF
  • 拆分PDF
  • 添加水印
  • 加密PDF

一、pyPdf,PyPDF2和PyPDF4的历史

最初的pyPdf软件包于2005年发布。pyPdf的最后一个正式版本是在2010年。大约一年后,一家名为Phasit的公司赞助了一个名为PyPDF2的pyPdf分支。该代码编写为向后与原始代码兼容,并且用了好多年,效果一直很好,其最后一个版本是在2016年。

有一个名为PyPDF3的软件包简短系列版本,然后该项目被重命名为PyPDF4。所有这些项目都完全相同,但pyPdf和PyPDF2 +之间的最大区别在于后者版本增加了Python 3支持。Python 3的原始pyPdf有一个不同的Python 3分支,但是这个分支已经多年没有维护了。

虽然最近放弃了PyPDF2,但新的PyPDF4与PyPDF2没有完全的向后兼容性。本文中的大多数示例都可以与PyPDF4完美配合,但也有一些不能,这就是为什么PyPDF4在本文中没有更多的特色。随意用PyPDF4替换PyPDF2的导入,看看它是如何工作的。

二、pdfrw:一个替代的PDF操作包

Patrick Maupin创建了一个名为pdfrw的软件包,它可以完成许多与PyPDF2相同的工作。除了加密的特殊情况外,本文后面提到PyPDF2的所有操作,pdfrw均可以实现。

pdfrw的最大区别在于它与ReportLab软件包集成,因此你可以使用一些或所有预先存在的PDF构建一个新的PDF。

三、PyPDF2的安装

如果使用Anaconda而不是常规Python,可以使用pip或conda安装PyPDF2。以下是使用pip安装PyPDF2的方法:

$ pip install pypdf2

由于PyPDF2没有任何依赖,因此安装非常快。

四、如何从Python中提取PDF文档信息

我们可以使用PyPDF2从PDF中提取元数据和一些文本,尤其是当在预先存在的PDF文件上执行某些类型的自动化时是非常有用的。

以下是当前可以提取的数据类型:

  • Author
  • Creator
  • Producer
  • Subject
  • Title
  • Number of page

可以在自己的电脑上随便找一个PDF文件进行尝试操作。下面是使用该PDF编写一些代码,并了解如何访问这些属性:

from PyPDF2 import PdfFileReader
def extract_information(pdf_path):
 with open(pdf_path, 'rb') as f:
  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)
 return information
if __name__ == '__main__':
 path = 'xxxx.pdf'
 extract_information(path)

首先从PyPDF2包导入PdfFileReader。PdfFileReader是一个具有多种与PDF文件交互的方法的类。在此示例中,我们调用了.getDocumentInfo(),它将返回DocumentInformation的实例,包含了我们感兴趣的大部分信息。我们还可以在reader对象上调用.getNumPages(),让它返回文档中的页数。

information这个变量具有多个实例属性,可以使用这些属性从文档中获取所需的其余元数据。我们可以打印出该信息并将其返回以备将来使用。

虽然PyPDF2具有.extractText(),可以在其页面对象上使用提取文本(本例中未显示),但它的效果不是很好。有些PDF会返回文本,有些会返回空字符串。如果要从PDF中提取文本,建议应该看一下PDFMiner项目。PDFMiner更加强大,专门用于从PDF中提取文本。

五、如何旋转页面?

有时候PDF是横向模式而不是纵向模式,甚至是颠倒的。当有人扫描文档为PDF或电子邮件时,很可能会发生这种情况。我们可以打印出文档并阅读纸质版本,也可以使用Python的强大功能来旋转有问题的页面。

下面看一下如何使用PyPDF2旋转文章的一些页面:

from PyPDF2 import PdfFileReader, PdfFileWriter
def rotate_pages(pdf_path):
 pdf_writer = PdfFileWriter()
 pdf_reader = PdfFileReader(path)
 # 顺时针旋转90度
 page_1 = pdf_reader.getPage(0).rotateClockwise(90)
 pdf_writer.addPage(page_1)
 # 逆时针旋转90度
 page_2 = pdf_reader.getPage(1).rotateCounterClockwise(90)
 pdf_writer.addPage(page_2)
 # 在正常方向上添加一页
 pdf_writer.addPage(pdf_reader.getPage(2))
 with open('rotate_pages.pdf', 'wb') as fh:
  pdf_writer.write(fh)
if __name__ == '__main__':
 path = '新路径.pdf'
 rotate_pages(path)

上面除了pdfileReader之外,还导入了pdfileWriter,因为我们需要编写一个新的pdf。rotate_pages()获取要修改的PDF的路径。在这个函数中,需要创建一个可以命名为pdf-writer的writer对象和一个名为pdf-reader的reader对象。

接下来,可以使用.get page()获取所需的页面。上面开始输入了第0页,也就是第一页,调用page对象的.rotateClockwise()顺时针旋转方法并输入90。然后同样地,对于第二页,调用.rotateCounterLockwise()逆时针旋转并输入90。

每次调用Rotation旋转方法后,都会调用.addPage(),这将向writer对象添加页面的旋转版本。最后一页是第3页,没有对其进行任何旋转。最后,使用.write()把所有新页写入新的PDF。

六、如何合并PDF?

在许多情况下,我们希望将两个或多个PDF合并到一个PDF中。例如,现在可能有一个标准的封面,需要转到许多类型的报告中。这时候就可以使用python来帮助完成这类工作。

下面是实现的代码,完成PDF合并的操作:

from PyPDF2 import PdfFileReader, PdfFileWriter

def merge_pdfs(paths, output):
 pdf_writer = PdfFileWriter()
 for path in paths:
  pdf_reader = PdfFileReader(path)
  for page in range(pdf_reader.getNumPages()):
   # 将每页添加到writer对象
   pdf_writer.addPage(pdf_reader.getPage(page))
 # 写入合并的pdf
 with open(output, 'wb') as out:
  pdf_writer.write(out)
if __name__ == '__main__':
 paths = ['document1.pdf', 'document2.pdf']
 merge_pdfs(paths, output='merged.pdf')

假如有一个要合并到一起的pdf列表时,可以直接使用merge_pdf函数完成。此函数采用了输入路径和输出路径作为参数。

首先遍历输入的paths,并为每个输入创建一个PDF阅读对象。然后遍历PDF文件中的所有页面,并使用.addpage()将这些页面写入writer对象。当完成对列表中所有PDF的所有页面的写入后,将在末尾写入新的结果中。

如果不想合并每个PDF的所有页面,可以通过添加一系列要添加的页面来稍微增强这个脚本。挑战一点的话,也可以使用Python的argparse模块为这个函数创建一个命令行接口。

七、如何拆分PDF?

有时可能需要将PDF拆分为多个PDF,对于包含大量扫描内容的PDF来说尤其重要。以下是如何使用PyPDF2将PDF拆分为多个文件:

from PyPDF2 import PdfFileReader, PdfFileWriter
def split(path, name_of_split):
 pdf = PdfFileReader(path)
 for page in range(pdf.getNumPages()):
  pdf_writer = PdfFileWriter()
  pdf_writer.addPage(pdf.getPage(page))
  output = f'{name_of_split}{page}.pdf'
  with open(output, 'wb') as output_pdf:
   pdf_writer.write(output_pdf)
if __name__ == '__main__':
 path = 'xxx.pdf'
 split(path, 'jupyter_page')

这个函数中再次创建了PDF的reaer对象,并对其所读取的页面进行遍历。对于PDF中的每个页面,创建一个新的PDF的writer实例并向其添加单个页面。然后,将该页面写入一个唯一命名的文件。脚本运行完毕后,就可以将原始PDF的每个页面拆分为单独的PDF。

八、如何添加水印?

水印是纸质或者电子文档上的图像或图案,一些水印只能在特殊照明条件下才能看到。水印的重要性在于它可以保护你的知识产权,例如图像或PDF。

我们可以使用Python和PyPDF2为文档添加水印,而且是拥有仅包含水印图像或文本的PDF。下面是向PDF添加水印方法:

from PyPDF2 import PdfFileWriter, PdfFileReader
def create_watermark(input_pdf, output, watermark):
 watermark_obj = PdfFileReader(watermark)
 watermark_page = watermark_obj.getPage(0)
 pdf_reader = PdfFileReader(input_pdf)
 pdf_writer = PdfFileWriter()
 # 给所有页面添加水印
 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)
if __name__ == '__main__':
 create_watermark(
  input_pdf='Jupyter_Notebook_An_Introduction.pdf', 
   output='watermarked_notebook.pdf',
  watermark='watermark.pdf')

上面create_watermark有三个参数:

  • input_pdf:要加水印的PDF文件路径
  • output:要保存PDF的水印版本的路径
  • watermark:包含水印图像或文本的PDF

在代码中,打开水印PDF并从文档中抓取第一页,因为这是水印应该驻留的位置。然后使用input_pdf和通用pdf_writer对象创建PDF的writer对象,以写出带水印的PDF。

下一步是遍历input_pdf中的页面,然后调用.mergePage()并以用上面读取的水印对象watermark_page为参数,这样会将watermark_page覆盖在当前页面的顶部,然后再将新合并的页面添加到pdf_writer对象中。遍历完成后,最后将新加水印的PDF写入磁盘。

九、如何加密PDF?

PyPDF2目前仅支持将用户密码和所有者密码添加到预先存在的PDF。在PDF版本中,所有者密码会提供PDF的管理员权限,并允许设置文档的权限,而用户密码只允许打开文档。

实际上,PyPDF2是不允许设置文档的任何权限的,即使它允许设置所有者密码的情况下。但无论如何,这是可以加密的方式,也将固有地加密PDF:

from PyPDF2 import PdfFileWriter, PdfFileReader
def add_encryption(input_pdf, output_pdf, password):
 pdf_writer = PdfFileWriter()
 pdf_reader = PdfFileReader(input_pdf)
 for page in range(pdf_reader.getNumPages()):
  pdf_writer.addPage(pdf_reader.getPage(page))
 pdf_writer.encrypt(user_pwd=password, owner_pwd=None, 
      use_128bit=True)
 with open(output_pdf, 'wb') as fh:
  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的密码为参数。由于需要加密整个输入PDF,因此需要遍历其所有页面并将其添加到writer编写器。最后一步是调用.encrypt(),以用户密码,所有者密码以及是否应该添加128位加密为参数。默认情况下,要启用128位加密。如果将其设置为False,则将应用40位加密。

结论

PyPDF2包非常有用,可以使用PyPDF2自动执行脚本完成PDF文档的批量操作。本文介绍了如何从PDF中提取元数据,旋转页面,合并和拆分PDF,添加水印,以及添加加密的操作。

同时,还要关注较新的PyPDF4包,因为它很快就会取代PyPDF2。也可以看看pdfrw包,它也可以执行许多与PyPDF2相同的操作。

以上所述是小编给大家介绍的Python玩转PDF的各种骚操作,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Python 相关文章推荐
利用soaplib搭建webservice详细步骤和实例代码
Nov 20 Python
linux系统使用python监控apache服务器进程脚本分享
Jan 15 Python
Python八大常见排序算法定义、实现及时间消耗效率分析
Apr 27 Python
Python3中在Anaconda环境下安装basemap包
Oct 21 Python
Python操作Excel插入删除行的方法
Dec 10 Python
Python内置random模块生成随机数的方法
May 31 Python
Python OpenCV 调用摄像头并截图保存功能的实现代码
Jul 02 Python
通过实例解析Python RPC实现原理及方法
Jul 07 Python
python爬虫要用到的库总结
Jul 28 Python
python输出国际象棋棋盘的实例分享
Nov 26 Python
python中对列表的删除和添加方法详解
Feb 24 Python
Python实现数据的序列化操作详解
Jul 07 Python
使用Python和Prometheus跟踪天气的使用方法
May 06 #Python
Python中常用的8种字符串操作方法
May 06 #Python
基于python if 判断选择结构的实例详解
May 06 #Python
20行python代码的入门级小游戏的详解
May 05 #Python
python2.7 安装pip的方法步骤(管用)
May 05 #Python
Python中print和return的作用及区别解析
May 05 #Python
Python深拷贝与浅拷贝用法实例分析
May 05 #Python
You might like
谈谈新手如何学习PHP
2006/12/14 PHP
PHP与SQL注入攻击[二]
2007/04/17 PHP
php 中英文语言转换类代码
2011/08/11 PHP
php-perl哈希算法实现(times33哈希算法)
2013/12/30 PHP
php获取数组元素中头一个数组元素值的实现方法
2014/12/20 PHP
PHP常用字符串操作函数实例总结(trim、nl2br、addcslashes、uudecode、md5等)
2016/01/09 PHP
PHP如何读取由JavaScript设置的Cookie
2017/03/22 PHP
javascript阻止scroll事件多次执行的思路及实现
2013/11/08 Javascript
jQuery使用元素属性attr赋值详解
2015/02/27 Javascript
js实现兼容IE和FF的上下层的移动
2015/05/04 Javascript
Angular实现的进度条功能示例
2018/02/18 Javascript
Vue自定义指令封装节流函数的方法示例
2018/07/09 Javascript
JavaScript+Canvas实现彩色图片转换成黑白图片的方法分析
2018/07/31 Javascript
利用node 判断打开的是文件 还是 文件夹的实例
2019/06/10 Javascript
antd Form组件方法getFieldsValue获取自定义组件的值操作
2020/10/29 Javascript
详解vue实现坐标拾取器功能示例
2020/11/18 Vue.js
[04:52]第二届DOTA2亚洲邀请赛主赛事第一天比赛集锦:OG娜迦海妖放大配合谜团大中3人
2017/04/02 DOTA
Python Mysql自动备份脚本
2008/07/14 Python
Python与shell的3种交互方式介绍
2015/04/11 Python
python下调用pytesseract识别某网站验证码的实现方法
2016/06/06 Python
python 2.7.14安装图文教程
2018/04/08 Python
Python爬虫基础之XPath语法与lxml库的用法详解
2018/09/13 Python
Python函数参数匹配模型通用规则keyword-only参数详解
2019/06/10 Python
Python pandas用法最全整理
2019/08/04 Python
从训练好的tensorflow模型中打印训练变量实例
2020/01/20 Python
在tensorflow下利用plt画论文中loss,acc等曲线图实例
2020/06/15 Python
Python selenium模块实现定位过程解析
2020/07/09 Python
python中的插入排序的简单用法
2021/01/19 Python
Html5 new XMLHttpRequest()监听附件上传进度
2021/01/14 HTML / CSS
芬兰攀岩、山地运动和户外活动用品购物网站:Bergfreunde
2016/10/06 全球购物
德国最新街头服饰网上商店:BODYCHECK
2019/09/15 全球购物
办理信用卡工作证明
2014/01/11 职场文书
先进德育工作者事迹材料
2014/01/24 职场文书
低碳环保口号
2014/06/12 职场文书
Java elasticsearch安装以及部署教程
2021/06/28 Java/Android
Go语言基础知识点介绍
2021/07/04 Golang