Python批量填写与提取PDF表单数据的代码实现
PDF表单(AcroForm)在办公自动化中常被用作合同模板或报表模板。通过Python可以批量填写这些表单字段,也可以从已填写的表单中提取数据。本文使用pdfplumber和PyPDF2两个库,给出可复用的批量处理代码。## 环境准备
安装依赖:
pip install pdfplumber PyPDF2 pandas openpyxl
## 案例一:批量填写PDF表单
### 1. 查看表单字段结构
在填写前,需要知道模板中有哪些字段。使用pdfplumber可以遍历注释(annotations)获取字段名:
import pdfplumber
def inspect_form_fields(pdf_path):
"""查看PDF表单字段名称与类型"""
with pdfplumber.open(pdf_path) as pdf:
for i, page in enumerate(pdf.pages):
annotations = page.annots
if annotations:
print(f"第 {i+1} 页表单字段:")
for ann in annotations:
print(f" - {ann.get('name', '未命名')}: 类型={ann.get('subtype', '')}")
运行后输出字段名列表,后续填写时需要使用完全一致的字段名称。
### 2. 单份填写函数
使用PyPDF2的PdfWriter更新表单字段值:
from PyPDF2 import PdfReader, PdfWriter
def fill_pdf_form(template_path, output_path, data_dict):
"""
填写单个PDF表单
:param template_path: 模板PDF路径
:param output_path: 输出PDF路径
:param data_dict: 字段名→值的字典
"""
reader = PdfReader(template_path)
writer = PdfWriter()
writer.add_page(reader.pages)
writer.update_page_form_field_values(writer.pages, data_dict)
with open(output_path, "wb") as f:
writer.write(f)
### 3. 批量生成合同
假设有一份Excel数据源,包含“客户名称”、“金额”、“签订日期”、“合同编号”等列,每行对应一份合同。读取Excel并循环生成:
import pandas as pd
import os
def batch_fill_forms(template_path, excel_path, output_dir):
os.makedirs(output_dir, exist_ok=True)
df = pd.read_excel(excel_path)
for _, row in df.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. 提取已填写的表单字段
使用PyPDF2的get_form_text_fields()可以获取所有可填写字段的当前值:
def extract_form_data(pdf_path):
reader = PdfReader(pdf_path)
fields = reader.get_form_text_fields()
print("表单字段提取结果:")
for field_name, value in fields.items():
print(f"{field_name}: {value}")
return fields
批量处理多个PDF并将结果汇总为Excel:
def batch_extract(pdf_dir, output_excel):
all_data = []
for f in os.listdir(pdf_dir):
if f.endswith(".pdf"):
fields = extract_form_data(os.path.join(pdf_dir, f))
fields["来源文件"] = f
all_data.append(fields)
if all_data:
df = pd.DataFrame(all_data)
df.to_excel(output_excel, index=False)
print(f"共提取 {len(all_data)} 份表单: {output_excel}")
### 2. 提取不可填写表格(文字型PDF)
对于不含AcroForm的PDF(例如文字型报表),可以使用pdfplumber提取表格数据:
def extract_table_from_scanned(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
all_tables = []
for i, page in enumerate(pdf.pages):
tables = page.extract_tables()
for table in tables:
if table and len(table) > 1:
df = pd.DataFrame(table, columns=table)
all_tables.append(df)
print(f"第{i+1}页找到表格: {len(table)}行")
if all_tables:
return pd.concat(all_tables, ignore_index=True)
return None
### 3. 完整处理流水线
将上述步骤组合成一个每日自动执行的流程:
def daily_pdf_pipeline():
print("开始PDF处理...")
form_data = extract_form_data("日报表.pdf")
print(f"提取到 {len(form_data)} 个字段")
table_df = extract_table_from_scanned("明细.pdf")
if table_df is not None:
table_df.to_excel("提取数据.xlsx", index=False)
print(f"导出 {len(table_df)} 行数据")
# 后续可加入汇总报告生成逻辑
print("处理完成!")
## 注意事项
1. PDF表单必须为AcroForm格式,非扫描件。如果模板是扫描图片,需先OCR识别。
2. 批量处理前务必用单个文件测试,确认字段名与Excel列名对应无误。
3. 中文字体需要嵌入到PDF中,否则填写后显示为方框。
4. PyPDF2的update_page_form_field_values对非ASCII字段名可能有限制,建议字段名使用英文。
通过以上代码,可以快速搭建批量PDF表单处理工具。在实际项目中,可根据需求扩充异常处理和日志记录。
Re: Python批量填写与提取PDF表单数据的代码实现
感谢楼主的详细分享!代码非常清晰实用,特别是预处理查看字段结构的部分,能避免字段名对不上的坑。批量生成合同和提取数据两个方向正好覆盖了日常办公中PDF表单操作的核心需求。我试了一下,遇到一个小问题:如果模板PDF有多个页面,update_page_form_field_values 是不是只更新了第一页?还是需要迭代所有页面才能把数据填到每一页的相同字段里?另外,对于下拉列表或复选框这类非文本字段,写法上需要注意什么吗?期待后续能补充更多场景的适配技巧!Re: Python批量填写与提取PDF表单数据的代码实现
感谢楼主的分享,代码很清晰,对于处理PDF表单的批量操作非常实用。有一个小问题想问一下:在案例二的 `extract_form_data` 里用了 `get_form_text_fields()`,但某些PDF里的字段可能是单选/复选框或数字签名,这个函数能正确获取吗?还是说需要额外处理?另外,如果遇到中文字段名或中文内容,PyPDF2 会不会有编码方面的问题?期待后续补充。Re: Python批量填写与提取PDF表单数据的代码实现
感谢脚本专家的分享,这套代码非常实用,正好解决了我最近批量处理合同表单的需求。特别是`inspect_form_fields`这个函数,以前我总得手动打开PDF属性查找字段名,现在可以直接打印出来,方便多了。 想请教一个细节:在使用PyPDF2的`update_page_form_field_values`时,如果模板中有复选框或下拉列表,data_dict里的值应该怎么传?直接传字符串就能自动匹配选项吗?另外,对于带中文的字段值,是否需要注意编码或字体问题? 期待您的进一步指点,也欢迎大家交流实际使用中的踩坑经验。
页:
[1]