PyPDF2.PdfMerger合并PDF出错的根本原因有四:路径未排序致顺序错乱;封面页重复插入;4.0+版本API变更要求显式传fileobj;字体不嵌入致中文乱码;大文件内存爆满。

PyPDF2.PdfMerger 合并 PDF 时空白页或顺序错乱
根本原因是 PdfMerger.append() 默认按文件系统读取顺序添加,但实际传入路径列表若未显式排序,容易因文件名数字未补零(如 "page1.pdf"、"page10.pdf")导致字典序错位;另外,某些 PDF 的第一页含封面/元数据,直接追加会把封面重复塞进中间。
- 用
sorted()对路径预处理,必要时用re.findall(r'\d+', name)提取数字再排序 - 避免直接传
glob.glob("*.pdf"),改用sorted(glob.glob("*.pdf"), key=lambda x: int(re.search(r'(\d+)', x).group(1))) - 如果源 PDF 有封面且只需合并内容页,用
reader = PdfReader(f); merger.append(fileobj=reader, pages=(1, None))跳过第 0 页
PyPDF2 4.0+ 版本中 PdfMerger.append() 报错 AttributeError: 'PdfMerger' object has no attribute '_pages'
这是 PyPDF2 从 3.x 升级到 4.0 后的内部结构变更:旧写法 merger.append(pdf_path) 在 4.0+ 中必须显式指定 fileobj 参数,否则触发属性访问失败。
- 正确写法是
merger.append(fileobj=PdfReader(pdf_path)),不能省略fileobj= - 若需保留页码书签,加参数
import_outline=True(默认为True,但显式写出更稳妥) - PyPDF2 4.0+ 不再支持直接传字符串路径,传错会报这个错,不是环境问题,是 API 改动
合并后中文乱码或字体丢失
PyPDF2 不嵌入字体,只复制原始 PDF 的字体引用。如果源 PDF 使用了非标准字体(比如 Windows 的“微软雅黑”或 macOS 的“PingFang SC”),而目标阅读器没装对应字体,就会 fallback 到缺省字体,显示方块或英文。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 这不是 PyPDF2 的 bug,是 PDF 规范限制——它不处理字体渲染,只做对象拼接
- 临时缓解:用
pdftoppm或pdf2image转成图片再合成,但丧失文本可选性 - 真正解法:用
reportlab+PyPDF2拆出文本重排,或换pypdf(PyPDF2 的继任者,对字体引用处理稍好,但仍不嵌入)
大文件合并卡死或内存爆满
PyPDF2 把整个 PDF 解析进内存,每个 100MB 的 PDF 可能占用 500MB+ 内存,合并 10 个就超 5GB。尤其当 PDF 含大量图像或图层时,PdfReader 初始化阶段就卡住。
立即学习“Python免费学习笔记(深入)”;
- 用
fitz.open()(即PyMuPDF)替代,它流式读取,内存占用低一个数量级 - 如果坚持用 PyPDF2,先用
pdfsizeopt或ghostscript压缩源文件:gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook -dNOPAUSE -dQUIET -dBATCH -sOutputFile=small.pdf input.pdf - 别在循环里反复创建
PdfReader实例,复用 reader 对象,减少解析开销
真正麻烦的是跨平台字体和大文件内存控制——这两个点不提前压测,上线后才发现,基本就得重写流程。


















