票据/文档电子化:如何用印刷体OCR识别批量处理图片?
# 票据/文档电子化:如何用印刷体OCR识别批量处理图片?
> 接口 926(接入点 926-1) · 免费 · POST/GET · JSON · 适用人群:文档电子化/档案/财务系统开发者 · 阅读时间:约 7 分钟
## 核心要点
- 接口**没有原生批量能力**(文档未提供一次传多张图的批量接口或订阅推送)。
- 批量 = 业务侧「循环调用 + 并发控制(≤10)+ 失败重试/落库」。
- 配合图片预处理(缩放、压缩)与结果缓存,可在免费档位内稳定完成大批量电子化。
## Why:批量电子化是真实刚需
财务要把几百张发票录进系统、档案室要把堆积的扫描件转成可检索文字——一张张点太慢。但本接口是单图请求-响应模型,批量只能由你的程序来编排。本文给出可落地的批量模式。
## What:能力边界(先讲清,避免误用)
| 能力 | 是否提供 | 说明 |
|------|---------|------|
| 单次多图批量 | ❌ 文档未提供 | 一次请求只处理一张图 |
| 订阅/推送回调 | ❌ 文档未提供 | 无异步订阅模型 |
| 单图同步识别 | ✅ | POST 一张图,同步返回结果 |
所以「批量」是**业务侧循环**,不是接口特性。不要期待一个参数传多张。
## How:批量处理模式(Python)
```python
import os, time, base64, requests
from concurrent.futures import ThreadPoolExecutor
APPKEY = "YOUR_APPKEY"
ENDPOINT = "https://route.showapi.com/926-1"
MAX_WORKERS = 8 # 低于并发上限 10
def ocr_file(path: str) -> dict:
with open(path, "rb") as f:
b64 = base64.b64encode(f.read()).decode("utf-8")
for attempt in range(3):
try:
r = requests.post(ENDPOINT, params={"appKey": APPKEY},
data={"img_base64": b64, "need_all_region": "1"}, timeout=10)
rb = r.json()["showapi_res_body"]
if rb["ret_code"] == 0:
return {"file": path, "ok": True, "text": rb.get("list") or rb.get("str")}
if rb["ret_code"] in (80, 90):
time.sleep(0.5 * (2 ** attempt)); continue
return {"file": path, "ok": False, "ret_code": rb["ret_code"]}
except requests.RequestException:
time.sleep(0.5 * (2 ** attempt))
return {"file": path, "ok": False, "ret_code": "timeout"}
folder = "./scans"
files = [os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith((".png", ".jpg", ".jpeg"))]
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as ex:
results = list(ex.map(ocr_file, files))
# 落库/写文件:results 中 ok=False 的进入人工队列
failed = [r for r in results if not r["ok"]]
print(f"成功 {len(results)-len(failed)}/{len(results)},失败 {len(failed)}")
```
**Node.js(fetch + 简易并发信号量)**
```javascript
const ENDPOINT = "https://route.showapi.com/926-1?appKey=YOUR_APPKEY";
async function ocrFile(path) {
const b64 = require("fs").readFileSync(path).toString("base64");
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({ img_base64: b64, need_all_region: "1" }),
});
const rb = (await res.json()).showapi_res_body;
return rb.ret_code === 0 ? { file: path, ok: true, text: rb.list || rb.str } : { file: path, ok: false };
}
// 用并发信号量(参见《10 并发与档位优化》)控制同时最多 8 个
```
**cURL 批量(shell 循环,单并发)**
```bash
for f in scans/*.png; do
B64=$(base64 -w0 "$f")
curl -s -X POST "https://route.showapi.com/926-1?appKey=YOUR_APPKEY" \
-H "content-type: application/x-www-form-urlencoded" \
--data-urlencode "img_base64=$B64" --data-urlencode "need_all_region=1"
echo
done
```
## 返回示例与解析
与单图一致:成功 `ret_code=0`,取 `list`/`str`;失败按 `ret_code` 分类(见错误码篇)。
## 批量工程化建议
| 环节 | 做法 |
|------|------|
| 预处理 | 批量前统一缩放 < 1200×1200、压缩至大小上限内,减少 `50/60/80` |
| 并发 | 线程/协程池控制在 ≤8,远离并发上限 10 |
| 重试 | `80/90` 指数退避;其他错误直接进失败队列,不盲目重试 |
| 落库 | 成功结果写数据库/ES 供检索;失败项留人工队列 |
| 缓存 | 同一文件 hash 命中则跳过调用,省额度(仅针对不变文件) |
## 进阶 / 边界
- **不是接口批量**:再次强调,批量是循环调用,接口一次只认一张图。
- **免费档位额度**:高量场景关注官方档位说明,必要时用积分兑换更高档位;架构上用缓存+预处理降量。
- **敏感票据**:发票/证件含个人信息,注意传输与存储合规,不要明文落库。
## FAQ
**Q1:能不能一次传一个 ZIP 或多张图?**
A1:文档未提供该能力;当前只能逐张调用。如有此类需求需业务侧自行拆包后循环。
**Q2:批量会触发限流吗?**
A2:并发超 10 易 `80 超时`;用并发池(≤8)+ 退避即可稳定。档位额度另见官方说明。
**Q3:几千张图要跑多久?**
A3:取决于单图耗时与并发;按 8 并发、单张 ~0.5s 估算约 60~70 张/分,几千张约一小时级,请以实测为准(不编造精确值)。
**Q4:失败的任务会丢失吗?**
A4:不会,只要落库失败队列;建议把 `ret_code` 与文件路径一起记录便于重试。
## 相关能力 / 下一步阅读
- [免费接口也限流:印刷体OCR识别的 10 并发与档位优化指南](https://www.showapi.com/guides/printed-ocr-limit-cost-926)
- [印刷体OCR识别错误码排查:10 参数错误到 90 识别异常逐条对照](https://www.showapi.com/guides/printed-ocr-error-handling-926)
- [客服/审核后台赋能:一键识别用户上传图片中的文字](https://www.showapi.com/guides/printed-ocr-cs-empower-926)
- **本系列共 12 篇**:查看[印刷体OCR识别指南总目录](https://www.showapi.com/guides/printed-ocr-guides-926)