我的知识记录

Python填写PDF表单字段:自动批量填合同

用Python的PyMuPDF读取PDF表单字段并批量填充,支持文本框、复选框、下拉框,填完另存为新文件,适合批量生成合同、申请表、报名表。

场景痛点

公司有一份固定模板的PDF合同或申请表,每次要手动打开Adobe Reader,在各个字段里填客户名、金额、日期,几十份下来手都软。其实PDF表单(AcroForm)里每个字段都有名字,用Python读出来、按字典填值、另存为新文件,一次能批量生成几百份。

用到的库

pip install pymupdf

完整代码

# -*- coding: utf-8 -*-
"""
读取 PDF 表单字段,按字典批量填充,另存为新 PDF。
"""
import fitz  # PyMuPDF
from pathlib import Path


def list_form_fields(pdf_path: str):
"""打印 PDF 里所有表单字段名和当前值,方便先摸清楚字段名。"""
doc = fitz.open(pdf_path)
print(f"=== {pdf_path} 的表单字段 ===")
for page in doc:
for widget in page.widgets():
print(f"  字段名: {widget.field_name!r:30} 类型: {widget.field_type_string:10} 当前值: {widget.field_value!r}")
doc.close()


def fill_pdf_form(template_pdf: str, output_pdf: str, data: dict):
"""
template_pdf: 带表单的 PDF 模板
output_pdf: 填好后另存的文件
data: {字段名: 值},如 {"customer": "张三", "amount": "12800"}
"""
doc = fitz.open(template_pdf)

for page in doc:
for widget in page.widgets():
field_name = widget.field_name
if field_name in data:
widget.field_value = str(data[field_name])
# 标记为已修改,保存时才会写进去
widget.update()

# 保存时把表单字段扁平化(flatten),填好的值变成普通文字,
# 别人打开不能再改;不想扁平化就去掉这个参数
doc.save(output_pdf, garbage=3, deflate=True)
doc.close()
print(f"已生成:{output_pdf}")


def batch_fill(template_pdf: str, output_dir: str, records: list):
"""
records: 一组字典,每个字典是一份要填的数据
"""
out = Path(output_dir)
out.mkdir(parents=True, exist_ok=True)

for idx, record in enumerate(records, start=1):
# 用客户名或序号命名输出文件
name = record.get("customer", f"doc_{idx:03d}")
out_file = out / f"{name}.pdf"
fill_pdf_form(template_pdf, str(out_file), record)


if __name__ == "__main__":
# 第一步:先跑这个,看清楚模板里的字段名
list_form_fields("contract_template.pdf")

# 第二步:按字段名填数据
batch_fill(
template_pdf="contract_template.pdf",
output_dir="filled_contracts",
records=[
{"customer": "张三", "amount": "12800", "date": "2026-09-14"},
{"customer": "李四", "amount": "25600", "date": "2026-09-14"},
{"customer": "王五", "amount": "8900",  "date": "2026-09-14"},
],
)

代码讲解

  • page.widgets() 遍历当前页所有表单控件,每个widget有field_name(字段名)、field_type_string(类型:Text/CheckBox/ComboBox)、field_value(当前值)。
  • list_form_fields() 是调试用的,第一次拿到模板先跑一遍,把所有字段名打印出来,再照着写data字典,避免猜错字段名。
  • widget.field_value = "..." 直接赋值,然后必须调widget.update(),PyMuPDF才会把修改写回文档。
  • 复选框的填值是"Yes""Off",下拉框要填选项里存在的值,否则保存后不显示。
  • 保存时不加flatten参数,填好的PDF仍然是可编辑表单;加了flatten=True(在save里传)就把值"烤"进页面,别人改不了。

运行结果

先跑list_form_fields看到模板里有哪些字段名,然后照着填数据。跑完filled_contracts/目录下生成张三.pdf李四.pdf王五.pdf,打开后客户名、金额、日期都已经填好。

注意事项

  • 不是所有PDF都有表单字段。扫描件PDF、Word另存的PDF通常没有可填字段,这种情况要用"在指定位置插入文字"的方案。
  • 字段名是PDF制作者在Acrobat里起的,可能是Text1customer_1这种,必须先list_form_fields看清楚,不能猜。
  • 中文字段值在某些旧版PDF阅读器里可能显示不全,用最新版Adobe Reader或浏览器打开验证。
  • 批量生成合同时,模板文件本身不要被修改,脚本只读模板、输出到新目录。

Python填写PDF表单字段:自动批量填合同

标签:

更新时间:2026-09-14 21:38:18

上一篇:Python获取PDF页数与元信息 标题作者教程

下一篇:Python提取PDF指定页面为新文件 方法详解