展开本页目录
开始前准备什么
- Python、pypdf、OpenAI SDK 与 jsonschema
- 不含受限数据的、未加密且有文字层的 PDF
- 确认当前模型能处理每页文本,并设输入预算
- 本地读文字层
- 按页提取
- 验证引文和值
- 人工核对入库
本地预检、页码、Schema、原文证据验证、逐页 usage。
这份流程处理文字层,不是 OCR
可选中复制的数字 PDF 通常适合先用 pypdf 读取文字。扫描页可能只有图片,pypdf 不会识别图片文字;抽出空文本时,标记需要 OCR 或人工处理,不继续要求模型猜内容。
部分 PDF 的列顺序、页眉或表格会在抽取后混乱,即便文本不为空也要抽查原页面。本示例输出页面序号,指 PDF 文件第几页,不假定等于印刷在页脚的页码。
本地提取与模型提取分开保存
| 文件 | 用途 | 何时生成 |
|---|---|---|
| pdf-page-text.json | 每页文本、文件页号与可处理状态 | 本地抽取后 |
| pdf-fields.json | 字段值、短引文、页号、状态与 usage | 模型逐页返回后 |
| 原始 PDF | 核对排版、表格关系及实际含义 | 人工验收时 |
- 文件
- pdf-page-text.json
- 用途
- 每页文本、文件页号与可处理状态
- 何时生成
- 本地抽取后
- 文件
- pdf-fields.json
- 用途
- 字段值、短引文、页号、状态与 usage
- 何时生成
- 模型逐页返回后
- 文件
- 原始 PDF
- 用途
- 核对排版、表格关系及实际含义
- 何时生成
- 人工验收时
先只在本地提取,再决定是否调用
下载脚本后先运行 --extract-only,这一步不会发送 API 请求。检查 pdf-page-text.json 中页面是否可读,再设置 Key 与模型运行模型提取;文本会发送到配置的网关和上游。
bash
python -m pip install -U pypdf openai jsonschema
python developer-pdf-extraction.py invoice.pdf --extract-only
# 人工检查 pdf-page-text.json 后再配置 Key 和模型
python developer-pdf-extraction.py invoice.pdf文字层提取的完整最小示例
这段可以独立执行,先判断每页是否存在可提取文字。完整下载版还包含输入限制、模型提取、Schema 与原文引文验证;没有截断后假装处理完整文档。
python
import json
from pathlib import Path
from pypdf import PdfReader
reader = PdfReader("invoice.pdf")
if reader.is_encrypted:
raise ValueError("请先用授权方式处理加密文档")
pages = []
for number, page in enumerate(reader.pages, 1):
text = (page.extract_text() or "").strip()
pages.append({"page": number, "text": text,
"status": "text_ready" if text else "needs_ocr_or_review"})
Path("pdf-page-text.json").write_text(
json.dumps(pages, ensure_ascii=False, indent=2), encoding="utf-8")
print("已本地保存;本步骤未调用模型")字段契约:值、短引文、所在页
下载版按页提取 seller、total、date。每个字段保存 value 和 quote;找不到时 value=null、quote 为空字符串。值要求原样复制,不改写金额,不推算日期,也不合并另一页的内容。
本地检查 quote 能否在该页原文定位、value 是否在 quote 中。通过只代表有可定位文字,仍不保证选中的是应付总额而不是税额。字段含义与表格关系继续由人工核验。
json
{
"page": 1,
"fields": {
"seller": {"value": "示例商店", "quote": "销售方:示例商店"},
"total": {"value": "128.50", "quote": "合计应付:128.50 元"},
"date": {"value": null, "quote": ""}
},
"status": "evidence_located_needs_human_review"
}演示限制与长文扩展
- 下载版限制 10 MB、20 页、每页 20,000 字符;这些是示例保护值,不是模型容量。
- 长页先按可解释段落分块,并保留页号与段落编号,不默默截断文件。
- 跨页表格、合并单元格与多种金额需增加业务规则,不能只靠字段类型。
- 多文档提取保留 file_id 和文件哈希,避免同名文件混用证据。
- PDF 可含图片、注释或复杂内容;处理不可信文件应在隔离环境中进行。
失败页保留,重试前先核对记录
空文本进入 OCR 或人工队列。JSON、Schema、引文校验失败进入失败队列;已有成功页继续保留。网络超时可能已在上游执行,先查控制台后决定是否重发某页。
脚本会逐次保存结果与 usage,运行第二次并不自动跳过第一页,可能再次计费。正式批量系统需要持久化文档页状态与显式重试策略。
怎样确认已经完成
- 扫描页被标记需要 OCR,不伪造空页字段
- 文件页号、原文与每项引文可对应
- 未知日期为 null,金额不被推算或改写
- 通过定位后再核对总额含义与原始 PDF
常见问题
扫描 PDF 可以直接用这个脚本吗?
文字层提取不等于 OCR。纯图片扫描页需要先识别文字,或另选经过验证的视觉处理方案。
引文能找到,就能自动入库吗?
不能。金额类别、表格关系和文档身份仍可能选错,需要业务验证与人工抽查。