
之前讲了很多 PDF 的基础操作这次用两个完整的实战案例把知识串起来——批量处理 PDF 合同和批量提取发票信息。一、实战案例一批量生成 PDF 合同把 Excel 里的客户数据批量生成合同 PDF这是办公自动化里最高频的需求。1. 准备数据importpandasaspd# 模拟客户数据data{客户编号:[KH001,KH002,KH003],客户名称:[北京科技有限公司,上海信息有限公司,广州贸易有限公司],合同金额:[150000,98000,210000],签订日期:[2026-07-01,2026-07-05,2026-07-10],项目内容:[数据分析系统开发,爬虫数据采集服务,可视化平台搭建],}dfpd.DataFrame(data)df.to_excel(客户数据.xlsx,indexFalse)2. 安装依赖pipinstallpython-docx docx2pdf# 先生成 Word再转 PDF3. 生成合同fromdocximportDocumentfromdocx.sharedimportPt,Cm,Inches,RGBColorfromdocx.enum.textimportWD_ALIGN_PARAGRAPHimportpandasaspdfromdatetimeimportdatetimeimportosclassContractGenerator:合同批量生成器def__init__(self,template_path):self.template_pathtemplate_pathdefgenerate_contract(self,customer):为单个客户生成合同docDocument(self.template_path)# 替换占位符replacements{{{客户编号}}:customer[客户编号],{{客户名称}}:customer[客户名称],{{合同金额}}:f{customer[合同金额]:,.0f},{{大写金额}}:self._num_to_cn(customer[合同金额]),{{签订日期}}:customer[签订日期],{{项目内容}}:customer[项目内容],}forpindoc.paragraphs:forkey,valinreplacements.items():ifkeyinp.text:forruninp.runs:ifkeyinrun.text:run.textrun.text.replace(key,val)# 保存filenamef合同_{customer[客户编号]}_{customer[客户名称]}.docxfilepathos.path.join(生成合同,filename)os.makedirs(生成合同,exist_okTrue)doc.save(filepath)returnfilepathdef_num_to_cn(self,num):金额转大写简化版c_num零壹贰叁肆伍陆柒捌玖c_unit分角元拾佰仟万拾佰仟亿# 实际项目需要完善的大写金额转换returnf{num}元整defbatch_generate(self,excel_path):批量生成dfpd.read_excel(excel_path)files[]for_,rowindf.iterrows():pathself.generate_contract(row)files.append(path)print(f已生成:{os.path.basename(path)})returnfiles# 使用generatorContractGenerator(合同模板.docx)filesgenerator.batch_generate(客户数据.xlsx)4. Word 转 PDFfromdocx2pdfimportconvertdefbatch_docx_to_pdf(docx_dir生成合同,pdf_dir生成PDF):批量把 Word 合同转成 PDFos.makedirs(pdf_dir,exist_okTrue)forfinos.listdir(docx_dir):iff.endswith(.docx):docx_pathos.path.join(docx_dir,f)pdf_pathos.path.join(pdf_dir,f.replace(.docx,.pdf))convert(docx_path,pdf_path)print(f已转换:{f}→{os.path.basename(pdf_path)})# 使用batch_docx_to_pdf()二、实战案例二批量提取发票信息从一堆 PDF 发票中自动提取关键字段导出到 Excel。1. 文字型发票提取importpdfplumberimportpandasaspdimportreimportosclassInvoiceExtractor:发票信息提取器def__init__(self):self.fields[发票号码,开票日期,金额,税额,价税合计,销售方名称,购买方名称,货物名称]defextract_from_text(self,pdf_path):从文字型 PDF 发票中提取信息info{文件:os.path.basename(pdf_path)}textwithpdfplumber.open(pdf_path)aspdf:forpageinpdf.pages:textpage.extract_text()or# 发票号码matchre.search(r发票号码[:]\s*(\d),text)ifmatch:info[发票号码]match.group(1)# 开票日期matchre.search(r开票日期[:]\s*(\d{4}[\-\年]\d{1,2}[\-\月]\d{1,2}),text)ifmatch:info[开票日期]match.group(1).replace(年,-).replace(月,-)# 金额价税合计matchre.search(r价税合计[(]大写[)][^0-9]*([\d,]\.\d{2}),text)ifmatch:info[价税合计]match.group(1).replace(,,)# 销售方名称matchre.search(r销售方[名称]?[:]\s*(.?)(?:\n|$),text)ifmatch:info[销售方名称]match.group(1).strip()# 购买方名称matchre.search(r购买方[名称]?[:]\s*(.?)(?:\n|$),text)ifmatch:info[购买方名称]match.group(1).strip()returninfodefextract_from_table(self,pdf_path):从发票 PDF 的表格中提取商品明细items[]withpdfplumber.open(pdf_path)aspdf:forpageinpdf.pages:tablespage.extract_tables()fortableintables:forrowintable[1:]:# 跳过表头ifrowandrow[0]andlen(row)4:items.append({货物名称:row[0],数量:row[1]iflen(row)1else,单价:row[2]iflen(row)2else,金额:row[3]iflen(row)3else,})returnitemsdefbatch_extract(self,pdf_dir):批量提取all_data[]forfinos.listdir(pdf_dir):iff.endswith(.pdf):infoself.extract_from_text(os.path.join(pdf_dir,f))all_data.append(info)print(f已提取:{f})dfpd.DataFrame(all_data)df.to_excel(发票信息汇总.xlsx,indexFalse)print(f\n共提取{len(all_data)}张发票已导出到 发票信息汇总.xlsx)returndf# 使用extractorInvoiceExtractor()extractor.batch_extract(发票PDF)2. 扫描件发票OCRimportpytesseractfromPILimportImageimportpdfplumberimportiodefocr_invoice(pdf_path):OCR 识别扫描件发票withpdfplumber.open(pdf_path)aspdf:fori,pageinenumerate(pdf.pages):# 转图片imgpage.to_image(resolution300)img_pathftemp_page_{i}.pngimg.save(img_path)# OCR 识别textpytesseract.image_to_string(Image.open(img_path),langchi_simeng,# 中文 英文)# 提取关键信息invoice_nore.search(r发票号码[:]\s*(\d),text)totalre.search(r价税合计[:]?\s*[¥]?([\d,]\.\d{2}),text)print(f发票号码:{invoice_no.group(1)ifinvoice_noelse未识别})print(f价税合计:{total.group(1)iftotalelse未识别})# 使用需要安装 Tesseract-OCR 引擎# ocr_invoice(扫描发票.pdf)三、实战案例三合并多个 PDFfromPyPDF2importPdfMerger,PdfReader,PdfWriterimportosdefmerge_invoices(pdf_dir,output合并发票.pdf):合并多个发票 PDF 为一个文件mergerPdfMerger()filessorted([fforfinos.listdir(pdf_dir)iff.endswith(.pdf)])forfinfiles:merger.append(os.path.join(pdf_dir,f))merger.write(output)merger.close()print(f合并完成共{len(files)}个文件 →{output})defsplit_into_single_pages(pdf_path,output_dir拆分明细):将合并的 PDF 按页拆分为单张os.makedirs(output_dir,exist_okTrue)readerPdfReader(pdf_path)foriinrange(len(reader.pages)):writerPdfWriter()writer.add_page(reader.pages[i])outputos.path.join(output_dir,f第{i1}页.pdf)withopen(output,wb)asf:writer.write(f)print(f已拆分{len(reader.pages)}页到{output_dir})四、完整工作流defdaily_invoice_pipeline(input_dir):每日发票处理流水线print(开始发票处理流水线...)# 1. 提取信息extractorInvoiceExtractor()dfextractor.batch_extract(input_dir)# 2. 合并 PDFmerge_invoices(input_dir,f发票汇总_{datetime.now().strftime(%Y%m%d)}.pdf)# 3. 生成统计报表ifnotdf.emptyand价税合计indf.columns:totaldf[价税合计].sum()countlen(df)print(f\n统计共{count}张发票总金额{total:,.2f}元)print(处理完成)# 使用daily_invoice_pipeline(发票PDF)五、各场景注意事项场景注意事项合同模板占位符不要用 {name} 要用 {{name}}避免正则冲突发票提取不同公司的发票格式不同需要针对性调整正则扫描件 OCR必须安装 Tesseract 引擎和中文语言包PDF 合并按文件名排序保证顺序建议文件名加日期前缀批量处理先处理一个样本调通再批量全跑 觉得有用的话点赞 关注【张老师技术栈】吧每周更新 Java/Python/爬虫 实战干货不让你白来。