用收据 OCR 转成 CSV,再导入会计软件
收据小票手动录入、Excel 打开乱码、明细全挤进一个单元格、PDF 没法复制——把这些月末苦活替换成“拍照→定义好列→一张=一行→导出 CSV→导入 freee/Money Forward/弥生”的实操指南。明细用数组列展开成一件商品=一行,UTF-8 BOM 杜绝乱码,每个值都带 bbox+match_ratio 可与原件核对。每张 ¥10、失败不计费、每月 100 张免费额度。
月末。从钱包和抽屉里翻出来的一沓收据和小票,得一张张手动录进会计软件:敲店名、敲日期、敲合计,再换下一张。攒到三十张,注意力早就散了,金额多打一位数都未必发现。“手动录收据”之所以折磨人,不在于量大,而在于它明明很简单、却又错不得。
想着扫描后贴进 Excel 吧,结果又撞上另一堵墙:打开 CSV,中文、日文全是乱码;小票上的明细(买了哪些商品的清单)一换行就被压进同一个单元格;用 PDF 发来的收据连复制都做不到。到头来还是把原件摊在屏幕旁边,盯着一行行重新敲一遍——这么折腾,数字化到底图个啥。
这篇文章,就是要把这套活替换成 “拍下收据 → 把列定义好一次 → 上传后一张=一行 → 导出 CSV 并导入 freee/Money Forward/弥生” 的实操指南。它不是产品说明书,请当成“月末那一沓收据该怎么收拾”的经验来读。
先上手试试(无需上传,10 秒搞定)
下面这个示例,是把两张真实收据跑了一遍 OCR 的结果。把鼠标移到任意一个字段(店名、日期、合计、明细)上,它是从图片哪个位置读出这个值的,就会在原件上高亮出来。不用上传,也不用登录。先来确认一下:读出来的值,是不是真的指向原件上的那个位置。

Each value with a box carries a verified on-page location — bbox + 4-point vertices + match_ratio — on a 0–1000 normalized grid (0,0 top-left → 1000,1000 bottom-right), the same shape the live API returns. Hover a field to trace it back to the pixels it came from.
从收据 OCR 到 CSV,真实的 4 个步骤
要做的事其实不多。下面按顺序用视频一步步看。
- 上传原图 ── 把拍好或扫好的收据,灌进事先定好的列(店名、日期、合计、明细…)。
- 在抽取表里确认 ── 一张变成一行,列自动填满。
- 用 bbox 与原件核对 ── 可疑的值点一下单元格,原件上对应位置就会亮起,肉眼立刻核查。
- 导出 CSV ── 直接导出成能导进会计软件的 CSV。
先看步骤一:上传拍好/扫好的收据后,每张图片都会按你定义的列被结构化。
列(schema)只需定义一次
关键在于:一开始就把列定下来。 像“店名、分店名、日期、合计、明细”这样把想要的项目先定义好,之后上传的所有收据都会按同一套形态(同一 schema)整理成一行。哪怕各家店的排版千差万别,输出的行形态都一样。也正因如此,最后才能汇成一张 CSV。
“明细全挤进一个单元格”问题的真相
手工填 Excel 时最头疼的,就是小票上的明细(买了哪些商品的清单)。一张收据上有十行商品,你要么把它塞进一个单元格,要么手动拆成十行。
在 space-ocr 里,明细被定义成数组(array)类型的列。导出 CSV 时,这个数组列会 展开成 明细.商品名 明细.单价 明细.数量 这样的子字段,按一件商品=一行纵向铺开。也就是说,它不是“挤进一个单元格”,而是一开始就以会计、汇总都能直接处理的行形态输出。
{
"columns": [
{ "name": "店舗名", "type": "string" },
{ "name": "支店名", "type": "string" },
{ "name": "日付", "type": "string" },
{ "name": "合計", "type": "string" },
{
"name": "明細",
"type": "array",
"children": [
{ "name": "商品名", "type": "string" },
{ "name": "単価", "type": "string" },
{ "name": "数量", "type": "string" }
]
}
]
}可疑的值,点一下就跳到原件去核对
读取完成后,你不必照单全收。点一下拿不准的单元格,原件图片上“就是从这里读出来的”那个位置就会高亮。视线一下子被带过去,整沓收据抽查起来特别快。
它之所以管用,是因为每个值都连带返回 读取位置(bbox)和一致度(match_ratio)。一个值到底来自图片的哪里,人和系统事后都能回溯——也就是说,可审计。
这些坐标,不是 AI 凭“应该在这儿吧”给出的数字。 语言模型返回的,只有值的文本,以及它参考过的单词 token 提示(wid),坐标本身它并不生成。引擎会先把这个值的文本,和 Vision OCR 实际在页面上检测到的字符(symbol)逐字比对,再把框放到找到的那个真实像素位置上。在此基础上,给每个值附上 match_ratio(一致度,0~1.0)。1.0 表示所有字符都在原件上找到了,0.85 以上视为可信匹配。语言模型给的 token 提示,有时会用来辅助修正找到的 token 的位置,但不会盲信 ── 尤其当相同的值排成一列时提示容易飘,所以会用整列的归类和整行的一致性来校验,一旦对不上就退回逐字比对的结果。坐标以 xmin / ymin / xmax / ymax 的 0~1000 归一化网格(0,0=左上,1000,1000=右下)返回,因此不依赖图片的分辨率。说到底,重点不是“AI 不会错”,而是“把每一个值都对照原件,再用数值说明它匹配到了什么程度”。
导出 CSV,导入会计软件
核对完毕,就把这张表导出成 CSV。表头由标量列+数组的子列(像 明细.商品名 那样展开)构成,明细按一件商品=一行纵向展开。如果你手动改过某些单元格,会以你修改后的值为准。
再说乱码这件事。导出的 CSV 带 UTF-8 BOM,所以用 Excel 打开也不会乱码。这正是它从根上不会出现“Excel 乱码”的原因。
导入 freee/Money Forward/弥生
导出的 CSV,从各会计软件的 “CSV 导入”功能读入即可。它走的不是官方 API 对接,而是通用的 CSV 导入。也正因如此,它不太依赖会计软件那边的版本或套餐,只要把列的对应关系(映射)配好,就能直接导进去。
月末攒下的收据:拍照 → 一张表 → 一个 CSV → 一次性导入软件。原本手动录入的时间,就变成了核对的时间。
如果手头不是图片而是扫描 PDF,可以一并看看扫描 PDF 转 Excel 的步骤。想用 API 自动处理发票、送货单的话,发票、送货单 OCR API 的文章会有帮助。
PDF 形式的收据,也能直接处理
邮件里收到的收据是 PDF,还复制不了——这也是常见的卡点。把 PDF 拖进应用,每一页都会先自动转成图片,再去跑 OCR。所以“PDF 没法复制”这堵墙,你这边完全不用操心。多页 PDF 会逐页处理,结果一并堆进表里。
价格透明,失败不计费
- 每张 ¥10 的按量计费(按 call/image 计)。
- 失败不计费 ── 没出结果的图片不收钱,引擎错误会自动退款。
- 免费额度每月 100 张(无需信用卡,每月重置)。
- 想包月用就选 Pro ¥7,980/月。
如果只是想“先拿这个月的收据试试看”,在免费额度内就能直接跑起来。
收据、发票的电子化,在配合发票制度(インボイス制度)和电子账簿保存法(電子帳簿保存法)建立合规流程的实务中很有用。每个值都能带着 match_ratio 回溯到原件的哪个位置读出来,这一点有助于公司内部核查和确认。不过本文不构成会计或法务建议,也不保证满足任何法律要求或通过认证。制度合规的最终判断,请务必向顾问税理士等专业人士确认。
月末的收据,拍张照就收工
- 把列(schema)定义一次除了店名、分店名、日期、合计,把明细定义成数组(array)类型的列,子字段为商品名、单价、数量。这样之后所有收据都会按同一形态整理成一行。
- 把收据拍照/扫描后上传手机拍照或扫描都行。PDF 拖进来后,每一页会先自动转成图片再做 OCR。它会按一张=一行读取,列自动填满。
- 用原件核对可疑的值点一下单元格,原件图片上读取这个值的位置(bbox)就会高亮。match_ratio 低于 0.85 的值是匹配偏弱的信号,应优先确认、修改。手动改过的值会与原始 OCR 值分开保存。
- 导出成 CSV把表导出成 CSV。明细等数组列会像“明细.商品名”那样展开,按一件商品=一行纵向展开。导出带 UTF-8 BOM,所以用 Excel 打开日文也不乱码。
- 用会计软件的 CSV 导入功能导入从 freee、Money Forward、弥生等的“CSV 导入”功能读入。它不是官方 API 对接,而是通用的 CSV 导入,所以把列的对应关系配好就能直接导进去。