夜雨聆风学习资料网

ARTICLE · 1141871

PDF批量拆分,用Python 3分钟搞定,告别手工复制粘贴

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 page    python pdf_split.py ./待拆分 -o ./结果 -m size -n 10    python 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:            continue        if "-" 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:            continue        writer = 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 文件")        return    print(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 page
② 每 10 页拆一个
python pdf_split.py D:\待拆分 -o D:\结果 -m size -n 10
③ 按页码范围拆
python 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"))
剩下的,都是循环 + 批量 + 参数化的工程包装。

相关学习资料