适用场景
在日常企业信息化流程中,火车票信息的电子化录入是一项高频、重复且容易出错的工作。无论是财务部门处理员工报销,还是个人管理出行记录,手工录入票面信息(出发站、到达站、车次、座位、票价、身份证号等)都耗时费力。借助 OCR(光学字符识别)技术,通过一个简单的 HTTP 请求即可将火车票图片转换为结构化数据,直接对接报销系统、ERP 或行程管理应用。
典型场景包括:
- 差旅费报销自动录入:员工上传票据图片,系统自动提取票面字段,生成报销单草稿。
- 行程管理与统计:自动汇总个人或团队的出行记录,分析交通维护复杂度。
- 票据核对与验证:将识别结果与购票订单或发票进行比对,减少人工复核。
接口能力边界
本接⼝专门针对国内全类型火车票设计,涵盖高铁(G 字头)、动车(D 字头)、城际(C 字头)、普通列车(K、T、Z 等)的纸质车票与电子客票。一次调用可提取最多 13 个字段,包括:
- 出发站(start_station)与到达站(end_station)
- 车次号(train_num)
- 乘车人姓名(name)与身份证号(id_num)
- 座位类别(seat_cls)与座位号(seat_num)
- 发车时间(time)
- 票价(price)与总金额(total_amount)
- 售票站(sale_station)与售票凭证号(sale_num)
- 票号(ticket_num)
注意:由于返回数据包含个人敏感信息(姓名、身份证号),该接口仅限已登录用户调用,匿名访问不开放。调用前需确保已获取有效的 API Key。
接口的 QPS 限制为 2 次/秒,适合中小规模的批量处理。若需要更高并发,建议采用队列缓冲与降级策略。
鉴权方式
调用时需要在请求头中携带授权信息。根据最新规范,使用Authorization头传递 Bearer Token:
Authorization: Bearer <你的 API Key>请勿在 URL 参数或请求体中直接暴露 API Key。部分旧版文档可能提到X-API-Key头,但为了统一与安全,推荐使用Authorization。若你的服务端 SDK 仅支持旧方式,请自行适配。
请求参数详解
接口采用 POST 方法,请求地址固定为:
https://v1.apizero.cn/api/ocr-train-ticket请求体为 JSON 对象,包含两个必填字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
input_type | string | 是 | 图片传输方式,可选url或base64 |
input_data | string | 是 | 图片内容。input_type=url时填写公网可访问的图片链接(http/https);input_type=base64时填写图片的 Base64 编码字符串,可带有data:image/xxx;base64,前缀或直接纯编码 |
- 图片大小建议:单张图片最好不超过 5 MB,过大的图片会增加传输时间并可能触发服务端限制。
- 图片格式:支持常见的 JPEG、PNG、BMP 格式。
- Base64 编码:推荐使用去掉换行符的纯 base64 字符串,避免请求解析错误。
请求头还需设置Content-Type: application/json。
curl 接入示例
以下是一个完整的 curl 调用示例(请替换YOUR_API_KEY与图片 URL):
curl -sS -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input_type": "url", "input_data": "https://example.com/train-ticket.jpg"}' \ "https://v1.apizero.cn/api/ocr-train-ticket"若使用 Base64 方式,可先生成编码:
# 将图片转为 base64(去掉换行) IMAGE_BASE64=$(base64 -w0 ./train-ticket.jpg) curl -sS -X POST \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input_type": "base64", "input_data": "'"$IMAGE_BASE64"'"}' \ "https://v1.apizero.cn/api/ocr-train-ticket"Python 接入示例
使用requests库是最常见的Python实现方式。以下示例代码处理 URL 和 Base64 两种输入:
import requests import base64 API_URL = "https://v1.apizero.cn/api/ocr-train-ticket" API_KEY = "your_api_key_here" # 请替换 def recognize_train_ticket(image_input, input_type="url"): headers = { "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" } payload = { "input_type": input_type, "input_data": image_input } resp = requests.post(API_URL, json=payload, headers=headers) resp.raise_for_status() # 检查 HTTP 状态 return resp.json() # 使用图片 URL result = recognize_train_ticket("https://example.com/train-ticket.jpg") print(result) # 使用本地图片 Base64 with open("train-ticket.jpg", "rb") as f: encoded = base64.b64encode(f.read()).decode("utf-8") result2 = recognize_train_ticket(encoded, input_type="base64") print(result2)注意事项:生产环境中应将 API Key 存储在环境变量或配置中心,避免硬编码。
返回值解读
成功响应的状态码为200,且返回 JSON 结构如下:
{ "code": 0, "msg": "成功", "request_id": "req_abc123", "data": { "end_station": "上海虹桥", "id_num": "110101199001011234", "name": "张三", "price": "553.00", "sale_num": "G123456", "sale_station": "北京南", "seat_cls": "二等座", "seat_num": "05车12A号", "start_station": "北京南", "ticket_num": "E123456789", "time": "2024-01-15 09:00", "total_amount": "¥553.00", "train_num": "G101" } }关键字段说明
| 字段 | 类型 | 示例 | 说明 |
|---|---|---|---|
code | number | 0 | 业务状态码,0 表示成功,非 0 表示失败 |
msg | string | "成功" | 业务提示信息 |
request_id | string | "req_abc123" | 本次请求的唯一标识,便于排查 |
data | object | - | 结构化识别结果,包含 13 个子字段 |
data内部字段:
start_station/end_station:出发站、到达站;中文全称。train_num:车次号,如 G101。name/id_num:乘车人姓名与身份证号(已脱敏?此处为原始识别结果,实际使用时建议根据业务需要做脱敏处理)。seat_cls/seat_num:座位等级(二等座/一等座/硬座等)和座位编号。time:发车时间,格式YYYY-MM-DD HH:mm。price/total_amount:票价(数字字符串)和含币种的总金额,如¥553.00。sale_station/sale_num:售票站与售票凭证号(主要针对纸质票)。ticket_num:票号(通常为 9-10 位数字字母组合)。
注意:部分字段在特定票种下可能为空,如电子客票可能无
sale_station,但接口仍会返回空字符串。
常见错误排查
| HTTP 状态 | code | msg | 可能原因与解决方案 |
|---|---|---|---|
| 401 | -1 | 未授权 | 未提供Authorization头或 API Key 无效。检查密钥是否正确,是否已登录。 |
| 400 | 1001 | 参数错误 | input_type不在允许范围内,或input_data为空。 |
| 400 | 1002 | 图片下载失败 | input_type=url时,无法从 URL 获取图片。检查图片链接是否可公开访问,或图片已被删除。 |
| 400 | 1003 | 图片解码失败 | 图片格式不支持或 Base64 编码异常。确认图片为常见格式,Base64 字符串无多余换行符。 |
| 429 | -1 | 请求过于频繁 | QPS 超过 2。可加入重试退避(如指数退避)。 |
| 500 | -1 | 服务内部错误 | 后端异常,可尝试稍后重试,或记录request_id联系技术支持。 |
工程化注意事项
1. 图片预处理
- 清晰度:确保图片中票面文字清晰、无遮挡、无反光。若从手机拍照获取,建议使用 500 万像素以上摄像头,并保持票面平整。
- 裁剪与压缩:若图片包含周围背景,可先裁剪出票面区域,减少干扰。压缩到 2~3 MB 以内可提高传输速度。
- 格式转换:推荐统一转换为 JPEG 格式,平衡质量与大小。
2. 调用频率控制
QPS 限制为 2,若需批量处理多张票据,建议使用队列(如 Redis List 或 Python 的asyncio.Queue)控制并发,每次请求间隔至少 500ms。示例:
import time import requests def batch_recognize(image_urls): results = [] for url in image_urls: result = recognize_train_ticket(url) results.append((url, result)) time.sleep(0.6) # 控制速率 return results3. 错误重试策略
对于 429(限流)和 5xx(服务端错误),可重试最多 3 次,使用指数退避 (0.5s, 1s, 2s)。但注意不要对 4xx 参数错误重试,以免无限循环。
4. 数据脱敏
接口返回的姓名与身份证号是明文,在日志记录或传输到前端时务必做脱敏处理。例如:
- 姓名:只显示姓氏,名字用
*替代 →张* - 身份证号:显示前 6 位和后 4 位,中间 8 位用
********替代 →110101********1234
5. 缓存相同图片
同一张图片的识别结果理论上是不变的。可对图片 Base64 或 URL 做哈希,将结果缓存到本地(如 Redis 或本地文件),避免重复调用。
参考文档
- 火车票识别 API 官方文档
- 原始接口定义(Markdown)