紙やPDFの請求書を、1枚ずつExcelに手入力する。月末のあの作業が、地味に消耗しますよね。Claudeの画像認識に「品目と金額をCSVで出して」と投げたら、表形式のまま吸い出せました。今回はレイアウト違い・低画質・回転・スマホ撮影の悪条件まで混ぜた7枚で、どこまで正確に読めるかを実測しています。結果はフィールド単位で99%。崩れたのはどこか、会計ソフトに取り込めるCSVを吐くスクリプトと一緒に、正直に書きます。
結論:デジタル請求書なら金額はほぼ完璧。崩れるのは日付など細部
答えはシンプルでした。きれいに発行されたPDFなら、金額の読み取りはほぼ間違えません。実際、今回の7枚で金額・数量・単価・合計の誤読はゼロでした。低画質にしても、4度傾けても、スマホで暗く撮った想定までやっても、金額は崩れません。
唯一こけたのは、いちばん汚した1枚の「日付の末尾1桁」だけ。123個のフィールドのうち、間違えたのはこれ1つです。だから「金額の表データ化はAIに任せて、合計の検算で守る」が現実解でした。順に見ていきましょう。
題材:意地悪に汚した請求書7枚を作った
本物の請求書は当然出せないので、現場の「読みにくさ」を仕込んだダミーをPythonで7枚生成しました。正解の品目・数量・単価・金額を持たせたうえで、画像だけをClaudeに渡しています。狙ったのは、きれいな1枚で終わらせないこと。わざと条件を散らしました。
- レイアウト・フォント違い:ゴシック / 明朝 / 太字を混在。明細が3〜4行。
- 税率と日付表記の揺れ:消費税10%と軽減8%、「2026-06-15」「2026/06/20」「令和8年6月10日」。
- #5 低解像度+ブラー:FAXやコピーで潰れた想定。
- #6 回転4°+ノイズ:雑にスキャンして斜めになった想定。
- #7 強い低解像度+ブラー+JPEG劣化+傾き:スマホで暗所撮影した最悪条件。

合計で明細22行・検証フィールド123個。この123個をどれだけ正しく拾えるかが勝負です。
やってみた:123項目中122正解(99.19%)
Claudeに画像を渡し、発行元・日付・明細・小計・消費税・合計を構造化(JSON)で返させました。それを正解と1フィールドずつ突き合わせています。結果がこちらです。
| 指標 | 結果 |
|---|---|
| 請求書 | 7 枚 |
| 検証フィールド | 123 個 |
| 正解 | 122 個 |
| 正解率 | 99.19% |
| 金額・数量・単価・合計の誤読 | 0 件 |
| 唯一の誤り | #7(強劣化)の日付 2026-06-18 → 2026-06-15 |
クリーンな4枚は完全一致でした。和暦の「令和8年6月10日」も、スラッシュ区切りの「2026/06/20」も、そのまま正しく解釈しています。驚いたのは低画質と回転の2枚。ブラーで潰れていても、4度斜めでも、金額と明細は1つも外しませんでした。
「本当に読めているの?」という人向けに、生の入出力を1組だけ見せます。さきほどの#1(サクラ商事)の画像を渡して、Claudeが実際に返したJSONがこれです。金額も明細も、正解と1文字も違いませんでした。
{
"issuer": "株式会社サクラ商事",
"date": "2026-06-15",
"line_items": [
{"name": "コピー用紙 A4 (500枚)", "qty": 12, "unit_price": 480, "amount": 5760},
{"name": "ボールペン 黒 (10本入)", "qty": 5, "unit_price": 320, "amount": 1600},
{"name": "クリアファイル A4 (20枚)", "qty": 8, "unit_price": 250, "amount": 2000}
],
"subtotal": 9360, "tax": 936, "total": 10296
}

こけたのは、スマホ暗所撮影を想定して強烈に劣化させた#7だけ。それも金額は全部正しく、外したのは日付の末尾「18」を「15」と読んだ1か所です。金額が読めるのに日付の細部が落ちる。これが現実的な崩れ方でした。逆に言えば、いちばん怖い「金額の誤読」は今回出ていません。
| #7の発行日 | 値 |
|---|---|
| 正解 | 2026-06-18 |
| Claudeの抽出 | 2026-06-15(末尾を誤読) |
コピペで動く実装(Anthropic API・画像入力+構造化出力)
本番で使う形のスクリプトです。請求書画像をBase64で渡し、抽出スキーマ(列定義)を固定してJSONで受け取ります。最後に会計ソフト取り込み用のCSVを書き出し、合計の検算結果も列に付けています。
# -*- coding: utf-8 -*-
"""
請求書/領収書の画像から品目・金額・日付・合計を Claude の画像認識で抽出し CSV 化する。
実行: ANTHROPIC_API_KEY を設定して python extract_invoices_with_claude.py
"""
import base64, csv, glob, json, os
import anthropic
MODEL = "claude-opus-4-8" # 画像認識の精度重視。コスト優先なら claude-sonnet-4-6
SCHEMA = {
"type": "object",
"properties": {
"issuer": {"type": "string"},
"date": {"type": "string", "description": "YYYY-MM-DD 形式。和暦は西暦へ変換"},
"line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": {"type": "string"},
"qty": {"type": "integer"},
"unit_price": {"type": "integer"},
"amount": {"type": "integer"},
},
"required": ["name", "qty", "unit_price", "amount"],
"additionalProperties": False,
},
},
"subtotal": {"type": "integer"},
"tax": {"type": "integer"},
"total": {"type": "integer"},
},
"required": ["issuer", "date", "line_items", "subtotal", "tax", "total"],
"additionalProperties": False,
}
PROMPT = ("この請求書画像から、発行元・日付・明細(品名/数量/単価/金額)・小計・消費税・合計を"
"正確に読み取ってJSONで返してください。数字はカンマや¥を除いた整数で。")
client = anthropic.Anthropic()
rows = []
for path in sorted(glob.glob("invoice_*.png")):
data = base64.standard_b64encode(open(path, "rb").read()).decode()
resp = client.messages.create(
model=MODEL,
max_tokens=2000,
output_config={"format": {"type": "json_schema", "schema": SCHEMA}},
messages=[{"role": "user", "content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": data}},
{"type": "text", "text": PROMPT},
]}],
)
inv = json.loads(next(b.text for b in resp.content if b.type == "text"))
calc_ok = inv["subtotal"] + inv["tax"] == inv["total"] # 合計の検算でガード
for it in inv["line_items"]:
rows.append([os.path.basename(path), inv["issuer"], inv["date"],
it["name"], it["qty"], it["unit_price"], it["amount"],
inv["subtotal"], inv["tax"], inv["total"],
"OK" if calc_ok else "要確認(合計不一致)"])
print(f"{path}: {inv['issuer']} 合計¥{inv['total']:,} 検算={'OK' if calc_ok else 'NG'}")
with open("invoices.csv", "w", encoding="utf-8-sig", newline="") as f:
w = csv.writer(f)
w.writerow(["ファイル","発行元","日付","品名","数量","単価","金額","小計","消費税","合計","検算"])
w.writerows(rows)
print(f"-> invoices.csv に {len(rows)} 明細を出力")
ポイントは2つです。1つは output_config で列定義(スキーマ)を固定すること。これでパース時に崩れません。もう1つは、画像認識の精度を取りに行くならモデルを claude-opus-4-8 にすること。コストを抑えたいなら claude-sonnet-4-6 でも実用になります。(画像入力の公式ドキュメント)
ガードの作り方:合計の検算で「読み間違い」を機械で弾く
精度99%でも、残り1%をどう守るかが実務では効きます。いちばん簡単で強いのが、合計の検算です。スクリプトでは各データについて「小計+消費税=合計」が一致するかを確認し、合わなければ「要確認」フラグを立てています。
今回は金額の誤読がゼロだったので、検算で弾かれたものはありませんでした。これは裏を返すと、金額系のミスは検算で機械的に拾える、ということです。日付のように検算で守れないフィールドは、別の手当てが要ります。実装では日付に「低確信フラグ」を持たせ、その行だけ目視する運用にすると安全です。全件を端から見直すより、桁違いに軽くなります。
向かないケース・気をつけたいこと
良い数字だけ並べると嘘になるので、限界も書きます。
- 今回は合成のデジタル請求書。実物はもっと厳しいです。手書き・感熱紙の薄れ・写真の影や反射が入ると、精度は確実に下がります。99%をそのまま自社に当てはめない方が安全です。
- 崩れたのが日付で済んだのは運の要素もある。強い劣化では金額の桁を落とすこともありえます。だから検算と目視のガードを外さないこと。
- 撮り方で精度は大きく変わる。スキャンは明るく・まっすぐ・高解像度。これだけで読み取りは安定します。暗所のスマホ撮影は最後の手段です。
逆に言えば、デジタル発行のPDFがそろっている会社なら、いちばんおいしい使いどころです。受信したPDFをそのまま流し込めば、月末の手入力がほぼ消えます。
まとめ
- 請求書/領収書の表データ化は、Claudeの画像認識で 123項目中122正解(99.19%)。
- 金額・数量・単価・合計の誤読はゼロ。低画質・回転・スマホ撮影想定でも金額は崩れなかった。
- 唯一の誤りは強劣化1枚の日付1桁(18→15)。金額より細部が落ちる。
- 合計の検算(小計+税=合計)で金額ミスを機械的に弾き、日付は低確信フラグで目視。
- 手書き・感熱紙・写真は精度が落ちる前提。スキャンは明るく・まっすぐ・高解像度で。
「AIで下ごしらえ、最後の確認だけ人」という形は、前に書いた 顧客リストの名寄せ記事 と同じ設計です。画像処理を自走で実測した WebP最適化の記事 もあわせてどうぞ。ほかの効率化ネタは 業務効率化実践のカテゴリ にまとめています。
経理の手入力を減らしたい方へ
「受け取った請求書を会計ソフトに自動で取り込みたいけど、検算やCSV変換の組み込みが不安」という方へ。経理・バックオフィスの自動化の導入支援もやっています。請求書の流し込みから検算ガードの設計まで、30分の無料相談から始められます。 → サービス詳細