处理 PDF 表单(PDF Form)是办公自动化中一个比较高级的需求——批量填写合同模板、生成大量报表、提取表单数据。这篇用两个完整案例讲清楚。
一、案例一:批量填写 PDF 表单
假设你有一份 PDF 合同模板,里面有表单字段(姓名、金额、日期等),需要根据 Excel 数据批量填写并生成合同。
1. 准备工作
pipinstallpdfplumber PyPDF22. 查看 PDF 表单字段
importpdfplumberdefinspect_form_fields(pdf_path):"""查看 PDF 中的表单字段信息"""withpdfplumber.open(pdf_path)aspdf:fori,pageinenumerate(pdf.pages):# 获取注释(包括表单字段)annotations=page.annotsifannotations:print(f"第{i+1}页表单字段:")foranninannotations:print(f" -{ann.get('name','未命名')}: "f"类型={ann.get('subtype','')}")3. 批量填写
fromPyPDF2importPdfReader,PdfWriterimportpandasaspddeffill_pdf_form(template_path,output_path,data_dict):""" 填写 PDF 表单 template_path: 模板 PDF output_path: 输出 PDF data_dict: 字段名→值的字典 """reader=PdfReader(template_path)writer=PdfWriter()page=reader.pages[0]# 更新表单字段writer.add_page(page)# 设置表单字段值writer.update_page_form_field_values(writer.pages[0],data_dict)# 保存withopen(output_path,"wb")asf:writer.write(f)defbatch_fill_forms(template_path,excel_path,output_dir):"""根据 Excel 数据批量生成 PDF 合同"""importos os.makedirs(output_dir,exist_ok=True)df=pd.read_excel(excel_path)for_,rowindf.iterrows():# 构建字段数据data={"name":row["客户名称"],"amount":str(row["金额"]),"date":str(row["签订日期"]),"contract_no":row["合同编号"],}output=os.path.join(output_dir,f"合同_{row['客户名称']}.pdf")fill_pdf_form(template_path,output,data)print(f"已生成:{output}")二、案例二:提取 PDF 表单数据
1. 提取已填写的表单
defextract_form_data(pdf_path):"""提取 PDF 表单中的填写数据"""reader=PdfReader(pdf_path)fields=reader.get_form_text_fields()print("表单字段提取结果:")forfield_name,valueinfields.items():print(f"{field_name}:{value}")returnfieldsdefbatch_extract(pdf_dir,output_excel):"""批量提取多个 PDF 表单到 Excel"""importos all_data=[]forfinos.listdir(pdf_dir):iff.endswith(".pdf"):fields=extract_form_data(os.path.join(pdf_dir,f))fields["来源文件"]=f all_data.append(fields)ifall_data:df=pd.DataFrame(all_data)df.to_excel(output_excel,index=False)print(f"共提取{len(all_data)}份表单:{output_excel}")2. 提取不可填写的表格数据
defextract_table_from_scanned(pdf_path):""" 从扫描件或不可填写的 PDF 中提取表格 适用于文字型 PDF 中的表格数据 """importpdfplumberimportpandasaspdwithpdfplumber.open(pdf_path)aspdf:all_tables=[]fori,pageinenumerate(pdf.pages):tables=page.extract_tables()fortableintables:iftableandlen(table)>1:# 第一行为表头df=pd.DataFrame(table[1:],columns=table[0])all_tables.append(df)print(f"第{i+1}页找到表格:{len(table)}行")ifall_tables:result=pd.concat(all_tables,ignore_index=True)returnresultreturnNone3. 完整工作流
defdaily_pdf_pipeline():"""每日 PDF 处理流水线"""print("开始 PDF 处理...")# 1. 提取表单数据form_data=extract_form_data("日报表.pdf")print(f"提取到{len(form_data)}个字段")# 2. 提取表格数据table_df=extract_table_from_scanned("明细.pdf")iftable_dfisnotNone:table_df.to_excel("提取数据.xlsx",index=False)print(f"导出{len(table_df)}行数据")# 3. 生成汇总报告# ...print("处理完成!")三、注意事项
1. PDF 表单需要是 AcroForm 格式,不是扫描件 2. 拍照/扫描件需要先 OCR 识别 3. 批量处理前先测试一个样本 4. 中文字体在 PDF 中需要嵌入,否则显示方框💡 觉得有用的话,点赞 + 关注【张老师技术栈】吧!每周更新 Java/Python/爬虫 实战干货,不让你白来。