提取 PDF 表单域数据:无代码与自动化方法

填写完成的 PDF 表单中,往往包含需要用于其他场景的信息,例如登记表中的联系方式、问卷中的回答,或申请表中的地址。偶尔查阅时,可以逐份打开 PDF 查看;但将数据导出后,更便于核对、整理和进一步处理。

实际操作中有两种常见方式:通过 PDF 编辑器的界面导出表单数据,或使用 C# 程序读取各个字段,并按自定义格式写入文本文件。本文介绍 Adobe Acrobat、福昕 PDF 编辑器,以及使用 Spire.PDF for .NET 实现的自动化方案。

为便于比较,以下示例均使用同一份已填写的表单,并以 TXT 作为输出格式。

开始之前:表单域与页面文本的区别

PDF 表单域是用于存储值的交互式对象。例如,文本框中输入的姓名、下拉列表中选择的国家,以及语言复选框的选中状态,都属于表单域数据。

外观看起来像表单的文档,不一定包含这些对象。扫描后的申请表可能只是一张图片;经过扁平化处理的 PDF,则可能将填写结果显示为静态页面内容。这两种情况下,都无法通过本文的方法读取原来的交互式表单域。

本文主要处理交互式 AcroForm 表单域。从扫描件中提取填写内容需要采用其他流程,例如先进行 OCR,再识别对应的回答。提取 PDF 页面上的普通表格,也属于另一类任务。

示例表单包含个人信息、地址、语言复选框和颜色选择项。部分内部字段名带有控件类型说明,例如 Given Name Text Box 和 Country Combo Box。这些名称会出现在原始导出结果中。

提取数据前已填写的 PDF 示例表单

方法一:使用 Adobe Acrobat 导出 PDF 表单域数据

Acrobat 提供表单数据导出命令,可以直接保存已填写的字段值,无需逐项复制。请使用能够访问“准备表单”工具的桌面应用,以下步骤不适用于浏览器中的 PDF 查看器。

将表单数据导出为 TXT

  1. 在 Adobe Acrobat 中打开已填写的 PDF。
  2. 选择所有工具 → 准备表单。
  3. 在表单面板中,打开更多 → 导出数据。
  4. 在“另存为”对话框中选择 TXT。
  5. 设置文件名和保存位置,点击保存。

此导出流程还提供 FDF、XFDF 和 XML 格式。具体可用格式可能取决于表单的创建方式,不同界面版本中的菜单位置也可能有所不同。

Acrobat 的导出数据命令

理解导出的文本结构

在测试的示例中,Acrobat 生成了以制表符分隔的文本:所有字段名位于一条长行中,对应的字段值位于下一行。简化后的结构如下:

1
2
Given Name Text Box<TAB>Family Name Text Box<TAB>City Text Box
罗斯<TAB>尼尔森<TAB>斯普林菲尔德

这里的 <TAB> 表示制表符,并不是文件中实际显示的文字。

在记事本中开启自动换行后,这些长行会在窗口边缘折行,导致字段名与字段值之间的对应关系难以辨认。关闭 格式→ 自动换行 后,可以保留完整的逻辑行,但仍需要横向滚动查看。

在记事本中关闭自动换行后查看 Acrobat 导出的 TXT

导出文件中包含有用的数据,但它并不是按字段逐项纵向排列的文本报告。如果希望以更清晰的表格形式查看,可以将 TXT 导入电子表格应用,并选择制表符作为分隔符。如果需要生成便于阅读的“字段名:值”列表,则还需要进一步整理格式。

Acrobat 还提供 选项 → 将数据文件合并到电子表格,用于汇总多份表单的数据。因此,通过界面提取数据并不意味着每次只能处理一份文档。

方法二:使用福昕 PDF 编辑器导出 PDF 表单域数据

福昕 PDF 编辑器提供类似的导出流程:

  1. 打开已填写的 PDF 表单。
  2. 选择表单 → 导出 → 到文件。
  3. 选择 TXT 作为输出格式。
  4. 设置文件名和保存位置,点击保存。

Windows 版使用指南还列出了 CSV、XML、FDF 和 XFDF 等支持的导出格式。表单导出命令适用于交互式表单,而不是普通的静态 PDF。

Foxit 的导出到文件命令

导出结果与 Acrobat 有什么区别?

对于同一份 PDF 示例,福昕 PDF 编辑器导出的 TXT 与 Acrobat 几乎相同:第一行是内部字段名,下一行是对应的值,各项之间使用制表符分隔。关闭自动换行后,结构更容易辨认,但文件本身的排版并未发生变化。

在记事本中关闭自动换行后查看福昕 PDF 编辑器导出的 TXT

这一结论仅针对本次测试的示例,并不意味着两款软件在处理所有表单、使用所有版本或导出设置时,都会生成完全相同的文件。

如果你已经在使用福昕 PDF 编辑器,它是一个实用的替代方案。不过,在本次 TXT 导出场景中,更换编辑器并没有得到更易读的逐字段文本报告。

方法三:使用 C# 提取 PDF 表单域数据

通过代码读取字段,可以自行控制最终文本的组织方式。下面的示例不再沿用表格式的导出布局,而是每行输出一个字段,移除字段名中常见的控件类型后缀,并明确标识复选框的选中和未选中状态。

示例使用 Spire.PDF for .NET 及其 Spire.Pdf.Interactive.Forms 命名空间。该命名空间在 12.10.7 版本中引入,因此请使用此版本或更新的兼容版本。采用其他表单 API 的旧示例可能使用不同的类。

安装类库

创建一个 C# 控制台项目,并安装 NuGet 包:

1
dotnet add package Spire.PDF

将示例 PDF 放到下方代码指定的输入路径,或修改 inputPath,使其指向你自己的文件。程序会将 GetAllValues.txt 写入应用的当前工作目录,并在完成后输出文件的完整路径。

完整 C# 示例

以下代码沿用所提供的提取逻辑,显式引入所需命名空间,使用 UTF-8 编码输出,并支持写入多选列表框中的全部选中值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using Spire.Pdf;
using Spire.Pdf.Interactive.Forms;

namespace ExtractFormFieldValues
{
internal class Program
{
static readonly Regex SuffixRegex = new Regex(
@"\s*(Text\s*Box|Combo\s*Box|Check\s*Box|Formatted\s*Field|List\s*Box)\s*$",
RegexOptions.IgnoreCase);

// 这份示例表单中各语言复选框对应的标签。
static readonly Dictionary<string, string> LanguageMap = new()
{
["Language 1"] = "Deutsch",
["Language 2"] = "English",
["Language 3"] = "Français",
["Language 4"] = "Esperanto",
["Language 5"] = "Latin",
};

static string CleanName(string name)
{
if (string.IsNullOrWhiteSpace(name)) return "";
return SuffixRegex.Replace(name, "").Trim();
}

static string GetCheckBoxValue(PdfCheckBoxField chk, string cleanName)
{
if (!chk.IsChecked) return "Unchecked";

// 对于此模板,如果存在映射,则将通用的 Yes 导出值
// 替换为对应的语言标签。
if (chk.OnValue == "Yes" &&
LanguageMap.TryGetValue(cleanName, out var language))
{
return $"{language} (Checked)";
}

return $"{chk.OnValue} (Checked)";
}

static void Main(string[] args)
{
string inputPath = "FormExample.pdf";
string outputPath = Path.GetFullPath("GetAllValues.txt");

using var doc = new PdfDocument();
doc.LoadFromFile(inputPath);

var form = PdfForm.Create(doc);
if (form == null || form.Fields.Count == 0)
{
Console.WriteLine("No form fields were detected.");
return;
}

var sb = new StringBuilder();

foreach (PdfField field in form.Fields)
{
string name = CleanName(field.Name);
string value = field switch
{
PdfTextField tb => tb.Text,
PdfComboBoxField cb => cb.SelectedValue,
PdfListBoxField lb => string.Join(", ", lb.SelectedValues),
PdfRadioButtonField rb => rb.SelectedValue,
PdfCheckBoxField chk => GetCheckBoxValue(chk, name),
_ => ""
};

sb.AppendLine($"{name}: {value}");
}

File.WriteAllText(outputPath, sb.ToString(), new UTF8Encoding(false));
Console.WriteLine($"Extraction complete: {outputPath}");
}
}
}

提取逻辑说明

程序首先加载 PDF,获取表单容器,然后遍历其中的字段。switch 表达式根据字段类型选择需要读取的值:文本框提供文本内容,选择类控件提供选中项的导出值,复选框则提供选中状态及选中状态对应的导出值。

CleanName 会移除字段名末尾能够识别的后缀。例如,Given Name Text Box 会被简化为 Given Name。这只是针对示例中的命名约定进行处理,并不是从任意 PDF 中还原字段旁可见标签的通用方法。

复选框需要进一步解释。Yes 这样的导出值本身可能完全有效,但无法说明 Language 2 代表英语还是其他语言。字典为这份特定模板补充了这些信息。处理其他表单时,需要配置相应的映射,除非字段自身的导出值已经提供了有意义的标签。

需要注意,OnValue 为 Yes 并不能证明表单作者没有设置自定义值。代码只是在处理已配置映射的语言字段时,将其视为一个通用值。

输出示例

对于已填写的示例表单,生成的文本可以直接阅读:

C# 导出的 TXT 与已填写的 PDF 对照,显示易读的字段名、字段值和复选框状态

本示例保留 form.Fields 返回的字段顺序,并不会按照页面的阅读顺序重新排序。其他 PDF 可能返回不同的顺序;如果需要固定的报告顺序,应显式配置字段排列规则。

处理其他表单时的限制与调整

此示例演示了从常见 AcroForm 值字段中提取内容。它未实现 XFA 字段提取或签名详情处理。Spire.PDF 提供了用于访问 XFA 字段的独立 API,这些 API 需要不同的提取工作流程。

选择类控件保存的导出值可能与界面中显示的选项标签不同。如果需要输出易读的标签,应检查选项定义并添加相应的转换逻辑。多行文本字段本身也可能包含换行符,因此一个字段在输出文件中可能占用多行。

处理多份 PDF 时,可以在文件循环中调用相同的提取逻辑。需要事先确定,是为每份文档生成独立的 TXT,还是合并输出并添加清晰的文件名标题。批量处理属于本示例的扩展方向,当前单文件程序尚未实现这一功能。

你可能还感兴趣: 使用 C# 在 PDF 中创建可填写表单

应该选择哪种方法?

需求 Acrobat 福昕 PDF 编辑器 C# 示例
通过图形界面导出 支持 支持 需要编写程序
本次测试的 TXT 排版 以制表符分隔字段名和字段值 与 Acrobat 类似 按“字段名:值”逐项输出
简化内部字段名 需要额外处理 需要额外处理 已支持移除能够识别的后缀
添加特定模板的语言标签 需要额外处理 需要额外处理 通过映射实现
自定义输出规则 受导出流程限制 受导出流程限制 由代码控制
在更大的工作流中重复执行 取决于应用提供的工具 取决于应用提供的工具 可扩展为批量运行或系统集成

如果只需要快速导出,并且可以接受后续使用表格形式处理数据,可以选择 Acrobat 或福昕 PDF 编辑器。如果 TXT 本身就是最终交付文件,或者需要控制字段名称、解释复选框含义,以及保持一致的输出格式,则更适合使用 C# 方案。

常见问题

为什么导出的 TXT 在记事本中看起来比较混乱?

在本次 Acrobat 和福昕 PDF 编辑器的测试结果中,字段名和字段值分别位于不同的长行中,各项之间使用制表符分隔。自动换行会在视觉上拆分这些长行,使对应关系难以辨认。关闭自动换行便于检查;以制表符为分隔符导入电子表格后,可以得到更清晰的表格视图。

这些方法能提取扫描表单中的填写内容吗?

如果 PDF 只包含扫描图片,就无法通过原来的表单域提取数据。此时需要 OCR,并通过额外流程将识别出的填写内容与对应标签关联起来。

为什么选中的复选框返回 Yes,而不是页面上的选项标签?

复选框保存的选中状态导出值可能只是 Yes,而选项标签是页面上的独立文本。可以针对具体模板建立映射,将字段与有意义的标签关联起来,示例中的语言复选框就采用了这种做法。

C# 代码会修改原始 PDF 吗?

代码不会将更改保存到 PDF。它只加载文件、读取字段,并写入一个独立的 TXT 文件。

同样的数据能写入 CSV 或 JSON 吗?

可以。保留字段读取逻辑,将 TXT 写入步骤替换为合适的序列化方式即可。输出 CSV 时,应正确转义逗号、引号和换行符;输出 JSON 时,应使用序列化器,而不是手动拼接 JSON 字符串。