python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python PDF创建与填写表单

使用Python在PDF文档中自动创建与填写表单

作者:大丸子

本文将教你使用Python自动完成表单创建、批量填写、字段提取和扁平化,实现电子合同全流程自动化,特别适合供应商协议、人事合同等场景,文中的示例代码讲解详细,有需要的小伙伴可以了解下

在企业数字化进程中,电子合同、申请表、报销单、问卷等场景大量依赖 PDF 表单(AcroForm)进行数据采集。传统做法是先用 Adobe Acrobat 或在线编辑器手工绘制表单字段,再由业务人员逐份打开、逐字段录入,面对批量合同时不仅耗时,还容易出现字段填错、漏填、格式不一致等问题。当表单需要对接审批系统、CRM 或归档数据库时,纯人工方式更难以满足合规与效率要求。

将表单的"创建—填写—提取—固化"全流程交给代码自动完成,可以让一份合同模板在数秒内生成数十份差异化合同,并在签署后自动回收关键字段进入业务系统。这种方式特别适用于人力资源合同、采购订单、供应商协议、用户调研问卷等高频、强结构化的场景。

本文将以一份"供应商合作协议"为线索,演示如何使用 Python 完成 PDF 表单的创建、批量自动填写、字段值提取以及表单固化(Flatten)等关键操作,构建一条可复用的电子合同自动化流水线。

本文使用的方法需要用到 Free Spire.PDF for Python,可通过 pip 安装:

pip install spire.pdf.free

1. 创建 PDF 电子合同表单模板

电子合同的第一步是生成带有可填写字段的 PDF 模板。我们先用代码在空白页面上绘制合同标题、说明文字,并添加文本框字段与列表框字段,搭建出一份可分发的空白合同模板。

from spire.pdf.common import *
from spire.pdf import *

outputFile = "ContractTemplate.pdf"

# 创建 PDF 文档
doc = PdfDocument()
# 允许在已有文档上创建表单(新建文档时也建议显式设置)
doc.AllowCreateForm = True

# 添加一个页面
page = doc.Pages.Add()

# 创建字体与画刷
titleFont = PdfTrueTypeFont("微软雅黑", 18.0, PdfFontStyle.Bold, True)
labelFont = PdfTrueTypeFont("微软雅黑", 11.0, PdfFontStyle.Regular, True)
fieldFont = PdfTrueTypeFont("宋体", 11.0, PdfFontStyle.Regular, True)
brush = PdfBrushes.get_Black()
hintBrush = PdfBrushes.get_DodgerBlue()

# 绘制合同标题
titleFormat = PdfStringFormat(PdfTextAlignment.Center)
page.Canvas.DrawString("供应商合作协议", titleFont, brush,
                        page.Canvas.ClientSize.Width / float(2), 40.0, titleFormat)

# 绘制说明文字
page.Canvas.DrawString("请填写以下字段后签署,带 * 字段为必填项。", labelFont, hintBrush, 50.0, 80.0)

# 字段起始坐标
x = 50.0
y = 120.0
labelGap = 15.0
fieldWidth = 200.0
fieldHeight = 18.0

# 1) 添加"供应商名称"文本框字段
label1 = "供应商名称 *:"
page.Canvas.DrawString(label1, labelFont, brush, x, y)
textX = x + labelFont.MeasureString(label1).Width + labelGap
textBoxName = PdfTextBoxField(page, "vendor_name")
textBoxName.Bounds = RectangleF(textX, y, fieldWidth, fieldHeight)
textBoxName.BorderWidth = 0.75
textBoxName.BorderStyle = PdfBorderStyle.Solid
textBoxName.Font = fieldFont
doc.Form.Fields.Add(textBoxName)

# 2) 添加"统一社会信用代码"文本框字段
y = y + 40.0
label2 = "信用代码 *:"
page.Canvas.DrawString(label2, labelFont, brush, x, y)
textX = x + labelFont.MeasureString(label2).Width + labelGap
textBoxCode = PdfTextBoxField(page, "credit_code")
textBoxCode.Bounds = RectangleF(textX, y, fieldWidth, fieldHeight)
textBoxCode.BorderWidth = 0.75
textBoxCode.BorderStyle = PdfBorderStyle.Solid
textBoxCode.Font = fieldFont
doc.Form.Fields.Add(textBoxCode)

# 3) 添加"合同金额(元)"文本框字段
y = y + 40.0
label3 = "合同金额 *:"
page.Canvas.DrawString(label3, labelFont, brush, x, y)
textX = x + labelFont.MeasureString(label3).Width + labelGap
textBoxAmount = PdfTextBoxField(page, "amount")
textBoxAmount.Bounds = RectangleF(textX, y, fieldWidth, fieldHeight)
textBoxAmount.BorderWidth = 0.75
textBoxAmount.BorderStyle = PdfBorderStyle.Solid
textBoxAmount.Font = fieldFont
doc.Form.Fields.Add(textBoxAmount)

# 4) 添加"签署日期"文本框字段
y = y + 40.0
label4 = "签署日期 *:"
page.Canvas.DrawString(label4, labelFont, brush, x, y)
textX = x + labelFont.MeasureString(label4).Width + labelGap
textBoxDate = PdfTextBoxField(page, "sign_date")
textBoxDate.Bounds = RectangleF(textX, y, fieldWidth, fieldHeight)
textBoxDate.BorderWidth = 0.75
textBoxDate.BorderStyle = PdfBorderStyle.Solid
textBoxDate.Font = fieldFont
doc.Form.Fields.Add(textBoxDate)

# 5) 添加"付款方式"列表框字段
y = y + 40.0
label5 = "付款方式 *:"
page.Canvas.DrawString(label5, labelFont, brush, x, y)
textX = x + labelFont.MeasureString(label5).Width + labelGap
listBoxPayment = PdfListBoxField(page, "payment_method")
listBoxPayment.Items.Add(PdfListFieldItem("一次性付清", "pay_once"))
listBoxPayment.Items.Add(PdfListFieldItem("分期付款(按月)", "pay_monthly"))
listBoxPayment.Items.Add(PdfListFieldItem("分期付款(按季)", "pay_quarterly"))
listBoxPayment.Items.Add(PdfListFieldItem("验收后付款", "pay_after_accept"))
listBoxPayment.Bounds = RectangleF(textX, y, fieldWidth, 60.0)
listBoxPayment.Font = fieldFont
listBoxPayment.SelectedIndex = 0
doc.Form.Fields.Add(listBoxPayment)

# 保存模板
doc.SaveToFile(outputFile, FileFormat.PDF)
doc.Close()

说明:

此步骤的作用是生成一份可分发的空白合同模板,为后续批量自动填写奠定基础。

创建PDF表单模板

2. 自动填写电子合同表单

模板生成后,实际业务中往往需要根据数据库或 Excel 中的供应商信息批量填写合同。下面演示如何加载模板,遍历表单字段并按业务数据自动填充。

from spire.pdf.common import *
from spire.pdf import *

inputFile = "ContractTemplate.pdf"
outputFile = "FilledContract.pdf"

# 加载合同模板
doc = PdfDocument()
doc.LoadFromFile(inputFile)

# 获取表单并转换为 FormWidget
pdfform = doc.Form
formWidget = PdfFormWidget(pdfform)

# 业务数据:来自数据库或 Excel 的供应商信息
vendorData = {
    "vendor_name": "成都**科技有限公司",
    "credit_code": "91510100MA6XXXXXX9X",
    "amount": "128000.00",
    "sign_date": "2026-08-28"
}

# 遍历所有字段并按名称填充
if formWidget.FieldsWidget.Count > 0:
    for i in range(formWidget.FieldsWidget.Count):
        field = formWidget.FieldsWidget.get_Item(i)

        # 处理文本框字段
        if isinstance(field, PdfTextBoxFieldWidget):
            textBoxField = field if isinstance(field, PdfTextBoxFieldWidget) else None
            if textBoxField.Name in vendorData:
                textBoxField.Text = vendorData[textBoxField.Name]

        # 处理列表框字段
        if isinstance(field, PdfListBoxWidgetFieldWidget):
            listBoxField = field if isinstance(field, PdfListBoxWidgetFieldWidget) else None
            if listBoxField.Name == "payment_method":
                # 选择"分期付款(按月)"
                listBoxField.SelectedIndex = [1]

# 保存填写后的合同
doc.SaveToFile(outputFile)
doc.Close()

说明:

此步骤实现了"模板 + 数据 = 合同"的自动化填充,是批量出合同的核心环节。

自动填写表单结果

批量生成多份合同

将上述填充逻辑封装为函数,即可根据供应商列表批量生成合同:

from spire.pdf.common import *
from spire.pdf import *

def fillContract(templatePath, outputPath, vendorData, paymentIndex):
    doc = PdfDocument()
    doc.LoadFromFile(templatePath)
    formWidget = PdfFormWidget(doc.Form)

    if formWidget.FieldsWidget.Count > 0:
        for i in range(formWidget.FieldsWidget.Count):
            field = formWidget.FieldsWidget.get_Item(i)
            if isinstance(field, PdfTextBoxFieldWidget):
                textBoxField = field if isinstance(field, PdfTextBoxFieldWidget) else None
                if textBoxField.Name in vendorData:
                    textBoxField.Text = vendorData[textBoxField.Name]
            if isinstance(field, PdfListBoxWidgetFieldWidget):
                listBoxField = field if isinstance(field, PdfListBoxWidgetFieldWidget) else None
                if listBoxField.Name == "payment_method":
                    listBoxField.SelectedIndex = [paymentIndex]
    doc.SaveToFile(outputPath)
    doc.Close()

# 供应商列表(实际来自数据库查询)
vendors = [
    {"vendor_name": "成都云启科技有限公司", "credit_code": "91510100MA6XXXXXX9X",
     "amount": "128000.00", "sign_date": "2026-08-28"},
    {"vendor_name": "深圳前海数据服务有限公司", "credit_code": "91440300MA5XXXXXX3X",
     "amount": "86500.00", "sign_date": "2026-08-28"},
    {"vendor_name": "杭州数澜科技股份有限公司", "credit_code": "91330106MA2XXXXXX1X",
     "amount": "210000.00", "sign_date": "2026-08-28"},
]

# 批量生成
for idx, vendor in enumerate(vendors):
    fillContract("ContractTemplate.pdf", f"Contracts/Contract_{idx + 1}.pdf", vendor, 0)

说明:

3. 提取表单字段数据用于归档与校验

合同签署回收后,业务系统通常需要把表单中的关键字段读出来归档、入库或与原始订单校验。下面演示如何遍历所有字段并提取其值。

from spire.pdf.common import *
from spire.pdf import *

inputFile = "FilledContract.pdf"
outputFile = "ExtractedFormData.txt"

# 加载已填写的合同
doc = PdfDocument()
doc.LoadFromFile(inputFile)
formWidget = PdfFormWidget(doc.Form)

result = []

if formWidget.FieldsWidget.Count > 0:
    for i in range(formWidget.FieldsWidget.Count):
        field = formWidget.FieldsWidget.get_Item(i)

        # 提取文本框字段值
        if isinstance(field, PdfTextBoxFieldWidget):
            textBoxField = field if isinstance(field, PdfTextBoxFieldWidget) else None
            result.append(f"字段名:{textBoxField.Name},值:{textBoxField.Text}")

        # 提取列表框字段值
        if isinstance(field, PdfListBoxWidgetFieldWidget):
            listBoxField = field if isinstance(field, PdfListBoxWidgetFieldWidget) else None
            selectedValue = listBoxField.SelectedValue
            result.append(f"字段名:{listBoxField.Name},选中值:{selectedValue}")

# 保存提取结果
with open(outputFile, "w", encoding="UTF-8") as f:
    for line in result:
        f.write(line + "\n")

doc.Close()

说明:

4. 表单字段管理:必填、修改、扁平化与删除

在合同流程的不同阶段,往往需要对表单字段做进一步管理:起草时标记必填、审批时修改个别字段、签署完成后扁平化防止篡改、归档前删除临时字段。

4.1 设置必填字段与修改字段值

from spire.pdf.common import *
from spire.pdf import *

inputFile = "ContractTemplate.pdf"
outputFile = "ManagedContract.pdf"

doc = PdfDocument()
doc.LoadFromFile(inputFile)
formWidget = PdfFormWidget(doc.Form)

if formWidget.FieldsWidget.Count > 0:
    for i in range(formWidget.FieldsWidget.Count):
        field = formWidget.FieldsWidget.get_Item(i)

        if isinstance(field, PdfTextBoxFieldWidget):
            textBoxField = field if isinstance(field, PdfTextBoxFieldWidget) else None
            # 将关键字段标记为必填
            if textBoxField.Name in ["vendor_name", "credit_code", "amount", "sign_date"]:
                textBoxField.Required = True
            # 为字段设置统一字体,提升填写后的视觉效果
            textBoxField.Font = PdfTrueTypeFont("宋体", 11.0, PdfFontStyle.Regular, True)

# 保存
doc.SaveToFile(outputFile)
doc.Close()

说明:

4.2 扁平化表单防止二次修改

合同签署完成后,通常需要将表单字段"烧录"成静态内容,防止后续被篡改:

from spire.pdf.common import *
from spire.pdf import *

inputFile = "FilledContract.pdf"
outputFile = "FlattenedContract.pdf"

doc = PdfDocument()
doc.LoadFromFile(inputFile)

# 扁平化所有表单字段:字段值转为普通文本,不再可编辑
doc.Form.IsFlatten = True

doc.SaveToFile(outputFile)
doc.Close()

说明:

4.3 删除指定字段

在模板复用场景中,有时需要从已有表单中移除某些不再使用的字段:

from spire.pdf.common import *
from spire.pdf import *

inputFile = "ContractTemplate.pdf"
outputFile = "RemovedFieldContract.pdf"

doc = PdfDocument()
doc.LoadFromFile(inputFile)
formWidget = PdfFormWidget(doc.Form)

if formWidget.FieldsWidget.Count > 0:
    i = 0
    while i < formWidget.FieldsWidget.Count:
        field = formWidget.FieldsWidget.get_Item(i)
        if isinstance(field, PdfTextBoxFieldWidget):
            textBoxField = field if isinstance(field, PdfTextBoxFieldWidget) else None
            # 删除"签署日期"字段
            if textBoxField.Name == "sign_date":
                formWidget.FieldsWidget.Remove(textBoxField)
                continue
        i = i + 1

doc.SaveToFile(outputFile)
doc.Close()

说明:

关键类与方法说明表

为便于查阅,下面整理本文中主要使用到的类、属性与方法。

类 / 方法说明
PdfDocumentPDF 文档对象,负责创建、加载与保存文档
PdfDocument.AllowCreateForm是否允许在文档上创建表单字段
PdfDocument.Form获取文档的表单对象
PdfFormWidget表单操作对象,提供 FieldsWidget 字段集合
FieldsWidget.get_Item(i)按索引获取字段
FieldsWidget.Remove(field)移除指定字段
PdfTextBoxField(page, name)创建文本框字段
PdfListBoxField(page, name)创建列表框字段
PdfListFieldItem(text, value)列表框/组合框的选项项
PdfTextBoxFieldWidget文本框字段操作对象,可读写 Text、Required、Font 等
PdfListBoxWidgetFieldWidget列表框字段操作对象,可读写 SelectedIndex、SelectedValue
field.Bounds = RectangleF(x, y, w, h)设置字段位置与尺寸
field.BorderStyle / field.BorderWidth设置字段边框样式与宽度
PdfTrueTypeFont(name, size, style, true)创建 TrueType 字体,用于页面绘制与字段字体设置
PdfBrushes.get_Black()获取黑色画刷,用于绘制文本
page.Canvas.DrawString(...)在页面上绘制文本
doc.Form.IsFlatten = True扁平化所有表单字段,转为静态文本

总结

通过本文示例,你已经了解如何使用 Python 完成 PDF 电子合同表单的完整生命周期管理:从创建带字段的合同模板,到根据业务数据批量自动填写,再到签署后提取字段值回流业务系统,最后通过扁平化固化签署结果。整个过程高度自动化,特别适用于供应商协议、人事合同、采购订单等高频、强结构化场景。

相比手工在 Acrobat 中逐份填写,代码方式具有批量处理、字段校验、与业务系统无缝对接等优势。你可以在此基础上扩展更多能力,例如结合数字签名保障法律效力、对接数据库实现合同台账自动入库、用 OCR 识别纸质合同回填电子表单等,构建完整的电子合同管理闭环。

到此这篇关于使用Python在PDF文档中自动创建与填写表单的文章就介绍到这了,更多相关Python PDF创建与填写表单内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文