推荐使用pypdf(pypdf2的现代维护分支)进行pdf拆分,它轻量稳定、支持新pdf特性;pdfplumber适合文本/表格提取等分析场景,纯拆页无需使用。

用 PyPDF2 或 pypdf(推荐)最直接可靠,pdfplumber 适合需要文本/布局分析的场景,但纯拆页没必要上它。
用 pypdf 拆页(替代已停更的 PyPDF2)
pypdf 是 PyPDF2 的现代维护分支,API 更稳定,支持新 PDF 特性,且默认启用严格模式防崩溃。
- 安装:
pip install pypdf - 核心逻辑是遍历
reader.pages,对每页新建PdfWriter并写入 - 注意页码从
0开始,文件名建议补零(如page_001.pdf),避免排序错乱 - 如果原 PDF 有加密,需先调用
reader.decrypt(password),否则读取会报NotImplementedError或空页
from pypdf import PdfReader, PdfWriter
reader = PdfReader("input.pdf")
for i, page in enumerate(reader.pages):
writer = PdfWriter()
writer.add_page(page)
with open(f"page_{i+1:03d}.pdf", "wb") as f:
writer.write(f)
处理大文件时的内存与性能问题
单页写入看似简单,但对百页以上 PDF,反复创建 PdfWriter 实例会触发多次对象初始化和 I/O,拖慢速度。
- 批量写入不可行——
PdfWriter不支持“只写一页”,必须构造完整文档 - 真正有效的优化是:提前读入全部页面对象(
reader.pages是 lazy-loaded,首次访问才解析),再并发写入(用concurrent.futures.ThreadPoolExecutor) - 但要注意:PDF 解析本身非线程安全,不能多线程共用同一个
reader;必须每个线程重新打开文件或复制PageObject - 更稳妥的做法是先用
reader.pages[i]提取所有PageObject到列表,再分发给线程写入
为什么不用 pdfplumber 拆页?
pdfplumber 主要用于提取文本、表格、坐标等,底层依赖 pdfminer.six,解析开销远高于 pypdf。强行用它拆页会:
- 多出 3–5 倍运行时间(尤其含图片或复杂字体的 PDF)
- 丢失原始 PDF 的元数据、书签、表单域等结构信息
- 遇到加密 PDF 时默认静默失败,不报错也不输出,容易误判为“拆成功了”
- 若真需要边拆边分析内容,应先用
pypdf拆页,再对单页 PDF 用pdfplumber处理
Windows 路径与中文文件名问题
在 Windows 上用中文路径或文件名时,open(..., "wb") 本身没问题,但常见坑在文件名生成环节:
- 不要用
os.path.join拼接含中文的路径后直接传给open——多数情况能工作,但某些旧 Python 版本或特定 locale 下会编码异常 - 更稳的方式:确保源 PDF 路径用
pathlib.Path处理,目标文件名用str()显式转义 - 如果遇到
UnicodeEncodeError,大概率是终端或 IDE 控制台编码不匹配,而非代码问题;可临时加sys.stdout.reconfigure(encoding='utf-8')(Python 3.7+)
拆页逻辑本身很简单,真正的复杂点藏在 PDF 的异构性里:加密方式、跨页流对象、损坏交叉引用表、非标准压缩……这些不会在小样例里暴露,但一到生产环境就卡住。建议加一层 try/except PdfReadError 捕获并跳过坏页,而不是让整个流程中断。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











