ARTICLE · 1141871
PDF批量拆分,用Python 3分钟搞定,告别手工复制粘贴
200页的扫描件要拆成单页、一份合同要按章节拆开、几千页的汇编要每10页打包一次……手工干?那是折磨自己。
一、先说痛点
做行政、财务、法务、教培的朋友,大概都遇到过这种活:
一本 300 页的扫描版教材,要拆成 300 个单页 PDF 上传系统;
一份 投标文件,要按"1-5页 / 6-20页 / 21-30页"拆成几个部分发给不同的人;
一堆 电子发票 合在一个 PDF 里,要按每张一页拆出来报销;
客户发来 几十个 PDF,每个都要按同样规则拆……
用 Adobe 手动拆?一个文件点几十次,眼睛都花了,还容易错。
其实用 Python,20 行代码就能解决,而且能批量处理整个文件夹。
二、准备工作:只要 1 个库
打开命令行,装一个库就行:
pip install pypdf小提示:老教程里的
PyPDF2已经停止维护,官方把它升级成了pypdf,接口几乎一样,直接用新的即可。
三、核心原理:20 行代码看懂拆分
拆 PDF 的本质就三步:读进来 → 取页面 → 写出去。
from pypdf import PdfReader, PdfWriterreader = PdfReader("原始文件.pdf")writer = PdfWriter()# 取第 1 页(注意索引从 0 开始)writer.add_page(reader.pages[0])with open("拆分结果.pdf", "wb") as f:writer.write(f)
就这么简单。把"取第 1 页"换成循环,就是批量拆分了。
四、完整版:支持 3 种拆分模式 + 批量处理
下面这份代码可以直接复制使用,支持:
| 模式 | 说明 | 适用场景 |
|---|---|---|
page | 每页拆成一个 PDF | 扫描件、发票、试卷 |
size | 每 N 页拆成一个 PDF | 按固定页数打包 |
range | 按指定页码范围拆 | 按章节、按合同条款 |
# -*- coding: utf-8 -*-"""PDF 批量拆分工具依赖:pip install pypdf用法示例:python pdf_split.py ./待拆分 -o ./结果 -m pagepython pdf_split.py ./待拆分 -o ./结果 -m size -n 10python pdf_split.py ./待拆分 -o ./结果 -m range -r "1-5,6-10,11-20""""import osimport argparsefrom pypdf import PdfReader, PdfWriterdef ensure_dir(path):if not os.path.exists(path):os.makedirs(path)def open_reader(pdf_path):"""打开 PDF,自动尝试用空密码解密"""reader = PdfReader(pdf_path)if reader.is_encrypted:try:reader.decrypt("")except Exception:raise RuntimeError("文件已加密,需要密码才能处理")return readerdef split_by_page(pdf_path, out_dir):"""每页拆成一个文件"""reader = open_reader(pdf_path)base = os.path.splitext(os.path.basename(pdf_path))[0]files = []for i, page in enumerate(reader.pages, start=1):writer = PdfWriter()writer.add_page(page)out = os.path.join(out_dir, f"{base}_第{i}页.pdf")with open(out, "wb") as f:writer.write(f)files.append(out)return filesdef split_by_size(pdf_path, out_dir, pages_per_file=10):"""每 N 页拆成一个文件"""reader = open_reader(pdf_path)base = os.path.splitext(os.path.basename(pdf_path))[0]total = len(reader.pages)files = []for start in range(0, total, pages_per_file):end = min(start + pages_per_file, total)writer = PdfWriter()for i in range(start, end):writer.add_page(reader.pages[i])out = os.path.join(out_dir, f"{base}_{start + 1}-{end}页.pdf")with open(out, "wb") as f:writer.write(f)files.append(out)return filesdef split_by_ranges(pdf_path, out_dir, ranges):"""按指定页码范围拆,ranges 形如 '1-5,6-10,11'"""reader = open_reader(pdf_path)base = os.path.splitext(os.path.basename(pdf_path))[0]total = len(reader.pages)files = []for seg in ranges.split(","):seg = seg.strip()if not seg:continueif "-" in seg:a, b = seg.split("-", 1)start, end = int(a), int(b)else:start = end = int(seg)# 越界保护start = max(1, start)end = min(total, end)if start > end:continuewriter = PdfWriter()for i in range(start - 1, end):writer.add_page(reader.pages[i])name = f"{base}_{start}页.pdf" if start == end else f"{base}_{start}-{end}页.pdf"out = os.path.join(out_dir, name)with open(out, "wb") as f:writer.write(f)files.append(out)return filesdef batch_split(input_dir, output_dir, mode="page", pages_per_file=10, ranges=""):ensure_dir(output_dir)pdfs = [f for f in os.listdir(input_dir) if f.lower().endswith(".pdf")]if not pdfs:print("目录里没有找到 PDF 文件")returnprint(f"共发现 {len(pdfs)} 个 PDF,开始处理...\n")for idx, name in enumerate(pdfs, 1):path = os.path.join(input_dir, name)sub_dir = os.path.join(output_dir, os.path.splitext(name)[0])ensure_dir(sub_dir)try:if mode == "page":files = split_by_page(path, sub_dir)elif mode == "size":files = split_by_size(path, sub_dir, pages_per_file)else:files = split_by_ranges(path, sub_dir, ranges)print(f"[{idx}/{len(pdfs)}] {name} → 拆出 {len(files)} 个文件")except Exception as e:print(f"[{idx}/{len(pdfs)}] {name} 处理失败:{e}")print("\n全部完成!")if __name__ == "__main__":parser = argparse.ArgumentParser(description="PDF 批量拆分工具")parser.add_argument("input_dir", help="存放 PDF 的文件夹")parser.add_argument("-o", "--output", default="output", help="输出文件夹,默认 output")parser.add_argument("-m", "--mode", default="page",choices=["page", "size", "range"],help="page=每页一个 / size=每N页一个 / range=按页码范围")parser.add_argument("-n", "--num", type=int, default=10, help="size 模式下每个文件的页数")parser.add_argument("-r", "--ranges", default="", help='range 模式,如 "1-5,6-10"')args = parser.parse_args()batch_split(args.input_dir, args.output, args.mode, args.num, args.ranges)
五、怎么用?三个命令搞定
把代码保存为 pdf_split.py,把要拆的 PDF 全丢进一个文件夹,比如 D:\待拆分。
① 每页拆一个(最常用)
python pdf_split.py D:\待拆分 -o D:\结果 -m pagepython pdf_split.py D:\待拆分 -o D:\结果 -m size -n 10python pdf_split.py D:\待拆分 -o D:\结果 -m range -r "1-5,6-20,21-50"共发现 3 个 PDF,开始处理...[1/3] 合同A.pdf → 拆出 24 个文件[2/3] 教材B.pdf → 拆出 186 个文件[3/3] 发票C.pdf → 拆出 12 个文件全部完成!
每个源文件会对应一个独立的子文件夹,结果整整齐齐。
六、进阶:打包成 exe,同事也能用
你不可能要求同事都装 Python。用 pyinstaller 打包一下:
pip install pyinstallerpyinstaller -F pdf_split.py
生成的 dist/pdf_split.exe 直接发给别人,双击命令行就能用。甚至可以让同事把 PDF 拖到 exe 上——不过拖拽需要额外处理参数,最简单的还是让他们在文件夹地址栏敲 cmd 然后粘贴命令。
七、几个容易踩的坑
1. 页码从 1 开始还是从 0 开始?pypdf 里 reader.pages[0] 是第 1 页。上面代码在输出文件名时做了 +1,所以你看到的"第 1 页"就是真实的第 1 页。
2. 加密 PDF 拆不了?
如果 PDF 设了打开密码,pypdf 会报错。上面代码里 decrypt("") 只能处理"空密码加密"(有些系统导出的 PDF 会这样)。真有密码的话,得先解密:把 decrypt("") 换成 decrypt("你的密码")。
3. 输出目录别和输入目录一样
否则第二次运行会把上次拆出来的文件也当成待处理文件,越拆越多。
4. 拆分会不会损失画质?
不会。PDF 拆分只是把页面对象重新组织,不重新压缩、不重新渲染,原图原字一模一样。
5. 拆分能减小文件体积吗?
通常能。如果原文件里有一份共享的字体、图片资源,拆开后每个小文件都得各存一份,反而可能变大。反之如果页面内容彼此独立,拆分后总体积会明显下降。
八、一句话总结
PDF 拆分的核心就三行:
reader = PdfReader("in.pdf")writer.add_page(reader.pages[0])writer.write(open("out.pdf", "wb"))