乐于分享
好东西不私藏

每天学习一点Python——用PyPDF2玩转PDF文件-2

每天学习一点Python——用PyPDF2玩转PDF文件-2

每天学习一点Python——用PyPDF2玩转PDF文件-2


工作中经常需要处理PDF文件——合并多份报告、插入目录页、旋转方向错误的页面、甚至给机密文件加密。

今天我们用PyPDF2库,逐行拆解四个实战场景


一、合并多个PDF文件

from PyPDF2 import PdfMergerfrom pathlib import Pathreports_dir = (    Path.cwd()/    "practice_files"/    "expense_reports")

📌 逐行拆解:

• from PyPDF2 import PdfMerger→ 导入合并PDF所需的PdfMerger

• from pathlib import Path→ 导入Path类,用于跨平台路径操作

• Path.cwd()→ 获取当前工作目录

• 连续两个/→ Path对象的路径拼接语法


expense_reports = list(reports_dir.glob("*.pdf"))expense_reports.sort()

📌 逐行拆解:

• .glob("*.pdf")→ 在reports_dir路径下匹配所有.pdf结尾的文件

• expense_reports→ 得到所有PDF文件的目录列表

• list()→ 将生成器转为列表

• .sort()→ 按文件名升序排序,确保合并顺序可控

⚠️ 关键点如果reports_dir指向的是文件而非文件夹.glob()会返回空列表


pdf_merger = PdfMerger()for path in expense_reports:    pdf_merger.append(str(path))    # 也可以选择追加的页数    # pdf_merger.append(str(path), pages=(0, 3))

📌 逐行拆解:

• PdfMerger()→ 创建合并器对象

• append(str(path))→ 将PDF文件追加到合并器末尾

• 参数要求:文件路径字符串 或 文件对象

• 可选参数:pages=(0,3)→ 只取第1-3页(默认全部页面


with Path("expense_reports.pdf").open(mode="wb") as output_file:    pdf_merger.write(output_file)

📌 逐行拆解:

• Path("expense_reports.pdf").open(mode="wb")→ 以二进制写入模式创建输出文件

• pdf_merger.write(output_file)→ 将合并后的内容写入文件

✅ 执行结果:当前目录生成expense_reports.pdf内含所有匹配的PDF文件


二、在指定位置插入PDF页面

report_dir = (    Path.cwd()/    "practice_files"/    "quarterly_report")report_path = report_dir/"report.pdf"toc_path = report_dir/"toc.pdf"

📌 逐行拆解:

• report_path→ 指向主报告

• toc_path→ 指向目录页PDF


pdf_merger = PdfMerger()pdf_merger.append(str(report_path))pdf_merger.merge(1, str(toc_path))

📌 逐行拆解:

• append()→ 先装入主报告

• merge(1, str(toc_path))→ 在索引1的位置插入目录

• 第一个参数:插入位置(0-based)→ 1表示原报告的第2页之前

• 与append()的区别:merge()嵌入中间,不是追加到末尾


with Path("full_report.pdf").open(mode="wb") as output_file:    pdf_merger.write(output_file)

✅ 执行结果:生成full_report.pdf

• 第1页:原报告首页• 第2页:目录• 之后:原报告剩余页


💡 易错Tipmerge()的位置索引是插入后该页将成为第几页merge(1, toc) = 新文档的第2页是目录。建议:先在纸上画页码,再敲代码。


🧩 三、按奇偶页旋转页面

from PyPDF2 import PdfReader, PdfWriterpdf_path = Path.cwd()/"full_report.pdf"pdf_reader = PdfReader(str(pdf_path))pdf_writer = PdfWriter()

📌 逐行拆解:

• PdfReader()→ 读取PDF文件,参数需是路径字符串

• PdfWriter()→ 创建空白写入器,用于组装新PDF


for n in range(len(pdf_reader.pages)):    page = pdf_reader.pages[n]    if n % 2 == 0:        page.rotate(-90)    pdf_writer.add_page(page)

📌 逐行拆解:

• pdf_reader.pages→ 列表,包含所有页面对象

• len(pdf_reader.pages)→ 总页数

• n % 2 == 0→ 索引从0开始 → 对应第1、3、5页

• rotate(-90)→ 顺时针旋转90度(负值=顺时针,正值=逆时针)

• add_page(page)→ 将(可能旋转过的)页面加入写入器


with open("rotated_output.pdf","wb") as output_file:    pdf_writer.write(output_file)

✅ 执行结果:生成rotated_output.pdf

• 第1、3、5页:顺时针旋转90度• 其他页:保持不变


💡 易错Tip• rotate()直接修改原页面对象• 若后续需要原始方向,务必提前复制页面• 旋转参数单位是必须是90的倍数


🔔 特别注意:这里的n从0开始,所以你会发现第1、3、5页进行了旋转


四、检测并修复旋转过的页面

pdf_path = Path.cwd()/"rotated_output.pdf"pdf_reader = PdfReader(str(pdf_path))pdf_writer = PdfWriter()

📌 逐行拆解:

• 读取刚才生成的旋转版PDF,准备修复


for page in pdf_reader.pages:    try:        if page["/Rotate"] == -90:            page.rotate(90)    except KeyError:        pass    pdf_writer.add_page(page)

📌 逐行拆解:

• page["/Rotate"]→ 访问页面的旋转属性字典

• 若键不存在(页面未被旋转过)→ 抛出KeyError

• except KeyError: pass→ 跳过无旋转属性的页面

• page.rotate(90)→ 将-90度的页面逆时针回转90度,恢复正向


with open("output.pdf","wb") as output_file:    pdf_writer.write(output_file)

✅ 执行结果:生成output.pdf所有页面恢复原始方向


💡 易错Tip并非所有PDF页面都有/Rotate若直接访问page['/Rotate']而不捕获异常,程序会崩溃

也可用hasattr的方法:

pdf_path = Path.cwd()/"rotated_output.pdf"pdf_reader = PdfReader(str(pdf_path))pdf_writer = PdfWriter()for page in pdf_reader.pages:    if hasattr(page, '/Rotate') and page['/Rotate'] == -90:        page.rotate(90)    pdf_writer.add_page(page)with open("output.pdf","wb") as output_file:    pdf_writer.write(output_file)

五、为PDF添加密码保护

pdf_path = Path.cwd()/"full_report.pdf"pdf_reader = PdfReader(str(pdf_path))pdf_writer = PdfWriter()

📌 逐行拆解:

• 读取原始完整报告,准备加密


pdf_writer.append(pdf_reader)pdf_writer.encrypt(user_pwd="mnzxs")

📌 逐行拆解:

• append(pdf_reader)→ 将读取器中的所有页面复制到写入器

• encrypt(user_pwd="mnzxs")→ 设置用户密码

• 可选参数:owner_pwd= → 所有者密码(权限更高)use_128bit=True → 提升加密强度(默认40位RC4)


output_path = Path.cwd()/"full_report_protected.pdf"with output_path.open(mode="wb") as output_file:    pdf_writer.write(output_file)

✅ 执行结果:生成full_report_protected.pdf打开时需输入密码mnzxs


六、解密受保护的PDF

pdf_path = Path.cwd()/"full_report_protected.pdf"pdf_reader = PdfReader(str(pdf_path))

📌 逐行拆解:

• 读取加密文件⚠️ 此时若直接访问pdf_reader.pages会抛出异常


success = pdf_reader.decrypt("mnzxs")

📌 逐行拆解:

• decrypt(password)→ 尝试用密码解密

• 返回值:1 或 PasswordType.USER_PASSWORD → 成功0 → 失败

• 解密成功后→ pdf_reader.pages才可访问


if success:    print("解密成功")    page = pdf_reader.pages[0]else:    print("解密失败")

✅ 执行结果:

解密成功

💡 易错Tip• decrypt()成功后,读取器对象会一直保持解密状态,无需再次解密• decrypt()不会修改源文件,只是让你能读取内容• 若要移除密码,必须用写入器另存新文件


七、总结

今天我们走完了PDF处理的完整链路

操作
核心代码
合并 PdfMerger().append()
插入 merge(位置, 文件)
旋转 page.rotate(±90)
加密 writer.encrypt(user_pwd=...)
解密 reader.decrypt(...)

📌 两点牢记:

🔸 路径处理Path()拼接时——文件夹还是文件,心里要有数

🔸 页面索引程序员数数从0开始,用户看页从1开始


📦 资源获取提示

关注「码农自习室」,后台回复关键词 Python学习,即可获取本文完整代码,一起动手掌握高效编程的核心技巧!


❤️ 支持我们

如果觉得本文对你有帮助,欢迎点赞 + 关注,您的支持是我们持续创作优质内容的最大动力!


📚 学习资源说明

本文内容整理自《Python基础教程(第3版)》第13章,所有命令均已实测。

本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 每天学习一点Python——用PyPDF2玩转PDF文件-2

评论 抢沙发

1 + 5 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮