ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Eigent PDF 表单填写技能实战:从可填写字段判定到注解式填充的完整技术路径

2026/9/14 16:07:00 拓冰建站 浏览量
Eigent PDF 表单填写技能实战:从可填写字段判定到注解式填充的完整技术路径 Eigent PDF 表单填写技能实战从可填写字段判定到注解式填充的完整技术路径【免费下载链接】eigentEigent: The Open Source Cowork Desktop - Local and Free Alternative to Claude Cowork and Codex项目地址: https://gitcode.com/GitHub_Trending/ei/eigent本文以 Eigent 仓库中 PDF 技能的核心文档 forms.md 为主体完整讲解 Agent 填写 PDF 表单的两条技术路径针对带 AcroForm 可填写字段的 PDF 走字段提取—值校验—表单写入流程针对扫描件/图片型 PDF 走结构提取或视觉估测—坐标校验—FreeText 注解写入流程。读完后你能掌握 scripts 目录下全部 7 个配套脚本的用法、各中间 JSON 的字段含义以及两套坐标系PDF 坐标、图像像素坐标的转换原理与源码实现细节。1. forms.md 在 PDF 技能中的定位与总体流程Eigent 仓库内置了一个示例 PDF 处理技能入口文档 SKILL.md 在Quick Reference中明确将填写 PDF 表单这一任务指向 FORMS.mdFill PDF forms | pdf-lib or pypdf (see FORMS.md)。因此 forms.md 是 Agent 在执行帮我填这张 PDF 表单类任务时的操作性手册其核心设计是一个先判定、再分叉的流程第一步永远是运行 check_fillable_fields.py 检查 PDF 是否带有可填写fillable表单字段有可填写字段 → 走Fillable fields路径结构化写入表单域无可填写字段 → 走Non-fillable fields路径添加文本注解先尝试从 PDF 结构提取坐标失败再回退到视觉估测。forms.md 开篇特别强调必须按顺序执行步骤不要跳步直接写代码CRITICAL: You MUST complete these steps in order. Do not skip ahead to writing code这是为了保证坐标来源可信、避免凭感觉写死坐标。1.1 第一步判定是否存在可填写字段在 forms.md 所在目录执行python scripts/check_fillable_fields file.pdf从源码看check_fillable_fields.py 的实现极简用 pypdf 的PdfReader读取文件后调用reader.get_fields()有返回值则打印This PDF has fillable form fields否则打印This PDF does not have fillable form fields; you will need to visually determine where to enter data。也就是说判定依据就是 PDF 是否存在 AcroForm 字段字典后续所有分支都以此输出为准。2. 路径一可填写表单字段Fillable fields当 PDF 有可填写字段时按以下四步执行所有脚本均从 forms.md 所在目录即resources/example-skills/pdf运行。2.1 提取字段信息python scripts/extract_form_field_info input.pdf field_info.json该命令生成一个 JSON 文件列出所有字段。原文档定义的字段格式按类型分为四类[ { field_id: (字段的唯一 ID), page: (页码从 1 开始), rect: ([left, bottom, right, top] 边界框PDF 坐标y0 为页面底部), type: (\text\、\checkbox\、\radio_group\ 或 \choice\) }, // 复选框额外带 checked_value 与 unchecked_value { field_id: (字段的唯一 ID), page: (页码从 1 开始), type: checkbox, checked_value: (把字段设为该值即勾选), unchecked_value: (把字段设为该值即取消勾选) }, // 单选组带 radio_options 列表 { field_id: (字段的唯一 ID), page: (页码从 1 开始), type: radio_group, radio_options: [ { value: (把字段设为该值即选中此单选项), rect: (该单选按钮的边界框) } // ...其他单选选项 ] }, // 下拉/多选字段带 choice_options 列表 { field_id: (字段的唯一 ID), page: (页码从 1 开始), type: choice, choice_options: [ { value: (把字段设为该值即选中此选项), text: (选项的显示文本) } // ...其他选项 ] } ]结合 extract_form_field_info.py 源码可以补充几个关键实现事实类型映射make_field_dict 将 PDF 字段类型/Tx映射为text、/Btn映射为checkbox、/Ch映射为choice无法识别的类型会标记为unknown (…)。复选框取值复选框的checked_value/unchecked_value来自字段的状态表/_States_当两个状态中不含/Off时脚本会打印提示勾选/取消值可能不正确建议对结果做视觉确认——这是一个明确的降级告警遇到时应核对输出 PDF。单选组的来源radio_group 的组装逻辑 并不是直接读字段而是遍历每一页的/Annots注释凡是属于带/Kids的/Btn父字段、且每个注释的外观字典/AP/N中恰有一个非/Off值的就被归入同一radio_groupvalue取自该注释的 on 值rect取自注释的/Rect。排序规则最终字段列表按页码 → 自上而下 → 自左而右排序排序键为[page, -y, x]方便 Agent 按阅读顺序理解表单。位置缺失的处理无法从注释定位的字段会被跳过并打印Unable to determine location for field id: …, ignoring若字段信息中出现此类提示说明该字段在 JSON 中缺失需要人工确认是否影响填写。2.2 将 PDF 转为 PNG 并分析字段用途python scripts/convert_pdf_to_images file.pdf output_directory该脚本把每一页渲染为一张 PNG。从 convert_pdf_to_images.py 源码看渲染使用pdf2image的convert_from_path(pdf_path, dpi200)即200 DPI若任一维度超过max_dim1000像素会等比缩放到 1000 像素以内再保存为page_1.png、page_2.png……原文档在此步的要求是分析这些图像以确定每个表单字段的用途务必把 bounding box 的 PDF 坐标转换为图像坐标。注意可填写路径的rect是标准 PDF 坐标y0在页面底部而图像坐标y0在页面顶部直接照抄会导致字段上下颠倒这是本流程中最常见的错误来源之一。2.3 编写 field_values.json确定每个字段的值后创建field_values.json原文档给出的格式如下[ { field_id: last_name, description: 用户的姓氏, page: 1, value: Simpson }, { field_id: Checkbox12, description: 用户年满 18 岁时勾选的复选框, page: 1, value: /On } // ...更多字段 ]约束条件field_id必须与extract_form_field_info.py输出中的field_id完全一致page必须与字段信息 JSON 中该字段的page值一致复选框要勾选时使用其checked_value的值如/On单选组则使用radio_options中某个选项的value。2.4 执行填充python scripts/fill_fillable_fields.py input.pdf field_values.json output.pdf原文档说明该脚本会校验你提供的字段 ID 和值是否有效若打印错误信息应修正对应字段后重试。源码层面fill_fillable_fields.py 的校验覆盖三类错误任一命中即打印ERROR: …并以退出码 1 终止字段 ID 不存在ERROR: … is not a valid field ID页码不匹配ERROR: Incorrect page number for … (got X, expected Y)取值非法validation_error_for_field_value复选框的值必须等于checked_value或unchecked_value单选组/下拉字段的值必须在其选项值列表内。写入阶段fill_pdf_fields使用PdfWriter(clone_fromreader)克隆原文件按页调用update_page_form_field_values(..., auto_regenerateFalse)更新字段值最后set_need_appearances_writer(True)设置 NeedAppearances 标志——含义是由 PDF 阅读器在打开时重新生成字段外观因此建议填写完成后用阅读器打开输出 PDF 做一次视觉确认。此外脚本还包含一个对 pypdf 内部get_inherited的 monkey patchL88-L101用于修复/Opt选项数组以[值, 显示文本]二元组形式继承时的解析问题属于 pypdf 兼容层补丁使用时无需干预。3. 路径二非可填写 PDFNon-fillable fields注解式填充当 PDF 没有可填写表单字段时填写方式变为在指定坐标叠加文本注解。原文档的策略是先从 PDF 结构提取坐标更精确结构不可用时再回退到视觉估测。3.1 Step 1先尝试结构提取python scripts/extract_form_structure input.pdf form_structure.json该命令创建form_structure.json包含四部分内容labels每个文本元素及其精确坐标x0, top, x1, bottom单位 PDF pointlines定义行边界的水平线checkboxes作为复选框的小方形矩形带中心坐标row_boundaries由水平线计算出的各行上/下边界。从 extract_form_structure.py 源码可以确认三类元素的提取规则基于 pdfplumber元素提取规则labelspage.extract_words()的每个词坐标四舍五入到 0.1 ptlinespage.lines中长度超过页宽50%的水平线checkboxespage.rects中边长同时落在5–15 pt区间、且宽高中差异 2 pt的近正方形矩形输出含center_x/center_yrow_boundaries每页内所有水平线 y 值去重排序后相邻两条线构成一行边界并给出row_height结果判定如果form_structure.json里有有意义的 labels对应表单字段的文本元素使用Approach A结构坐标如果 PDF 是扫描/图片型、几乎没有标签例如文本全部显示为(cid:X)之类的编码模式则使用Approach B视觉估测。3.2 Approach A结构坐标首选A.1 分析结构读取form_structure.json识别——标签分组相邻文本元素可能组成一个完整标签如 Last Name行结构top值相近的标签位于同一行字段列输入区从标签结束后开始x0 label.x1 间隙;复选框直接使用结构中的复选框坐标。原文档在此处声明的坐标系是y0 位于页面顶部y 向下增大这正是 pdfplumber 的坐标系与可填写路径中 PDF 注释的/Rect坐标系方向相反两条路径不要混用。A.2 检查缺失元素结构提取可能漏检部分表单元素常见情况包括——圆形复选框只有方形矩形会被识别为 checkbox、复杂图形装饰元素或非标准控件、颜色较浅的元素。如果 PDF 图像中能看到结构 JSON 里没有的字段对这些字段单独走视觉分析见混合方案。A.3 创建使用 PDF 坐标的 fields.json文本字段entry x0 标签 x1 5标签后的小间隙entry x1 下一个标签的 x0或行边界entry top 标签 topentry bottom 标签下方行边界线或标签 bottom row_height复选框直接使用form_structure.json中的矩形坐标entry_bounding_box [checkbox.x0, checkbox.top, checkbox.x1, checkbox.bottom]。pages中写入pdf_width和pdf_height以此声明坐标是 PDF 坐标。原文档的完整示例{ pages: [ {page_number: 1, pdf_width: 612, pdf_height: 792} ], form_fields: [ { page_number: 1, description: 姓的输入字段, field_label: Last Name, label_bounding_box: [43, 63, 87, 73], entry_bounding_box: [92, 63, 260, 79], entry_text: {text: Smith, font_size: 10} }, { page_number: 1, description: US Citizen Yes 复选框, field_label: Yes, label_bounding_box: [260, 200, 280, 210], entry_bounding_box: [285, 197, 292, 205], entry_text: {text: X} } ] }要点直接使用form_structure.json的pdf_width/pdf_height与坐标复选框通常用{text: X}这样的短文本表达勾选。A.4 校验边界框python scripts/check_bounding_boxes fields.json3.3 Approach B视觉估测回退方案B.1 PDF 转图python scripts/convert_pdf_to_images input.pdf images_dir/B.2 初步识别字段逐页观察图像识别表单分区并给出各字段的粗略估计位置——字段标签及其大致位置、输入区横线、方框或留白、复选框及其大致位置。每个字段记录近似像素坐标此阶段不必精确。B.3 放大精修精度关键步骤对每个字段裁剪估计位置附近的区域来精确化坐标。使用 ImageMagick 创建放大裁剪magick page_image -crop widthxheightxy repage crop_output.png其中x, y是裁剪区域左上角取粗略估计值减去边距width, height是裁剪区域大小字段区域每侧加约 50px 边距。原文档的示例——精修估计在 (100, 150) 附近的 Name 字段magick images_dir/page_1.png -crop 300x8050120 repage crops/name_field.png若magick命令不可用可用相同参数改用convert。观察裁剪图确定精确坐标1) 输入区的确切起点标签之后2) 输入区终点下一字段或边缘之前3) 输入线/框的上下边界。然后把裁剪内坐标换算回整图坐标full_x crop_x crop_offset_xfull_y crop_y crop_offset_y例如裁剪起点为 (50, 120)、裁剪图内输入框起点为 (52, 18)则entry_x0 52 50 102entry_top 18 120 138。对每个字段重复此过程相邻字段可合并到同一次裁剪中处理。B.4 创建使用精修坐标的 fields.jsonpages中改用image_width/image_height以此声明坐标是图像像素坐标并填入放大分析得到的精修像素坐标{ pages: [ {page_number: 1, image_width: 1700, image_height: 2200} ], form_fields: [ { page_number: 1, description: 姓的输入字段, field_label: Last Name, label_bounding_box: [120, 175, 242, 198], entry_bounding_box: [255, 175, 720, 218], entry_text: {text: Smith, font_size: 10} } ] }要点image_width/image_height必须与 convert_pdf_to_images.py 实际输出图像的像素尺寸一致注意脚本会把超过 1000px 的图缩放务必读实际保存后的尺寸而非 200 DPI 原始渲染尺寸。B.5 校验边界框python scripts/check_bounding_boxes fields.json3.4 混合方案结构 视觉当结构提取对大多数字段有效、但漏掉个别元素如圆形复选框、非常规控件时使用对form_structure.json中已检测到的字段用Approach A将 PDF 转为图像对缺失字段做视觉分析对缺失字段使用放大精修Approach B 的 B.3合并坐标结构提取来的字段用pdf_width/pdf_height视觉估测的字段必须把图像坐标换算为 PDF 坐标——pdf_x image_x * (pdf_width / image_width)pdf_y image_y * (pdf_height / image_height)fields.json 中只使用一套坐标系——全部换算为 PDF 坐标并声明pdf_width/pdf_height。4. 统一校验与收尾4.1 Step 2填充前必做校验python scripts/check_bounding_boxes fields.jsoncheck_bounding_boxes.py 做两类检查边界框相交同页内任意两个label_bounding_box或entry_bounding_box含同字段的 label 与 entry 之间发生交集即报FAILURE: intersection between …——相交意味着填充后文本会重叠框高不足entry 框高度rect[3] - rect[1]小于entry_text.font_size未指定时按 14 计算即报FAILURE: entry bounding box height … is too short …。全部通过时输出SUCCESS: All bounding boxes are valid错误信息累计到 20 条即中止后续检查提示先修正再重试。有报错必须先修正fields.json再继续。4.2 Step 3执行填充python scripts/fill_pdf_form_with_annotations.py input.pdf fields.json output.pdf填充脚本会自动识别坐标系并完成换算。从 fill_pdf_form_with_annotations.py 源码看其换算逻辑按页读取 PDF 实际 MediaBox 尺寸若该页声明了pdf_width调用 transform_from_pdf_coords——因为输入框是[x0, top, x1, bottom]y 向下需翻转成 pypdf 的[left, bottom, right, top]y 向上bottom pdf_height - 输入bottomtop pdf_height - 输入top若声明的是image_width调用 transform_from_image_coords——先按pdf/image比例缩放 x、y再做同样的 y 轴翻转文本通过pypdf.annotations.FreeText注解写入默认fontArial、font_size14加pt后缀、font_color000000且border_color与background_color均为None即无描边无底色视觉上不破坏原表单外观没有entry_text.text或文本为空的字段会被静默跳过成功后打印Successfully filled PDF form and saved to …与实际添加的注解数量。4.3 Step 4验证输出python scripts/convert_pdf_to_images output.pdf verify_images/将填充后的 PDF 转成图像逐页核对文本落点。若文本位置偏移按路径排查Approach A确认使用的是form_structure.json的 PDF 坐标且pages声明的是pdf_width/pdf_heightApproach B确认image_width/image_height与实际图像像素尺寸一致、坐标是精修后的像素值混合方案确认视觉估测字段的图像→PDF 坐标换算正确。5. 配套脚本与实现速查脚本作用核心实现check_fillable_fields.py判定是否有可填写字段pypdfget_fields()非空性检查extract_form_field_info.py导出字段 ID/类型/页码/矩形解析/FT、/States、/Kids、/Annots、/AP/Nconvert_pdf_to_images.pyPDF 每页转 PNGpdf2image200 DPI超 1000px 等比缩放extract_form_structure.py导出标签/横线/复选框/行边界pdfplumber 的extract_words/lines/rects含 5–15pt 方形与 50% 页宽横线规则check_bounding_boxes.py校验边界框相交与框高同页两两相交检测 框高 ≥ 字号默认 14fill_fillable_fields.py写入可填写表单域三重校验后update_page_form_field_values NeedAppearancesfill_pdf_form_with_annotations.py注解式填充坐标系统自动识别、y 轴翻转、FreeText 注解6. 实战注意事项两条路径的坐标系方向不同可填写路径的rect是 PDF 原生坐标y0在底部来自注释/Rect注解路径的结构坐标是y0在顶部pdfplumber 坐标系由填充脚本在写入时统一翻转。混用方向是文字上下颠倒的最常见原因。所有脚本必须在resources/example-skills/pdf目录下运行forms.md 反复强调 run from this files directory且 fill_fillable_fields.py 通过相对导入复用extract_form_field_info.get_field_info换目录执行会直接报 ImportError。依赖Python 侧需要pypdf、pdfplumber、pdf2image后者依赖 poppler 渲染环境Approach B 的放大精修依赖 ImageMagickmagick或旧版convert。字段用途必须靠图像确认field_id往往语义不明如Checkbox12forms.md 要求转图后分析图像以确定每个字段的用途——不要仅凭 ID 名称猜测。降级告警要当回事复选框状态异常、字段无法定位时两个提取脚本都会打印提示此时应人工核对输出 PDF 或改走视觉估测。更广泛的 PDF 处理背景合并、拆分、文本/表格提取、命令行工具可继续参考同目录的 SKILL.md 与 reference.md本文聚焦的表单填写流程以 forms.md 及其 scripts 目录下的实现为准。【免费下载链接】eigentEigent: The Open Source Cowork Desktop - Local and Free Alternative to Claude Cowork and Codex项目地址: https://gitcode.com/GitHub_Trending/ei/eigent创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考