Python 合并 PDF 文件(批量处理方法)

简介: 周一邮件堆成山?PDF合并总被收费、限页、传服务器?用Python+PyPDF2,5行代码批量合并PDF,免费、离线、无水印!支持自定义顺序、选页、加书签、处理加密/扫描件,还能打包成双击即用的exe——告别工具焦虑,三秒搞定。

周一早上九点,你的邮箱里躺着十几封邮件,每封都带了一个PDF附件——上周会议的签到表、各小组的报告、财务的报销凭证。领导在微信群里发了一条消息:“把这些文件合并成一个,发到公司群里。”

你打开第一个PDF,又打开第二个,鼠标拖来拖去,发现Adobe Acrobat弹出一个窗口:“您的试用期已结束。”同事推荐了在线合并工具,你上传完所有文件,等待进度条走到100%,页面弹出五个字:“请付费解锁。”
代理 IP 使用小技巧 让你的数据抓取效率翻倍 (27).png

这不是你的错。PDF合并这件事看起来简单,真上手才发现处处是坑。在线工具要么限制页数,要么加水印,要么悄悄把你的文件传到不明服务器。桌面软件不是收费就是臃肿得像个航空母舰。

你需要的其实很简单:一个能批量处理、不用花钱、跑起来就完事的工具。Python刚好能做到,而且代码少到你不用是程序员也能看懂。

先把你需要的工具装好
Python合并PDF这件事,全靠一个叫PyPDF2的库。它专门用来处理PDF,能读、能写、能合并、能拆分。

安装就一行命令:

pip install PyPDF2

如果你用的是Python 3,可能需要安装PyPDF2的升级版PyPDF4,用法几乎一样。这里用PyPDF2演示,兼容性最好。

装完之后,打开你的代码编辑器,新建一个Python文件,就叫merge_pdf.py。

最简单的合并:把所有PDF放在一起
假设你的桌面上有一个文件夹叫“待合并”,里面放了三个PDF文件:报告1.pdf、报告2.pdf、报告3.pdf。你想把它们按顺序拼成一个总报告。

代码长这样:

import PyPDF2
import os

创建一个空的PDF写入器

merger = PyPDF2.PdfMerger()

定义文件夹路径

folder_path = r"C:\Users\你的用户名\Desktop\待合并"

获取文件夹里所有PDF文件,并按文件名排序

pdf_files = [f for f in os.listdir(folder_path) if f.endswith('.pdf')]
pdf_files.sort()

逐个添加到合并器

for pdf in pdf_files:
full_path = os.path.join(folder_path, pdf)
merger.append(full_path)

写出合并后的文件

output_path = os.path.join(folder_path, "合并结果.pdf")
merger.write(output_path)
merger.close()

print(f"合并完成,文件保存在:{output_path}")

跑完这段代码,你会发现“待合并”文件夹里多了一个“合并结果.pdf”,里面按顺序包含了所有文件的内容。

这段代码的逻辑很简单:PyPDF2.PdfMerger()创建了一个空容器,相当于一张白纸。append()方法把每个PDF一页一页地贴上去,就像在打印机上叠放纸张。最后write()把结果存下来。

文件顺序乱了怎么办
上面的代码用了sort()来排序,但这只能保证按字母顺序排列。如果文件名是“报告1”、“报告10”、“报告2”,sort()会把“报告10”排在“报告2”前面,因为字符串比较是一个字符一个字符来的。

解决办法有两种。

第一种,给文件命名的时候用数字编号,比如001报告、002报告。这样排序就是按数字顺序,不会乱。

第二种,自己指定顺序:

手动指定顺序

pdf_files = ["签到表.pdf", "小组报告.pdf", "财务凭证.pdf"]

for pdf in pdf_files:
full_path = os.path.join(folder_path, pdf)
if os.path.exists(full_path):
merger.append(full_path)
else:
print(f"警告:找不到文件 {pdf}")

加一个判断,文件不存在的时候跳过并给出提示,防止程序崩溃。

只合并某些页面
有时候你不需要合并整个PDF,只需要其中的几页。比如一个20页的报告,你只要第3到第7页。

PyPDF2允许指定页码范围:

只合并第3到第7页(页码从0开始)

merger.append("报告.pdf", pages=(2, 7))

这里的pages参数接收一个元组,第一个数字是起始页(从0开始),第二个数字是结束页(不包含这一页)。所以(2, 7)表示第3页到第7页,一共5页。

如果你想单独挑几页,可以用另一种方式:

先读取文件

reader = PyPDF2.PdfReader("报告.pdf")

只取第1页、第3页、第5页

pages_to_take = [0, 2, 4]
for page_num in pages_to_take:
merger.append(reader.pages[page_num])

这种方式灵活度更高,你想怎么组合都行。

处理子文件夹里的PDF
真实的场景往往更复杂。你的文件可能分散在不同的子文件夹里:财务组一个文件夹、技术组一个文件夹、销售组一个文件夹。你想把这些文件夹里的所有PDF都合并到一起。

这时候需要用os.walk来遍历文件夹树:

import PyPDF2
import os

merger = PyPDF2.PdfMerger()
root_folder = r"C:\Users\你的用户名\Desktop\各部门报告"

遍历所有子文件夹

for folder_path, subfolders, files in os.walk(root_folder):
for file in files:
if file.endswith('.pdf'):
full_path = os.path.join(folder_path, file)
merger.append(full_path)
print(f"已添加:{full_path}")

merger.write(os.path.join(root_folder, "全部合并.pdf"))
merger.close()

这段代码会从根文件夹开始,一层一层往下找,把所有子文件夹里的PDF都翻出来合并。注意一个问题:这样合并的顺序是按os.walk的遍历顺序来的,不是按文件夹名字排序。如果你需要控制顺序,可以在添加之前先收集所有文件路径,排序之后再添加。

加上书签和目录
合并后的PDF如果页数太多,翻起来很痛苦。加上书签会友好很多。

你可以把每个文件的文件名作为书签插入:

merger = PyPDF2.PdfMerger()

for pdf in pdf_files:

# 记录当前总页数,作为书签的起始位置
merger.append(pdf)
# 获取文件名(不含扩展名)作为书签名称
bookmark_name = os.path.splitext(pdf)[0]
# 在最后添加的书签位置插入书签
# 这里需要先获取当前总页数,PyPDF2的add_bookmark方法需要知道页码

PyPDF2添加书签的API稍微有点绕。更简单的方式是换一个库——pypdf(PyPDF2的现代替代品),它的书签功能更直观。

安装pypdf:

pip install pypdf

然后用pypdf合并并添加书签:

from pypdf import PdfWriter, PdfReader

writer = PdfWriter()

for pdf in pdf_files:
reader = PdfReader(pdf)

# 记录添加之前的页数
start_page = len(writer.pages)
# 添加所有页面
for page in reader.pages:
    writer.add_page(page)
# 添加书签,指向这个文件的第一页
bookmark_name = os.path.splitext(pdf)[0]
writer.add_outline_item(bookmark_name, start_page)

with open("带书签的合并文件.pdf", "wb") as f:
writer.write(f)

这样生成的PDF,左侧书签栏里会列出每个原文件的文件名,点击就能跳转到对应位置。

处理加密的PDF
有些PDF设置了打开密码,直接合并会报错。如果你知道密码,可以在读取时解密:

reader = PyPDF2.PdfReader("加密文件.pdf")
if reader.is_encrypted:
reader.decrypt("你的密码")

然后把reader的页面添加到merger里。

如果密码不知道,那基本无解。PDF的加密算法是工业级的,暴力破解不现实。你需要先找文件提供方要密码,或者用专门工具移除密码——但移除密码也需要先输入密码。

大文件合并时的内存问题
合并几十个PDF、几百页文件,PyPDF2跑起来很快。但如果合并上千页的大文件,或者一次合并上百个PDF,可能会遇到内存不足。

PyPDF2是把所有内容加载到内存里再写入的。解决方案是用pypdf的增量写入模式,或者换用PDFtk这个命令行工具——它在底层是用C++实现的,处理大文件比Python高效得多。

如果你坚持用Python,可以这样优化:分批次合并,先合并成几个中间文件,再把中间文件合并成最终结果。

先每10个文件合并成一个临时文件

batch_size = 10
temp_files = []

for i in range(0, len(pdf_files), batch_size):
batch = pdf_files[i:i+batch_size]
temp_writer = PyPDF2.PdfMerger()
for pdf in batch:
temp_writer.append(os.path.join(folder_path, pdf))
tempname = f"temp{i}.pdf"
temp_writer.write(temp_name)
temp_writer.close()
temp_files.append(temp_name)

再合并所有临时文件

final_merger = PyPDF2.PdfMerger()
for temp in temp_files:
final_merger.append(temp)
final_merger.write("最终合并.pdf")
final_merger.close()

清理临时文件

import os
for temp in temp_files:
os.remove(temp)

这种分段合并的方式,内存占用会小很多。

给代码加一个图形界面
代码写好了,但每次运行都要改文件夹路径,同事想用又不会Python。这时候可以加一个简单的图形界面,用tkinter(Python自带的GUI库)实现。

import tkinter as tk
from tkinter import filedialog, messagebox
import PyPDF2
import os

def merge_pdfs():

# 让用户选择文件夹
folder = filedialog.askdirectory()
if not folder:
    return

# 获取所有PDF文件
pdf_files = [f for f in os.listdir(folder) if f.lower().endswith('.pdf')]
if not pdf_files:
    messagebox.showwarning("提示", "该文件夹中没有PDF文件")
    return

pdf_files.sort()

# 合并
merger = PyPDF2.PdfMerger()
for pdf in pdf_files:
    full_path = os.path.join(folder, pdf)
    merger.append(full_path)

output_path = os.path.join(folder, "合并结果.pdf")
merger.write(output_path)
merger.close()

messagebox.showinfo("完成", f"合并完成!\n文件保存在:{output_path}")

创建窗口

root = tk.Tk()
root.title("PDF合并工具")
root.geometry("300x150")

btn = tk.Button(root, text="选择文件夹并合并PDF", command=merge_pdfs, height=3, width=25)
btn.pack(expand=True)

root.mainloop()

保存为pdf_merger_gui.py,双击运行,会弹出一个窗口,点按钮选择文件夹,剩下的交给程序。你的同事双击就能用,不需要安装Python环境吗?还是需要的——不过你可以用pyinstaller打包成一个exe文件,发给谁都能用。

处理扫描件和图片型PDF
有一种PDF比较特殊:里面不是文字,而是扫描的图片。这类PDF合并的时候,上面所有方法都适用,因为PyPDF2处理的是页面对象,不管里面是文字还是图片。

但合并之后可能会遇到一个问题——文件特别大。图片型PDF本来就大,合并之后更大。如果需要压缩,可以用另外的库,比如pypdf的压缩功能,或者用img2pdf重新生成。

简单压缩的方法:

from pypdf import PdfWriter, PdfReader

reader = PdfReader("大文件.pdf")
writer = PdfWriter()

for page in reader.pages:

# 压缩页面内容
page.compress_content_streams()
writer.add_page(page)

with open("压缩后.pdf", "wb") as f:
writer.write(f)

这个压缩力度有限,但聊胜于无。真正想大幅压缩图片型PDF,需要用OCR或专门的PDF压缩工具。

遇到报错怎么办
合并过程中最常见的报错是“PdfReadError: EOF marker not found”。意思是PDF文件可能损坏或不完整。解决办法是在append之前先验证文件是否能正常读取:

def is_valid_pdf(filepath):
try:
with open(filepath, 'rb') as f:
reader = PyPDF2.PdfReader(f)

        # 尝试获取页数,如果出错说明文件有问题
        _ = len(reader.pages)
    return True
except:
    return False

只添加有效的PDF

for pdf in pdf_files:
full_path = os.path.join(folder_path, pdf)
if is_valid_pdf(full_path):
merger.append(full_path)
else:
print(f"跳过无效文件:{pdf}")

另一个常见报错是“Permission denied”,表示文件被其他程序打开(比如你在Adobe Acrobat里正看着这个文件)。关掉文件再运行一次就行。

把合并过程写成日志
如果你要合并的文件很多,想记录哪些成功了、哪些失败了,可以加一个日志功能:

import logging

logging.basicConfig(filename='merge_log.txt', level=logging.INFO,
format='%(asctime)s - %(message)s')

for pdf in pdf_files:
try:
full_path = os.path.join(folder_path, pdf)
merger.append(full_path)
logging.info(f"成功添加:{pdf}")
except Exception as e:
logging.error(f"添加失败:{pdf},错误信息:{str(e)}")

跑完之后打开merge_log.txt,一目了然。

回到那个周一的早晨
现在你手头有了一段能用的Python代码。你双击运行,三秒钟之后,“合并结果.pdf”出现在文件夹里。你把它发到群里,领导回了一个大拇指。

更重要的是,下次再有同事遇到同样的问题,你不用再解释“你试试那个在线工具、注意不要点广告、合并完记得检查顺序”——直接把代码扔过去,或者打包成exe发给他。

PDF合并这件事,Python帮你做了一次性投入、无限次复用的自动化。那些浪费在下载软件、比较付费方案、担心文件泄露上的时间,都可以省下来了。

目录
相关文章
|
2天前
|
人工智能 JSON 机器人
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
本文带你零成本玩转OpenClaw:学生认证白嫖6个月阿里云服务器,手把手配置飞书机器人、接入免费/高性价比AI模型(NVIDIA/通义),并打造微信公众号“全自动分身”——实时抓热榜、AI选题拆解、一键发布草稿,5分钟完成热点→文章全流程!
10251 35
让龙虾成为你的“公众号分身” | 阿里云服务器玩Openclaw
|
14天前
|
人工智能 安全 Linux
【OpenClaw保姆级图文教程】阿里云/本地部署集成模型Ollama/Qwen3.5/百炼 API 步骤流程及避坑指南
2026年,AI代理工具的部署逻辑已从“单一云端依赖”转向“云端+本地双轨模式”。OpenClaw(曾用名Clawdbot)作为开源AI代理框架,既支持对接阿里云百炼等云端免费API,也能通过Ollama部署本地大模型,完美解决两类核心需求:一是担心云端API泄露核心数据的隐私安全诉求;二是频繁调用导致token消耗过高的成本控制需求。
5938 14
|
22天前
|
人工智能 JavaScript Ubuntu
5分钟上手龙虾AI!OpenClaw部署(阿里云+本地)+ 免费多模型配置保姆级教程(MiniMax、Claude、阿里云百炼)
OpenClaw(昵称“龙虾AI”)作为2026年热门的开源个人AI助手,由PSPDFKit创始人Peter Steinberger开发,核心优势在于“真正执行任务”——不仅能聊天互动,还能自动处理邮件、管理日程、订机票、写代码等,且所有数据本地处理,隐私完全可控。它支持接入MiniMax、Claude、GPT等多类大模型,兼容微信、Telegram、飞书等主流聊天工具,搭配100+可扩展技能,成为兼顾实用性与隐私性的AI工具首选。
23212 120
|
8天前
|
人工智能 JavaScript API
解放双手!OpenClaw Agent Browser全攻略(阿里云+本地部署+免费API+网页自动化场景落地)
“让AI聊聊天、写代码不难,难的是让它自己打开网页、填表单、查数据”——2026年,无数OpenClaw用户被这个痛点困扰。参考文章直击核心:当AI只能“纸上谈兵”,无法实际操控浏览器,就永远成不了真正的“数字员工”。而Agent Browser技能的出现,彻底打破了这一壁垒——它给OpenClaw装上“上网的手和眼睛”,让AI能像真人一样打开网页、点击按钮、填写表单、提取数据,24小时不间断完成网页自动化任务。
1956 4

热门文章

最新文章