日常从批量合并 PDF 到 PyPDF2 的使用
Posted 囚生CY
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了日常从批量合并 PDF 到 PyPDF2 的使用相关的知识,希望对你有一定的参考价值。
序言
临近卷铺走人因此有不少手续要办,提交文件遇到需要合并PDF文件的需求。恰好个人电脑还处于文件强制加密的状态,编辑文档保存会自动加密,出于某些原因不方便恢复到正常状态的备份,因此给合并PDF带来很多麻烦。
这时候会考虑是否有捷径可以走,这时候笔者发现Python是有可以进行PDF文件编辑操作的开源包PyPDF2,简单pip安装即可👇
pip install pypdf2
下面提供了一个非常便捷的用于批量合并PDF文件的函数,只需要传入需要合并的PDF文件所在目录,以及合并后的文件导出路径两个变量(pdf_path, save_path)即可👇
# -*- coding: UTF-8 -*-
# Author: 囚生CY
# 合并pdf的工具函数
import os
from PyPDF2 import PdfFileReader,PdfFileWriter
# 合并同一目录下的所有PDF文件
def merge_pdf(pdf_path,save_path): # pdf_path为需要合并的所有pdf所在路径, save_path为合并后的文件导出路径
writer = PdfFileWriter() # 创建PDF文件书写器对象
total_pages = 0 # 标记页码数
pdf_filepaths = [] # 用于存储所有的pdf的路径
for root,dirname,filenames in os.walk(pdf_path):
for filename in filenames:
try: suffix = filename[-4:]
except: continue # 这个报错说明文件名连4位都没有, 直接跳过即可
if suffix==".pdf": # 说明是pdf文件
pdf_filepaths.append(os.path.join(pdf_path,filename))
for path in pdf_filepaths: # 遍历所有pdf我呢见
reader = PdfFileReader(open(path,"rb")) # 读取pdf文件
pages = reader.getNumPages() # 获取当前pdf文件的页码数
total_pages += pages # 更新总页码数
for i in range(pages): writer.addPage(reader.getPage(i)) # 遍历当前pdf文件的每一页: 将每一页的信息添加到pdf文件书写器中
print("已添加\\t共页,累计页".format(path,pages,total_pages))
writer.write(open(save_path,"wb"))
print("PDF文件合并完成!")
if __name__ == "__main__":
pdf_path = "raw"
save_path = "merged_file.pdf"
merge_pdf(pdf_path,save_path)
应该说合并的效率是非常高的,并且结果也是很满意的,注意合并的顺序是文件名的默认排序,如果需要自定义顺序的话可以在PDF文件名前添加001, 002, ... , 010的前缀标注顺序即可。
PyPDF2 使用
事实上PyPDF2是个很小的包,在site-packages中可以看到它只有一层目录,而且主要的功能代码只在pdf.py中,但是这并不影响PyPDF2仍是一个有很多重要功能的包。因此在索用了前人的劳动成果解决问题后,细看当中还是否有其他的可取用的知识也是不错的选择。
其实从序言中的代码逻辑里不难看出,PyPDF2可以任意挑选PDF页面进行任意拼接的操作,因此可以很简单的实现PDF页面级别的增删改操作。事实上PyPDF2中只有两个功能类PdfFileWriter, PdfFileReader, 但是这两个类中都封装了很多功能,前者除了对PDF文件的简单页面编辑操作外,还可以对PDF文件进行一些改动,如加密、添加启动时的将执行的操作等;后者则是用于挖掘PDF文件中的信息,比如使用LATEX生成的PDF中就可以很容易的去查出reference, contents等信息,并且相对应PdfFileWriter中的加密,这里还给出了解密的功能。
PdfFileWriter类
writer对象可以为最终导出的PDF文件增加各种信息,如Metadata, Link等,这里主要介绍一下addJS与encrypt方法👇
writer.addBlankPage(1080,1920) # 添加一个空白页面, 参数为页面的宽与高
writer.addMetadata("version":"1.0.1") # 添加metadata后使用PdfFileReader对象可以读取metadata
writer.addJS("alert('FBI Warning!');") # 添加javascript可以在启动时执行,但是这个似乎对PDF阅读软件有限制,笔者使用的Foxit似乎不支持这个效果
writer.addBookMark(title="Chapter 1",pagenum=1) # 指定页码添加书签
writer.encrypt("123456","12345678") # 加密文档: 第一个参数是使用者的密码, 以该密码进入后权限受限制, 后者为所有者密码, 拥有文档的所有权限
writer.removeImages() # 移除文档中的所有图片
writer.removeLinks() # 移除文档中的所有链接
writer.removeText() # 移除文档中的所有文字
- addJS方法可以加入一段在导出的PDF文件启动时立即执行的JS,虽然作为JS小白并不能搞清楚脱离HTML页面究竟应该如何写JS代码,但是简单写个alert应该是没有太大问题的。但是这个似乎对PDF阅读器有所限制,至少笔者使用的Foxit阅读器是不能执行JS代码的。标准的Adobe阅读器应该是可行的。我有看到别人写"this.print(bUI:true,bSilent:false,bShrinkToFit:true);",虽然并不太懂是什么意思[Faceplam]
- encrypt可以给导出的PDF文档加密,启动时需要输入密码才能进入,并且可以设定两种不同权限的密码——使用者密码与所有者密码,可以很容易的实现。
此外writer对象还可以最终移除导出文档中所有图片、链接、文字,以及最终可以修改页面格式👇
PdfFileReader类
reader中有很多方法是和writer相对应的,writer设置了一些什么,就会在reader中得到什么👇
reader.decrypt("123456") # 解密进入文档
reader.getNumPages() # 总页数
reader.getOutlines() # 获取提纲
reader.getPageLayout() # 获取页面布局情况
reader.getPageMode() # 获取页面模式
reader.getXmpMetadata() # 获取元信息
reader.getBookMark() # 获取书签
其他一些诸如getDocumentInfo()以及getFields()等PDF文件的属性信息不多作介绍。
PageObject类
其实里面还有一个PageObject类,使用reader获取到的每一页就是一个PageObject类👇
page = reader.getPage(0) # 获取当前pdf文件的第一页
使用该类中的方法可以进行页面尺寸的裁剪,扩张,以及进行页面旋转的操作,这样使得在最终的合并结果中可以有形色各异的页面,不过这已经属于设计的范畴,笔者觉得没有太大深究的必要👇
page = page.rotateClockwise(90) # 顺时针旋转90°
page = page.rotateCounterClockwise(90) # 逆时针旋转90°
page = page1.mergePage(page2) # 合并两个页面, 比如当page2是水印图片页时可以起到对page1增加水印的效果
# 裁剪页面大小为当前的一半
page = page.mediaBox.upperRight = (
page.mediaBox.getUpperRight_x() / 2,
page.mediaBox.getUpperRight_y() / 2
)
值得注意的是PageObject类当中有一个page.extractText()方法可以用于挖掘页面中的文字信息,不过这个方法并不总是能奏效,只有当PDF是非常工整的文字型的PDF时才能比较精确的获取到页面中的文字信息。
后记
其实很多时候不仔细过一遍可能只觉得PyPDF2只是可以编辑重组页面,细细品后发现还是有很多有趣的功能。好在今晚不加班,抽空写了这篇博客。
总之分享学习,共同进步!
以上是关于日常从批量合并 PDF 到 PyPDF2 的使用的主要内容,如果未能解决你的问题,请参考以下文章