Python 自动化之 PDF 合并拆分与格式转换——进阶实战
上一篇讲了 PDF 文字提取和表格处理,这篇讲 PDF 的进阶操作——合并、拆分、格式互转(PDF→Word、PDF→Excel)、批量压缩。
一、PDF 合并
把多个 PDF 合并成一个,适合用来汇总报告、合并扫描件。
批量合并整个文件夹
fromPyPDF2importPdfMergerimportosdefmerge_all_pdfs(input_dir,output_file):"""合并整个文件夹下的所有 PDF"""merger=PdfMerger()# 按文件名排序(保证合并顺序)files=sorted([fforfinos.listdir(input_dir)iff.lower().endswith(".pdf")])ifnotfiles:print("没有找到 PDF 文件")returnforfinfiles:filepath=os.path.join(input_dir,f)merger.append(filepath)print(f"已添加:{f}")merger.write(output_file)merger.close()print(f"合并完成!共{len(files)}个文件 →{output_file}")# 使用merge_all_pdfs("待合并的PDF","汇总结果.pdf")按指定顺序合并
defmerge_selected_pdfs(file_list,output_file):"""按指定顺序合并 PDF"""merger=PdfMerger()forfinfile_list:ifos.path.exists(f):merger.append(f)print(f"已添加:{os.path.basename(f)}")merger.write(output_file)merger.close()print(f"合并完成 →{output_file}")# 使用:顺序自定义merge_selected_pdfs(["封面.pdf","目录.pdf","正文.pdf","附录.pdf",],"完整报告.pdf")二、PDF 拆分
1. 按页数拆分(每 N 页一份)
fromPyPDF2importPdfReader,PdfWriterimportosdefsplit_by_pages(input_file,output_dir,pages_per_file=10):""" 按每 N 页一组拆分 PDF 适合:把几百页的 PDF 拆成多份小文件 """os.makedirs(output_dir,exist_ok=True)reader=PdfReader(input_file)total=len(reader.pages)file_index=1forstartinrange(0,total,pages_per_file):writer=PdfWriter()end=min(start+pages_per_file,total)foriinrange(start,end):writer.add_page(reader.pages[i])output=os.path.join(output_dir,f"第{file_index}部分_第{start+1}-{end}页.pdf")withopen(output,"wb")asf:writer.write(f)print(f"已生成:{os.path.basename(output)}({end-start}页)")file_index+=1print(f"拆分完成,共{file_index-1}个文件")# 使用:每 20 页拆一份split_by_pages("大文件.pdf","拆分输出",pages_per_file=20)2. 提取指定页面
defextract_pages(input_file,output_file,page_numbers):""" 提取 PDF 中的指定页码范围 page_numbers: 从 1 开始的页号列表,如 [1, 3, 5] 或 range(1, 6) """reader=PdfReader(input_file)writer=PdfWriter()foriinpage_numbers:# page_numbers 从 1 开始,reader 从 0 开始writer.add_page(reader.pages[i-1])withopen(output_file,"wb")asf:writer.write(f)print(f"已提取{len(page_numbers)}页 →{output_file}")# 使用extract_pages("报告.pdf","摘要.pdf",[1,2,3])# 提取前 3 页extract_pages("报告.pdf","附录.pdf",range(48,55))# 提取第 48-54 页三、PDF 转 Word
方法一:pdfplumber + python-docx(文字型 PDF)
importpdfplumberfromdocximportDocumentdefpdf_to_word(pdf_path,word_path):"""文字型 PDF 转 Word(保留文本)"""doc=Document()withpdfplumber.open(pdf_path)aspdf:forpageinpdf.pages:text=page.extract_text()iftext:doc.add_paragraph(text.strip())doc.save(word_path)print(f"转换完成:{word_path}")# 使用pdf_to_word("报告.pdf","报告.docx")方法二:pdf2docx(保留格式,推荐)
pipinstallpdf2docxfrompdf2docximportConverterdefpdf_to_word_with_format(pdf_path,word_path):"""PDF 转 Word(保留表格、排版)"""cv=Converter(pdf_path)cv.convert(word_path,start=0,end=None)cv.close()print(f"转换完成:{word_path}")# 使用pdf_to_word_with_format("报告.pdf","报告.docx")pdf2docx 的转换质量更高,能保留表格和基本排版。如果遇到表格多的 PDF,优先用这个。
四、PDF 转 Excel(提取表格)
importpdfplumberimportpandasaspddefpdf_tables_to_excel(pdf_path,excel_path):"""从 PDF 中提取所有表格并导出到 Excel"""withpdfplumber.open(pdf_path)aspdf:all_tables=[]forpage_num,pageinenumerate(pdf.pages,1):tables=page.extract_tables()fortable_idx,tableinenumerate(tables,1):# 第一行为表头df=pd.DataFrame(table[1:],columns=table[0]iftableelseNone)all_tables.append({"sheet_name":f"第{page_num}页_表格{table_idx}","data":df})print(f"第{page_num}页找到表格{table_idx},{len(table)}行×{len(table[0])}列")# 写入 Excel(每个表格一个 sheet)withpd.ExcelWriter(excel_path)aswriter:fortinall_tables:sheet=t["sheet_name"][:31]# Excel sheet 名最长 31 字符t["data"].to_excel(writer,sheet_name=sheet,index=False)print(f"导出完成,共{len(all_tables)}个表格 →{excel_path}")# 使用pdf_tables_to_excel("财务报表.pdf","财务报表数据.xlsx")五、PDF 压缩
pipinstallpypdffrompypdfimportPdfReader,PdfWriterdefcompress_pdf(input_path,output_path):"""压缩 PDF 文件大小"""reader=PdfReader(input_path)writer=PdfWriter()forpageinreader.pages:writer.add_page(page)# 压缩内容流forpageinwriter.pages:page.compress_content_streams()withopen(output_path,"wb")asf:writer.write(f)original_size=os.path.getsize(input_path)compressed_size=os.path.getsize(output_path)ratio=(1-compressed_size/original_size)*100print(f"压缩完成:{original_size//1024}KB →{compressed_size//1024}KB (压缩{ratio:.0f}%)")defbatch_compress(input_dir,output_dir):"""批量压缩 PDF"""os.makedirs(output_dir,exist_ok=True)forfinos.listdir(input_dir):ifnotf.lower().endswith(".pdf"):continueinput_path=os.path.join(input_dir,f)output_path=os.path.join(output_dir,f)compress_pdf(input_path,output_path)# 使用batch_compress("原始PDF","压缩后PDF")六、PDF 提取图片
importzipfileimportosfromPILimportImagedefextract_images_from_pdf(pdf_path,output_dir):"""从 PDF 中提取所有图片"""os.makedirs(output_dir,exist_ok=True)# PDF 本质上是 ZIP 文件,图片在 word/media 目录下withzipfile.ZipFile(pdf_path,"r")asz:image_count=0fornameinz.namelist():ifname.startswith("word/media/")orname.startswith("media/"):ext=os.path.splitext(name)[1].lower()ifextin(".png",".jpg",".jpeg",".gif",".tiff"):# 提取图片z.extract(name,output_dir)# 重命名到根目录src=os.path.join(output_dir,name)dst=os.path.join(output_dir,f"image_{image_count}{ext}")os.rename(src,dst)image_count+=1# 清理空目录forroot,dirs,filesinos.walk(output_dir,topdown=False):ifnotfilesandnotdirs:os.rmdir(root)print(f"提取完成,共{image_count}张图片 →{output_dir}")# 使用extract_images_from_pdf("带图片的文档.pdf","提取的图片")七、PDF 添加水印
fromPyPDF2importPdfReader,PdfWriterdefadd_watermark(input_pdf,watermark_pdf,output_pdf):"""给 PDF 每一页添加水印"""reader=PdfReader(input_pdf)watermark=PdfReader(watermark_pdf)watermark_page=watermark.pages[0]writer=PdfWriter()forpageinreader.pages:page.merge_page(watermark_page)writer.add_page(page)withopen(output_pdf,"wb")asf:writer.write(f)print(f"水印添加完成 →{output_pdf}")# 使用add_watermark("合同.pdf","水印.pdf","合同_带水印.pdf")八、批处理完整模板
importosfromPyPDF2importPdfReader,PdfWriter,PdfMergerclassPDFBatchProcessor:"""PDF 批量处理器"""def__init__(self,input_dir,output_dir):self.input_dir=input_dir self.output_dir=output_dir os.makedirs(output_dir,exist_ok=True)defget_pdf_files(self):"""获取所有 PDF 文件"""return[fforfinos.listdir(self.input_dir)iff.lower().endswith(".pdf")]defmerge_all(self,output="合并结果.pdf"):"""合并所有 PDF"""files=self.get_pdf_files()merger=PdfMerger()forfinsorted(files):merger.append(os.path.join(self.input_dir,f))merger.write(os.path.join(self.output_dir,output))merger.close()print(f"合并{len(files)}个文件 →{output}")defsplit_all(self,pages_per_file=10):"""批量拆分每个 PDF"""forfinself.get_pdf_files():input_path=os.path.join(self.input_dir,f)name=os.path.splitext(f)[0]sub_dir=os.path.join(self.output_dir,name)os.makedirs(sub_dir,exist_ok=True)reader=PdfReader(input_path)total=len(reader.pages)forstartinrange(0,total,pages_per_file):writer=PdfWriter()end=min(start+pages_per_file,total)foriinrange(start,end):writer.add_page(reader.pages[i])output=os.path.join(sub_dir,f"{name}_p{start+1}-{end}.pdf")withopen(output,"wb")asf_out:writer.write(f_out)print(f"{f}:{total}页 →{sub_dir}/")defrotate_all(self,rotation=90):"""批量旋转所有 PDF 页面"""forfinself.get_pdf_files():input_path=os.path.join(self.input_dir,f)output_path=os.path.join(self.output_dir,f"rotated_{f}")reader=PdfReader(input_path)writer=PdfWriter()forpageinreader.pages:page.rotate(rotation)writer.add_page(page)withopen(output_path,"wb")asf_out:writer.write(f_out)print(f"旋转完成:{f}")# 使用processor=PDFBatchProcessor("输入PDF","输出PDF")processor.merge_all()# 合并# processor.split_all(5) # 拆分(每5页一份)# processor.rotate_all(90) # 旋转(顺时针90度)总结
PDF 处理的常见需求基本都覆盖了:
合并 → PdfMerger.append() 拆分 → PdfWriter 按页提取 转Word → pdf2docx 转Excel → pdfplumber 提取表格 压缩 → pypdf compress_content_streams 水印 → merge_page() 提取图片 → zipfile 解压遇到批量处理时,把需要的功能组合成一个函数,一条命令搞定几百个 PDF。
💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。
