上一篇讲了 PDF 文字提取和表格处理这篇讲 PDF 的进阶操作——合并、拆分、格式互转PDF→Word、PDF→Excel、批量压缩。一、PDF 合并把多个 PDF 合并成一个适合用来汇总报告、合并扫描件。批量合并整个文件夹fromPyPDF2importPdfMergerimportosdefmerge_all_pdfs(input_dir,output_file):合并整个文件夹下的所有 PDFmergerPdfMerger()# 按文件名排序保证合并顺序filessorted([fforfinos.listdir(input_dir)iff.lower().endswith(.pdf)])ifnotfiles:print(没有找到 PDF 文件)returnforfinfiles:filepathos.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):按指定顺序合并 PDFmergerPdfMerger()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_file10): 按每 N 页一组拆分 PDF 适合把几百页的 PDF 拆成多份小文件 os.makedirs(output_dir,exist_okTrue)readerPdfReader(input_file)totallen(reader.pages)file_index1forstartinrange(0,total,pages_per_file):writerPdfWriter()endmin(startpages_per_file,total)foriinrange(start,end):writer.add_page(reader.pages[i])outputos.path.join(output_dir,f第{file_index}部分_第{start1}-{end}页.pdf)withopen(output,wb)asf:writer.write(f)print(f已生成:{os.path.basename(output)}({end-start}页))file_index1print(f拆分完成共{file_index-1}个文件)# 使用每 20 页拆一份split_by_pages(大文件.pdf,拆分输出,pages_per_file20)2. 提取指定页面defextract_pages(input_file,output_file,page_numbers): 提取 PDF 中的指定页码范围 page_numbers: 从 1 开始的页号列表如 [1, 3, 5] 或 range(1, 6) readerPdfReader(input_file)writerPdfWriter()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文字型 PDFimportpdfplumberfromdocximportDocumentdefpdf_to_word(pdf_path,word_path):文字型 PDF 转 Word保留文本docDocument()withpdfplumber.open(pdf_path)aspdf:forpageinpdf.pages:textpage.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保留表格、排版cvConverter(pdf_path)cv.convert(word_path,start0,endNone)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 中提取所有表格并导出到 Excelwithpdfplumber.open(pdf_path)aspdf:all_tables[]forpage_num,pageinenumerate(pdf.pages,1):tablespage.extract_tables()fortable_idx,tableinenumerate(tables,1):# 第一行为表头dfpd.DataFrame(table[1:],columnstable[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每个表格一个 sheetwithpd.ExcelWriter(excel_path)aswriter:fortinall_tables:sheett[sheet_name][:31]# Excel sheet 名最长 31 字符t[data].to_excel(writer,sheet_namesheet,indexFalse)print(f导出完成共{len(all_tables)}个表格 →{excel_path})# 使用pdf_tables_to_excel(财务报表.pdf,财务报表数据.xlsx)五、PDF 压缩pipinstallpypdffrompypdfimportPdfReader,PdfWriterdefcompress_pdf(input_path,output_path):压缩 PDF 文件大小readerPdfReader(input_path)writerPdfWriter()forpageinreader.pages:writer.add_page(page)# 压缩内容流forpageinwriter.pages:page.compress_content_streams()withopen(output_path,wb)asf:writer.write(f)original_sizeos.path.getsize(input_path)compressed_sizeos.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):批量压缩 PDFos.makedirs(output_dir,exist_okTrue)forfinos.listdir(input_dir):ifnotf.lower().endswith(.pdf):continueinput_pathos.path.join(input_dir,f)output_pathos.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_okTrue)# PDF 本质上是 ZIP 文件图片在 word/media 目录下withzipfile.ZipFile(pdf_path,r)asz:image_count0fornameinz.namelist():ifname.startswith(word/media/)orname.startswith(media/):extos.path.splitext(name)[1].lower()ifextin(.png,.jpg,.jpeg,.gif,.tiff):# 提取图片z.extract(name,output_dir)# 重命名到根目录srcos.path.join(output_dir,name)dstos.path.join(output_dir,fimage_{image_count}{ext})os.rename(src,dst)image_count1# 清理空目录forroot,dirs,filesinos.walk(output_dir,topdownFalse):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 每一页添加水印readerPdfReader(input_pdf)watermarkPdfReader(watermark_pdf)watermark_pagewatermark.pages[0]writerPdfWriter()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_dirinput_dir self.output_diroutput_dir os.makedirs(output_dir,exist_okTrue)defget_pdf_files(self):获取所有 PDF 文件return[fforfinos.listdir(self.input_dir)iff.lower().endswith(.pdf)]defmerge_all(self,output合并结果.pdf):合并所有 PDFfilesself.get_pdf_files()mergerPdfMerger()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_file10):批量拆分每个 PDFforfinself.get_pdf_files():input_pathos.path.join(self.input_dir,f)nameos.path.splitext(f)[0]sub_diros.path.join(self.output_dir,name)os.makedirs(sub_dir,exist_okTrue)readerPdfReader(input_path)totallen(reader.pages)forstartinrange(0,total,pages_per_file):writerPdfWriter()endmin(startpages_per_file,total)foriinrange(start,end):writer.add_page(reader.pages[i])outputos.path.join(sub_dir,f{name}_p{start1}-{end}.pdf)withopen(output,wb)asf_out:writer.write(f_out)print(f{f}:{total}页 →{sub_dir}/)defrotate_all(self,rotation90):批量旋转所有 PDF 页面forfinself.get_pdf_files():input_pathos.path.join(self.input_dir,f)output_pathos.path.join(self.output_dir,frotated_{f})readerPdfReader(input_path)writerPdfWriter()forpageinreader.pages:page.rotate(rotation)writer.add_page(page)withopen(output_path,wb)asf_out:writer.write(f_out)print(f旋转完成:{f})# 使用processorPDFBatchProcessor(输入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/爬虫 实战干货不让你白来。
Python 自动化之 PDF 合并拆分与格式转换——进阶实战
上一篇讲了 PDF 文字提取和表格处理这篇讲 PDF 的进阶操作——合并、拆分、格式互转PDF→Word、PDF→Excel、批量压缩。一、PDF 合并把多个 PDF 合并成一个适合用来汇总报告、合并扫描件。批量合并整个文件夹fromPyPDF2importPdfMergerimportosdefmerge_all_pdfs(input_dir,output_file):合并整个文件夹下的所有 PDFmergerPdfMerger()# 按文件名排序保证合并顺序filessorted([fforfinos.listdir(input_dir)iff.lower().endswith(.pdf)])ifnotfiles:print(没有找到 PDF 文件)returnforfinfiles:filepathos.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):按指定顺序合并 PDFmergerPdfMerger()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_file10): 按每 N 页一组拆分 PDF 适合把几百页的 PDF 拆成多份小文件 os.makedirs(output_dir,exist_okTrue)readerPdfReader(input_file)totallen(reader.pages)file_index1forstartinrange(0,total,pages_per_file):writerPdfWriter()endmin(startpages_per_file,total)foriinrange(start,end):writer.add_page(reader.pages[i])outputos.path.join(output_dir,f第{file_index}部分_第{start1}-{end}页.pdf)withopen(output,wb)asf:writer.write(f)print(f已生成:{os.path.basename(output)}({end-start}页))file_index1print(f拆分完成共{file_index-1}个文件)# 使用每 20 页拆一份split_by_pages(大文件.pdf,拆分输出,pages_per_file20)2. 提取指定页面defextract_pages(input_file,output_file,page_numbers): 提取 PDF 中的指定页码范围 page_numbers: 从 1 开始的页号列表如 [1, 3, 5] 或 range(1, 6) readerPdfReader(input_file)writerPdfWriter()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文字型 PDFimportpdfplumberfromdocximportDocumentdefpdf_to_word(pdf_path,word_path):文字型 PDF 转 Word保留文本docDocument()withpdfplumber.open(pdf_path)aspdf:forpageinpdf.pages:textpage.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保留表格、排版cvConverter(pdf_path)cv.convert(word_path,start0,endNone)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 中提取所有表格并导出到 Excelwithpdfplumber.open(pdf_path)aspdf:all_tables[]forpage_num,pageinenumerate(pdf.pages,1):tablespage.extract_tables()fortable_idx,tableinenumerate(tables,1):# 第一行为表头dfpd.DataFrame(table[1:],columnstable[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每个表格一个 sheetwithpd.ExcelWriter(excel_path)aswriter:fortinall_tables:sheett[sheet_name][:31]# Excel sheet 名最长 31 字符t[data].to_excel(writer,sheet_namesheet,indexFalse)print(f导出完成共{len(all_tables)}个表格 →{excel_path})# 使用pdf_tables_to_excel(财务报表.pdf,财务报表数据.xlsx)五、PDF 压缩pipinstallpypdffrompypdfimportPdfReader,PdfWriterdefcompress_pdf(input_path,output_path):压缩 PDF 文件大小readerPdfReader(input_path)writerPdfWriter()forpageinreader.pages:writer.add_page(page)# 压缩内容流forpageinwriter.pages:page.compress_content_streams()withopen(output_path,wb)asf:writer.write(f)original_sizeos.path.getsize(input_path)compressed_sizeos.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):批量压缩 PDFos.makedirs(output_dir,exist_okTrue)forfinos.listdir(input_dir):ifnotf.lower().endswith(.pdf):continueinput_pathos.path.join(input_dir,f)output_pathos.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_okTrue)# PDF 本质上是 ZIP 文件图片在 word/media 目录下withzipfile.ZipFile(pdf_path,r)asz:image_count0fornameinz.namelist():ifname.startswith(word/media/)orname.startswith(media/):extos.path.splitext(name)[1].lower()ifextin(.png,.jpg,.jpeg,.gif,.tiff):# 提取图片z.extract(name,output_dir)# 重命名到根目录srcos.path.join(output_dir,name)dstos.path.join(output_dir,fimage_{image_count}{ext})os.rename(src,dst)image_count1# 清理空目录forroot,dirs,filesinos.walk(output_dir,topdownFalse):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 每一页添加水印readerPdfReader(input_pdf)watermarkPdfReader(watermark_pdf)watermark_pagewatermark.pages[0]writerPdfWriter()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_dirinput_dir self.output_diroutput_dir os.makedirs(output_dir,exist_okTrue)defget_pdf_files(self):获取所有 PDF 文件return[fforfinos.listdir(self.input_dir)iff.lower().endswith(.pdf)]defmerge_all(self,output合并结果.pdf):合并所有 PDFfilesself.get_pdf_files()mergerPdfMerger()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_file10):批量拆分每个 PDFforfinself.get_pdf_files():input_pathos.path.join(self.input_dir,f)nameos.path.splitext(f)[0]sub_diros.path.join(self.output_dir,name)os.makedirs(sub_dir,exist_okTrue)readerPdfReader(input_path)totallen(reader.pages)forstartinrange(0,total,pages_per_file):writerPdfWriter()endmin(startpages_per_file,total)foriinrange(start,end):writer.add_page(reader.pages[i])outputos.path.join(sub_dir,f{name}_p{start1}-{end}.pdf)withopen(output,wb)asf_out:writer.write(f_out)print(f{f}:{total}页 →{sub_dir}/)defrotate_all(self,rotation90):批量旋转所有 PDF 页面forfinself.get_pdf_files():input_pathos.path.join(self.input_dir,f)output_pathos.path.join(self.output_dir,frotated_{f})readerPdfReader(input_path)writerPdfWriter()forpageinreader.pages:page.rotate(rotation)writer.add_page(page)withopen(output_path,wb)asf_out:writer.write(f_out)print(f旋转完成:{f})# 使用processorPDFBatchProcessor(输入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/爬虫 实战干货不让你白来。