1. 从 700 张硬盘照片到一张 Excel:我为什么用 Claude Code 做 OCR
先说清楚这篇要解决的事:你手里有一堆截图、扫描件、设备照片,需要把里面的文字抠出来,还要整理成结构化报告(Excel/CSV/Markdown 都行)。传统做法是本地装 PaddleOCR 或 Tesseract,但没显卡、环境依赖一堆、中文识别率还飘。Claude Code 这类 CLI 工具配合多模态模型,可以直接把图片丢给模型做视觉理解,把「OCR + 字段抽取 + 汇总」串成一条链路。
这篇适合谁:需要批量处理截图/扫描件的开发者、运维、测试同学,尤其是那种「700 张硬盘照片要提取品牌、容量、型号、SN」的重复劳动场景。核心检索词就三个:Claude Code、OCR、导出报告。
我试过的场景是统计一批硬盘照片信息,把品牌、容量、型号、S/N 提取出来写进 Excel,同时输出一份「成功多少张、失败哪些」的核对清单。整条链路的关键不在模型多强,而在于统一 Key 配置和可核验的导出脚本。下面按「配置 → 调用 → 验证 → 排障」的顺序走一遍,配置骨架和脚本片段都能直接复制。
2. TaoToken 统一 Key 前置:一次配置,多模型切换
Claude Code 默认走 Anthropic 官方端点,但如果你想在 Kimi、豆包这类多模态模型之间切换,或者团队里统一管理额度,就需要一个兼容层。TaoToken 提供的就是这个角色:一个统一 Key,兼容 Anthropic 风格的接口,Claude Code 通过环境变量指向它即可。
先拿到 Key。打开控制台创建 API Key:
- 控制台入口:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite
- API Keys 管理:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite
创建后复制那串sk-开头的 Key,只显示一次,丢了就重建。这里有个坑:不要把 Key 硬编码进脚本提交到 Git,用环境变量或本地配置文件。
TaoToken 的 API 基址是https://taotoken.net/api(注意这个不加 UTM 参数,是给程序调用的)。Claude Code 需要两个环境变量:ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY。前者指向 TaoToken 的兼容端点,后者填你刚创建的 Key。
注意:Claude Code 读取的是 Anthropic 协议格式,TaoToken 做了协议适配,所以模型名可以填 Kimi-K2.5、doubao-seed-2.0-code 这类多模态模型,具体可用模型以文档为准。
文档入口放这里,配置细节对不上时去查:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
3. settings.json 配置骨架与 OCR 调用脚本
3.1 Claude Code 的 settings.json 骨架
Claude Code 支持项目级配置,在项目根目录建.claude/settings.json。下面这份骨架把端点、模型、权限都写清楚,你可以直接改 Key 后使用:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "sk-你的Key填这里", "ANTHROPIC_MODEL": "Kimi-K2.5" }, "permissions": { "allow": [ "Read", "Write", "Bash(python:*)", "Bash(ls:*)" ], "deny": [] } }如果你更习惯用 shell 环境变量,等价写法是:
export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-你的Key填这里" export ANTHROPIC_MODEL="Kimi-K2.5"两种方式选一种即可,settings.json 优先级更高,适合团队共享(Key 用占位符,各人本地覆盖)。
3.2 需求文档:让 Claude Code 知道要干什么
在项目根目录写一个task.md,把字段和输出格式讲清楚。这一步决定了后面 OCR 抽取的准确率,别偷懒:
# 任务:硬盘照片信息提取 ## 输入 - 目录:./photos/ 下的所有 jpg/png - 每张图是一块硬盘的标签照片 ## 提取字段 | 字段 | 说明 | |------|------| | 序号 | 按文件名排序 | | 品牌 | 如 Seagate / WD / Toshiba | | 容量 | 如 500GB / 2TB | | 型号 | 如 ST11503XXAS | | S/N | 序列号 | ## 输出 1. result.xlsx:成功提取的记录 2. failed.txt:识别失败或字段缺失的文件名列表 3. summary.txt:成功数 / 失败数 / 总数然后在项目目录打开终端,运行claude /init生成CLAUDE.md,再发指令:
claude # 进入交互后输入: 阅读 task.md,开始你的工作。Claude Code 会自己写 Python 脚本、调用多模态模型逐张识别、汇总结果。但「它自己写」这件事有个前提:你得把导出逻辑约束死,否则每次生成的表头都不一样。
3.3 可复制的 OCR + 导出脚本片段
下面这段是我实测能跑的骨架,核心思路是:遍历图片 → 转 base64 → 调多模态接口 → 解析 JSON → 写 Excel。你可以让 Claude Code 基于它改,也可以直接用:
import os, base64, json, time import requests import pandas as pd API_URL = "https://taotoken.net/api/v1/messages" API_KEY = os.environ["ANTHROPIC_API_KEY"] MODEL = os.environ.get("ANTHROPIC_MODEL", "Kimi-K2.5") PHOTO_DIR = "./photos" PROMPT = """你是OCR助手。识别这张硬盘标签照片,只返回JSON: {"brand":"","capacity":"","model":"","sn":""} 识别不到的字段填空字符串,不要编造。""" def encode_image(path): with open(path, "rb") as f: return base64.b64encode(f.read()).decode() def ocr_one(path): payload = { "model": MODEL, "max_tokens": 512, "messages": [{ "role": "user", "content": [ {"type": "image", "source": { "type": "base64", "media_type": "image/jpeg", "data": encode_image(path) }}, {"type": "text", "text": PROMPT} ] }] } headers = { "x-api-key": API_KEY, "anthropic-version": "2023-06-01", "content-type": "application/json" } r = requests.post(API_URL, headers=headers, json=payload, timeout=60) r.raise_for_status() text = r.json()["content"][0]["text"] text = text.strip().removeprefix("```json").removesuffix("```").strip() return json.loads(text) def main(): rows, failed = [], [] files = sorted(f for f in os.listdir(PHOTO_DIR) if f.lower().endswith((".jpg", ".png"))) for idx, name in enumerate(files, 1): try: data = ocr_one(os.path.join(PHOTO_DIR, name)) if not data.get("sn"): failed.append(name) continue rows.append({"序号": idx, **data, "文件": name}) except Exception as e: failed.append(f"{name} | {e}") time.sleep(0.3) pd.DataFrame(rows).to_excel("result.xlsx", index=False) with open("failed.txt", "w") as f: f.write("\n".join(failed)) with open("summary.txt", "w") as f: f.write(f"成功 {len(rows)} / 失败 {len(failed)} / 总数 {len(files)}") if __name__ == "__main__": main()几个参数说明:max_tokens给 512 够用,字段就四个;time.sleep(0.3)是防止批量请求触发限流;media_type按实际图片格式改,png 就写image/png。表头用中文,方便直接交付。
4. 端到端验证:跑通一次并核对结果
配置完别急着上 700 张,先拿 3 张图验证链路。步骤:
第一步,确认环境变量生效:
echo $ANTHROPIC_BASE_URL # 期望输出:https://taotoken.net/api第二步,跑一个最小请求,确认 Key 和端点通:
curl -s https://taotoken.net/api/v1/messages \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{"model":"Kimi-K2.5","max_tokens":64, "messages":[{"role":"user","content":"回复OK两个字"}]}'返回里能看到content字段带文字,就说明统一 Key 配置成功。如果返回 401,是 Key 问题;返回 404,是端点路径问题。
第三步,把 3 张测试图放进photos/,运行脚本:
python ocr_export.py cat summary.txt期望看到成功 3 / 失败 0 / 总数 3,打开result.xlsx核对字段是否和照片一致。这一步是「结果可核验」的关键:不要只看脚本没报错,要人工比对至少一张图的 S/N 是否和照片完全一致。
第四步,确认无误后再把 700 张全量丢进去。全量跑之前建议先备份photos/目录,脚本只读不写,但保险起见。
想直接在对话里验证模型对某张图的识别效果,可以用模型对话入口快速试:https://taotoken.net/model-chat?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite
5. 本篇常见错排查
5.1 401 Unauthorized:Key 没读到
最常见的原因是环境变量没导出,或者 settings.json 里 Key 还是占位符。检查顺序:echo $ANTHROPIC_API_KEY是否有值 → settings.json 是否被 Claude Code 正确加载 → Key 是否已过期。注意 Key 只在创建时显示一次,复制时别带空格。
5.2 模型返回的不是 JSON,解析报错
多模态模型有时会在 JSON 外面包一层 ```json 代码块,或者加一句「以下是识别结果」。脚本里已经用removeprefix/removesuffix处理了代码块,但如果模型加了自然语言前缀,json.loads还是会炸。稳妥做法是用正则抠出第一个{到最后一个}:
import re match = re.search(r"\{.*\}", text, re.S) data = json.loads(match.group()) if match else {}5.3 图片太大导致请求超时
手机拍的原图动辄 5MB 以上,base64 后更大。建议预处理压缩到长边 1600px 以内:
from PIL import Image img = Image.open(path) img.thumbnail((1600, 1600)) img.save(path, quality=85)5.4 批量跑一半被限流
表现是部分图片返回 429。加指数退避重试:
for attempt in range(3): try: return ocr_one(path) except requests.HTTPError as e: if e.response.status_code == 429: time.sleep(2 ** attempt) else: raise5.5 Excel 里中文乱码或字段错位
pandas.to_excel默认没问题,但如果字段名和 dict key 对不上,会出现整列 NaN。检查rows.append里的 key 是否和PROMPT里要求的 JSON 字段一致。另外 S/N 这类长数字串,Excel 可能自动转科学计数法,写表时用dtype=str或加前缀。
6. 长期跑批量任务:把配置沉淀下来
如果你只是偶尔处理几十张图,上面这套够用。但如果是持续性的批量任务,比如每周都要处理一批扫描件,建议做两件事:一是把settings.json和task.md放进项目模板,新任务直接复制;二是把脚本里的模型名、并发数、重试次数抽成配置项,方便切换。
长期编码和 Agent 类任务,用 Coding Plan 会更省心,额度和管理都集中:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite
接入过程中如果遇到协议对不上的报错,先翻接入文档,大部分坑都写了:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite
最后留一个实用技巧:跑全量之前,先用ls photos/ | head -5挑 5 张不同角度、不同光照的图做样本测试。硬盘标签有反光、倾斜、模糊的情况,样本覆盖到了,后面 700 张的失败率会低很多。失败列表failed.txt不要删,那是你二次处理的输入,针对失败图单独调 prompt 或换模型重跑,比全量重来省时间。