惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
美团技术团队
Apple Machine Learning Research
Apple Machine Learning Research
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
WordPress大学
WordPress大学
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
博客园 - Franky
博客园 - 司徒正美
酷 壳 – CoolShell
酷 壳 – CoolShell
爱范儿
爱范儿
Jina AI
Jina AI
Last Week in AI
Last Week in AI
雷峰网
雷峰网
IT之家
IT之家
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园 - 聂微东
小众软件
小众软件
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
V2EX

博客园 - Parry

PDF 多格式解析如何避免混用输出:TEXT、HTML、XML 与 TAG 数据契约 基金组合风险如何避免“一个分数说风险”:样本覆盖、VaR 与风险贡献 RAG 问答如何证明答案来自文档:知识库版本、引用片段与线程隔离 SEO 排名监控如何避免单次快照误判:SERP 任务、credits 与历史对比 ETF 盘中看板如何处理分钟行情:时间窗口、新鲜度与缺口标记 节气日历服务如何统一日期口径:时区、历法事实与文化参考分层 国际号码接入校验台案例方案 户外项目日照与节气计划台案例方案 门店二维码资产管理台案例方案 用传统历法宜忌接口构建节气日历服务 全球区域与 IP 定位工作台案例方案 基金组合风险分析台案例方案 A 股公告与科创板研究台案例方案 搜索可见性与 SEO 观测台案例方案 研究生招生信息决策台案例方案 微信资讯素材采编中心案例方案 多语言语料标注与实体分析台案例方案 智能文档字段提取工作台功能需求文档 SEO 自动巡检怎么做:用 PageSpeed、DNS、SSL 与 WHOIS 定位网站问题 咕咕监控 3.2.0:网页有重要变化时,第一时间告诉你 「鸭川小记」:让语音先流动起来,再慢慢变成可整理的内容 个人公开市场研究笔记功能需求文档 网页归档与报告生成系统功能需求文档 网站工具与内容转换台功能需求文档 全球大学排名查询网站功能需求文档 汽车车型内容资料库功能需求文档 资讯元数据管理平台功能需求文档 内容质检与纠错工作台功能需求文档 文本 NLP 分析平台功能需求文档 企业文档摘要翻译台功能需求文档
Python 接入 OCR:把图片文字整理成可校验的 JSON 字段
Parry · 2026-08-18 · via 博客园 - Parry

Python 接入 OCR:把图片文字整理成可校验的 JSON 字段

标签建议:Python、OCR、API、文档处理

OCR 接口返回文字后,项目才刚走完一半。真正进入数据库之前,还要解决文本为空、字段缺失、类型错误和结果不可追踪的问题。本文给出一个 Python 标准库方案:先调用 OCR 文字识别 API 恢复文本,再按 JSON Schema 抽取业务字段。

OCR 文字识别

1. 准备环境变量

不要把 AppKey 写进代码或提交到仓库:

export GUGUDATA_APPKEY='your-app-key'

2. 调用 OCR 接口

OCR 请求使用表单编码,图片 URL 放在 imageurl 字段中:

import json
import os
from urllib.parse import urlencode
from urllib.request import Request, urlopen


def recognize_image(image_url: str) -> list[str]:
    app_key = os.environ["GUGUDATA_APPKEY"]
    url = (
        "https://api.gugudata.com/imagerecognition/ocr"
        f"?{urlencode({'appkey': app_key})}"
    )
    body = urlencode({"imageurl": image_url}).encode("utf-8")
    request = Request(
        url,
        data=body,
        headers={"Content-Type": "application/x-www-form-urlencoded"},
        method="POST",
    )

    with urlopen(request, timeout=30) as response:
        payload = json.load(response)

    status = payload.get("DataStatus", {})
    if int(status.get("StatusCode", 0)) != 100:
        raise RuntimeError(status.get("StatusDescription", "OCR failed"))

    lines = payload.get("Data", {}).get("ResultText", [])
    if not lines:
        raise ValueError("OCR returned no text lines")
    return lines

这里有一个容易忽略的点:HTTP 200 不等于识别成功。还要检查 DataStatus.StatusCode,并验证 ResultText 不是空数组。

3. 规范化文本

OCR 返回的是文本行数组。进入字段抽取前,可以做最小化规范化,但不要随意删除标点或合并所有空格,否则可能破坏金额、编号和表格语义。

def normalize_lines(lines: list[str]) -> str:
    normalized = [line.strip() for line in lines if line.strip()]
    return "\n".join(normalized)

4. 用 Schema 约束字段

例如从采购截图中提取项目名称、项目编号和预算金额:

{
  "type": "object",
  "properties": {
    "projectName": {"type": "string"},
    "projectCode": {"type": "string"},
    "budgetAmount": {"type": "number"}
  },
  "required": ["projectName", "projectCode"]
}

规范化文本可以继续提交给 文档字段抽取 API。这样 OCR 负责“读字”,Schema 负责“交付结构”,两层失败也能分别记录。

5. 把失败分开处理

生产代码至少要区分:

  • 网络超时或非 2xx:有限次数重试,并采用退避策略;
  • 业务状态不为 100:记录状态描述,进入失败队列;
  • 文本为空或字段缺失:进入人工复核;
  • 金额、日期等类型不合法:阻止写入正式表。

如果输入是 PDF,不要先截图再逐页 OCR。可以直接使用 PDF 转文本 API 恢复连续文本,再复用相同的 Schema 抽取和校验步骤。

关键不是把三个接口简单串起来,而是让每一步都有明确输入、输出、状态和可重放证据。