pypdf 实战:5 段代码搞定 PDF 合并、加密与文本提取
2026/9/17 15:55:27 网站建设 项目流程

pypdf 实战:5 段代码搞定 PDF 合并、加密与文本提取

【免费下载链接】pypdfA pure-python PDF library capable of splitting, merging, cropping, and transforming the pages of PDF files项目地址: https://gitcode.com/GitHub_Trending/py/pypdf

周五下午,产品把 40 份区域销售报告发过来,要求合并成一份、盖"机密"水印、再设个只读密码。你打开终端,pip install pypdf装完这个纯 Python 的 PDF 处理库,下面几段代码就够把活干完。pypdf 能读、能合并、能加密、能抽文本,全在一个包里。

30 秒上手

装库,一行命令:

pip install pypdf # 加密可选: pip install pypdf[crypto]

先跑通一段最小脚本,确认能读到东西再看后面:

from pypdf import PdfReader reader = PdfReader("report.pdf") # 只读预览器 print("页数:", len(reader.pages)) # 先确认页数 print(reader.pages[0].extract_text()[:200]) # 第一页前 200 字

PdfReader 是只读预览器,PdfWriter 是空白画布——你从前者"搬页"到后者,再落盘,是所有改写操作的基本套路。

🔍 读懂一份 PDF

布局模式抽文本:extract_text默认的 plain 模式容易把多列排版打乱,layout 模式按页面几何位置还原,多列、跨栏文档更稳。

from pypdf import PdfReader reader = PdfReader("report.pdf") for page in reader.pages: text = page.extract_text(extraction_mode="layout") # 布局模式 print(text[:80]) # …其余页面同理

⚠️ 一个坑:参数名是extraction_mode="layout",没有layout_mode=True这种写法。

验证:打印出来的文本是否保持了两列的换行,而不是左右列交替串成一坨。

元数据速查:reader.metadata返回一个类字典对象,直接取字段即可,不用解析 XML。

meta = reader.metadata print(meta.title, meta.author, meta.creation_date)

⚠️ 一个坑:没写元数据的文件这些字段是None,取前先判空,别直接.strftime

验证:print(meta.title)不为空。

大纲解析:reader.outline返回嵌套列表,叶子节点是Destination,用reader.get_page_number(item)拿页码。递归一层就够,别自己维护栈。

验证:打印每个大纲项的页码,和你肉眼在阅读器里点到的位置一致。

📄 改一份 PDF

多文件合并:append比逐个add_page省事,整份追加、按页范围追加都支持。

from pypdf import PdfWriter writer = PdfWriter() writer.append("region_east.pdf") # 整份追加 writer.append("region_west.pdf", (0, 10)) # 只要前 10 页 with open("merged.pdf", "wb") as f: writer.write(f)

⚠️ 一个坑:append的第二个参数是页范围元组(start, stop),stop 不含边界;别拿它当"第 N 页"用。

验证:print(len(PdfReader("merged.pdf").pages))等于两份之和。

按页拆分:读一次,按区间add_page到多个 writer 即可。

from pypdf import PdfReader, PdfWriter reader = PdfReader("large.pdf") for start in range(0, len(reader.pages), 10): w = PdfWriter() for p in reader.pages[start:start+10]: w.add_page(p) with open(f"part_{start//10}.pdf", "wb") as f: w.write(f) # …其余区间同理

⚠️ 一个坑:reader.pages切片返回的是页对象引用,别在循环里改同一个 writer 反复写,每段开新的 writer。

验证:各分文件页数相加等于原文件。

旋转与缩放:文档建议优先用page.rotate(角度),它比add_transformation(Transformation().rotate())更直接;缩放走Transformation().scale

from pypdf import PdfReader, PdfWriter, Transformation reader = PdfReader("doc.pdf") writer = PdfWriter() for page in reader.pages: page.rotate(90) # 整页转 90 度 page.add_transformation(Transformation().scale(0.8, 0.8)) # 内容缩到 80% writer.add_page(page) # …其余页面同理 with open("out.pdf", "wb") as f: writer.write(f)

⚠️ 一个坑:rotate改的是页面旋转属性,scale只缩放内容不缩页面框,两者叠加时框不变、内容变小,别误以为缩放了整页。

验证:打开out.pdf看方向与内容大小是否符合预期。

叠加文字水印:把水印页merge_page到目标页,over=False让它垫底当背景水印。

from pypdf import PdfReader, PdfWriter reader = PdfReader("doc.pdf") stamp = PdfReader("confidential.pdf").pages[0] # 水印页 writer = PdfWriter() for page in reader.pages: page.merge_page(stamp, over=False) # over=False 水印在底 writer.add_page(page) with open("stamped.pdf", "wb") as f: writer.write(f)

⚠️ 一个坑:over=False才是水印垫底;写成True会把水印盖在最上层挡住正文。

验证:stamped.pdf每页都有水印且正文可读。

🔐 锁住一份 PDF

加密加权限:encrypt第一个位置参数是user_password(打开用),再传owner_password和算法。权限默认全开,想限只读就收窄permissions_flag

from pypdf import PdfReader, PdfWriter from pypdf.constants import UserAccessPermissions writer = PdfWriter() for page in PdfReader("doc.pdf").pages: writer.add_page(page) # 只允许打印+复制,禁止改内容和填表单 writer.encrypt( "open123", "owner123", algorithm="AES-256", permissions_flag=UserAccessPermissions.PRINT | UserAccessPermissions.EXTRACT, ) with open("locked.pdf", "wb") as f: writer.write(f)

⚠️ 一个坑:permissions_flag里位是 1 表示"允许",默认是全部允许;想限制要显式传标志位,而不是以为不传就是锁死。

验证:用open123能打开,用 owner 密码能解除限制。

带密码解密:读取时把密码传给PdfReader,再搬到新 writer 落盘即得到未加密副本。

from pypdf import PdfReader, PdfWriter reader = PdfReader("locked.pdf", password="open123") # 传入密码 writer = PdfWriter() for page in reader.pages: writer.add_page(page) with open("decrypted.pdf", "wb") as f: writer.write(f)

⚠️ 一个坑:密码错了会在PdfReader(...)构造时直接抛PdfReadError,后面extract_text根本轮不到执行,排错先看构造那行。

验证:PdfReader("decrypted.pdf")不带密码也能读。

排坑速查

大文件MemoryError→ pypdf 一次把整份文档读进内存 → 用文件对象传入PdfReader(open("big.pdf","rb"))并逐页处理,别一次for page in全量抽完。

加密 PDF 读时抛PdfReadError→ 构造PdfReader时没传密码 →PdfReader(path, password="…"),密码错和未加密是两种不同报错,先看具体信息。

extract_text出来是空串或乱码 → 字体没带 ToUnicode 映射,纯文本模式抽不到 → 换extraction_mode="layout"试一次,仍为空说明是纯图片扫描件,得走 OCR。

练手小项目

周末做个"报告打包器":读入一个文件夹里的所有 PDF,按文件名排序合并成一份,每页盖公司名水印,最后设一个打开密码。只处理这一个目录、不递归子目录、不抽文本入库——目标是跑通"合并+水印+加密"整条链。

【免费下载链接】pypdfA pure-python PDF library capable of splitting, merging, cropping, and transforming the pages of PDF files项目地址: https://gitcode.com/GitHub_Trending/py/pypdf

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询