ClaudeでPDF請求書をスプレッドシート化する|スキャン・回転・複数ページを実際に試した結果【2026年7月】
請求書PDFの手入力をAIに任せたい。ただ気になるのは「スキャンした紙でも読めるのか」「金額を読み間違えたらどう気づくのか」です。この記事では実際に5パターンのPDFを作ってClaude Codeに読ませ、どこまで正確で、どこが崩れるのかを実測しました。そのうえでスプレッドシートに流し込むまでの手順と、誤読を検知する仕組みをまとめます。
先に結論:思ったより読める。危ないのは「数字」ではなく「文字」だった
検証の結論を先に書きます。詳細は後述しますが、5パターンすべてで金額と数量は1件も間違いませんでした。傾いたスキャン、90度回転、低解像度、3ページ分割でもです。
一方で崩れたのは文字のほうでした。低解像度PDFで「システム開発(初期)」の全角括弧が半角括弧「(初期)」に変わりました。金額が合っているので気づきにくく、しかしマスタと文字列照合している業務では確実に事故ります。
つまり実務での勘所は「AIが金額を読み間違えるのが怖い」ではなく、「表記が微妙に揺れることを前提に、照合と検算の仕組みを用意しておく」ことでした。
まず方法を3つから選ぶ
ClaudeにPDFを読ませる経路は3つあります。用途がかなり違うので、ここを最初に決めます。
| 方法 | 向いている用途 | 必要なもの |
|---|---|---|
| Claude Code に読ませる | 月に数十件までの手作業。まず試すならこれ | Claude Code(サブスクでOK) |
API の document ブロック(base64) |
自社システムへの組み込み。件数が多い定型処理 | APIキー(従量課金) |
Files API で file_id 参照 |
同じPDFに何度も質問する。大きいPDF | APIキー。ベータ機能 |
この記事の検証は1番目(Claude Code)で行いました。理由は、多くの読者にとって最初の一歩がここになるからです。追加契約なしで今日試せます。
読み方を理解しておくと、後の注意点が納得しやすくなります。公式ドキュメントによると、Claudeは各ページを画像に変換し、そのページのテキストも一緒に抽出して、両方をセットで解析します。
つまり「テキスト抽出」だけでも「画像認識」だけでもありません。だから図やグラフも読めますし、逆に視覚的な読み取りの限界がそのまま影響します。文字が潰れていれば読み間違える余地が出る、というのはこの構造から来ています。
実機検証:5パターンのPDFで試した
- Claude Code 2.1.220(モデルは Claude Opus 5)
- A4・日本語の架空の請求書PDFを自作。明細4行(3ページ版は6行)
- プロンプトは共通で「明細をCSVで出力。列は 品目,数量,単価,金額。CSVのみ出力し説明は不要」
- 使用ツールは
Readのみに制限。各テスト1回実行 - 実測コストは
--output-format jsonのtotal_cost_usdの値
結果をまとめます。
| # | PDFの種類 | 数量・金額 | 文字列 | 実測コスト |
|---|---|---|---|---|
| 1 | 通常のテキストPDF | 全問正解 | 完全一致 | $0.122 |
| 2 | スキャン相当(画像のみ・傾き0.7度・ノイズ入り) | 全問正解 | 完全一致 | $0.098 |
| 3 | 90度回転したスキャンPDF | 全問正解 | 完全一致 | $0.117 |
| 4 | 低解像度(FAX相当まで劣化) | 全問正解 | 全角括弧が半角に変化 | $0.098 |
| 5 | 3ページ分割+ダミー金額混入 | 全問正解 | — | $0.126 |
テスト1:テキストPDF ─ 仕込んだ矛盾を自分で見つけた
普通のPDFなので正解は当然でしたが、想定外の挙動がありました。テスト用の請求書にはわざと金額の矛盾を仕込んでいました。上部に「合計金額(税込): 1,287,000 円」と書きつつ、明細の合計は 1,294,700 円になるようにしてあります(小計1,177,000+消費税117,700)。
「CSVのみを出力し、説明は書かないでください」と指示したのに、返ってきたのはこれです。
品目,数量,単価,金額
コンサルティング費用,3,180000,540000
システム開発(初期),1,480000,480000
保守サポート(6月分),6,25000,150000
交通費実費,1,7000,7000
(指示どおりCSVのみ出しましたが、1点だけ注意:PDF上部の
「合計金額(税込): 1,287,000 円」と明細下の「合計 1,294,700」が
不一致です。小計1,177,000+税117,700=1,294,700が明細と整合します。)
沈黙を指示されても矛盾を報告してきました。実務ではこれは望ましい挙動です。ただし「必ず報告してくれる」と期待するのは危険で、テスト2以降では同じ矛盾に触れませんでした(そちらは指示に忠実にCSVだけを返しました)。気づいたら報告するが、気づかないこともあるという前提で組むべきです。検算を仕組みとして入れる話は後述します。
テスト2・3:スキャンでも回転でも読めた
画像のみのPDF(テキスト層が存在しない、いわゆるスキャンPDF)でも全問正解でした。傾きとノイズを加えても影響なしです。
興味深いのはコストがテスト1より安かった点です($0.098 対 $0.122)。テキスト層がないぶん、渡される情報量が減ったためと考えられます。「スキャンだから高くつく」という直感は当たりませんでした。
90度回転も正解でした。公式ドキュメントは「ページは正しい向きに回転させること」をベストプラクティスとして挙げていますが、今回の1ページ・活字の請求書では回転していても支障ありませんでした。もちろん推奨に従うほうが安全ではあります。手書きや低品質と組み合わさると条件が変わる可能性があります。
テスト4:数字は合うのに文字が変わる
これが今回いちばん実務的な発見です。解像度を大きく落としたPDFで、金額・数量は全問正解だったにもかかわらず、品目名がこうなりました。
正解: システム開発(初期) 保守サポート(6月分)
出力: システム開発(初期) 保守サポート(6月分)
全角括弧が半角括弧になっています。数値が合っているので検算では絶対に検出できません。そして品目名で商品マスタや勘定科目マスタを引く処理を書いていると、ここで突然マッチしなくなります。
抽出結果をそのままキーにしないでください。少なくとも全角・半角の統一、空白の除去、記号の統一をかけてから照合します。Pythonなら unicodedata.normalize("NFKC", s) が最も手軽で、全角括弧・全角英数字・全角スペースをまとめて半角に寄せてくれます。
import unicodedata, re
def norm(s: str) -> str:
s = unicodedata.normalize("NFKC", s) # (初期)→ (初期)
s = re.sub(r"\s+", "", s) # 空白を除去
return s.strip()
# マスタ側も同じ関数を通してから比較する
master = {norm(k): v for k, v in master_raw.items()}
hit = master.get(norm(extracted_name))
ポイントはマスタ側にも同じ正規化をかけることです。片側だけ正規化しても意味がありません。
テスト5:3ページに分かれた明細とダミー金額
実務でいちばん厄介なのが複数ページです。今回は次の構成にしました。
- 1ページ目:明細3行+「ページ小計 778,000」
- 2ページ目:明細3行+「ページ小計 711,000」
- 3ページ目:合計のみ。ただしダミーとして「前回請求額(参考)1,320,000」を混入
「今回の税抜合計・税込請求額・明細行数」をJSONで聞いた結果です。
{
"total_excl_tax": 1489000,
"total_incl_tax": 1637900,
"item_count": 6
}
3つすべて正解でした。778,000+711,000=1,489,000というページをまたいだ足し算も合っており、「前回請求額」というダミーにも釣られませんでした。「今回の」という限定を正しく解釈しています。
プロンプトで total_excl_tax(今回の税抜合計) のようにキー名に日本語で意味を添えたことが効いた可能性があります。単に total と書くだけだと、どの合計を指すのか判断の余地が生まれます。請求書のように似た数字が並ぶ書類では、「何の合計か」を明示的に書くのが安全です。
番外:一度だけ読み取りに失敗した
正直に書いておきます。テスト5の初回実行時、Claude Codeがpdftoppm is not installed(poppler未導入)でPDFのページ描画に失敗しました。同じファイルで再実行したところ問題なく読めたため、ページ数や特定ファイルに起因する再現性のある問題ではありませんでした。
1ページ・2ページ・3ページのPDFでそれぞれ確認しましたが、いずれも通常は読めています。ただし環境によっては読み取り経路がpopplerに依存する場面があり得るということなので、業務で定常運用するなら brew install poppler(macOS)を入れておくと安定します。読み取り失敗をエラーとして検知できるようにしておくことも大切です。
なおこのとき、Claudeは同じフォルダにあった別ファイルの数値を流用して回答することを明示的に拒否しました。「PDFを読めていないためJSONを出力できません」と報告して止まっています。読めなかったときに黙って推測で埋めないという点は安心材料です。
スプレッドシートに流し込むまでの実務パターン
抽出できたら、あとはスプレッドシートに入れます。おすすめの構成は「PDF → CSV → スプレッドシート」の2段構えです。
なぜ直接スプシに書かせないのか
ClaudeにPDFを読ませてそのままスプレッドシートへ書き込ませることも技術的には可能です(スプレッドシート操作の方法は別記事で解説しています)。ただし実務では間にCSVを挟むほうが安全です。理由は3つあります。
- 検算を挟める:書き込む前に合計値を突合できる
- やり直せる:スプシに直接書くと、間違ったときの巻き戻しが面倒
- 差分が見える:CSVをGitやフォルダに残せば、後から「何を取り込んだか」を追える
手順
Claude Codeでの実行例です。実際に検証で使ったコマンドと同じ形です。
# 1. PDFからCSVを作る(Readのみ許可。ファイルは書かせない)
claude -p "invoice.pdf を読み、明細をCSVで出力してください。
列は 品目,数量,単価,金額 とします。CSVのみを出力し、説明は書かないでください。" \
--allowedTools "Read" --permission-mode dontAsk \
< /dev/null > out/invoice.csv
# 2. 検算スクリプトを通す(次章)
python3 verify.py out/invoice.csv
# 3. 検算を通ったものだけスプレッドシートへ取り込む
< /dev/null を付ける:付けないと標準入力を待ち、cronなどから実行したときに「no stdin data received in 3s」という警告が出ます。
ツールを絞る:抽出フェーズでは --allowedTools "Read" にして書き込みを禁止します。読むだけの処理に書き込み権限を与えない、という基本です。定期実行の組み方は別記事で解説しています。
誤読を検知する仕組みをどう作るか
ここが本番です。AIの出力を人が全部目視するなら自動化した意味がありません。かわりに機械的に検知できるチェックを置きます。
優先度の高い3つのチェック
| チェック | 何を防げるか | 実装 |
|---|---|---|
| 行の検算(数量×単価=金額) | 単価や数量の桁の読み間違い | 数行のコード。最優先 |
| 合計の突合(明細の和=記載の合計) | 行の取りこぼし・重複 | 合計をPDFから別途抽出して比較 |
| マスタ照合(正規化してから) | 品目名の表記揺れ | 前章の norm() を通して突合 |
特に2つ目の「合計の突合」がいちばん費用対効果が高いです。行が1行抜けても検算は全行通ってしまいますが、合計が合わなければ必ず引っかかります。
import csv, sys, unicodedata, re
def norm(s):
return re.sub(r"\s+", "", unicodedata.normalize("NFKC", s)).strip()
def to_int(s):
return int(re.sub(r"[^0-9-]", "", norm(s)))
rows = list(csv.DictReader(open(sys.argv[1], encoding="utf-8")))
errors, total = [], 0
for i, r in enumerate(rows, start=2): # 2行目=1件目
qty, price, amount = to_int(r["数量"]), to_int(r["単価"]), to_int(r["金額"])
if qty * price != amount:
errors.append(f"{i}行目: 検算不一致 {qty}x{price}={qty*price} ≠ {amount}")
total += amount
# PDFに記載されていた小計(別途抽出しておく)
EXPECTED_SUBTOTAL = 1177000
if total != EXPECTED_SUBTOTAL:
errors.append(f"合計不一致: 明細合計 {total} ≠ 記載 {EXPECTED_SUBTOTAL}")
if errors:
print("NG")
print("\n".join(errors))
sys.exit(1) # 取り込みを止める
print(f"OK {len(rows)}件 / 合計 {total:,}円")
検算は強力ですが、今回のテスト4で起きた「全角括弧が半角になる」タイプの誤りは検算をすべて通過します。数値は完全に正しいからです。
だからこそ、マスタ照合を正規化つきで入れておく必要があります。「照合できなかった品目名を人間に回す」という運用にすれば、機械が処理できる範囲を最大化しながら事故を防げます。
ダブルチェックを別の呼び出しでやる手もある
より慎重にやるなら、抽出した結果を別のClaude呼び出しに渡して、PDFと突き合わせて検証させる方法があります。ポイントは「同じ会話の続きで確認させない」ことです。自分が抽出した文脈が残っていると、間違いを見落としやすくなります。
ただしコストは倍近くになります。検算スクリプトで9割拾えるなら、まずはそちらを作るのが現実的です。
コストと制限の目安
実測コスト
今回の検証(A4・1〜3ページの請求書、明細4〜6行)では1回あたり $0.098〜$0.178でした。5テスト+切り分けの追加実行を含めた合計は約$1.30です。日本円で1件あたり15〜27円程度(1ドル150円換算)という感覚になります。
公式ドキュメントの目安はテキスト分で1ページあたり1,500〜3,000トークン、加えて各ページが画像に変換されるため画像分のトークンもかかります。PDF固有の追加料金はなく、通常のAPI料金が適用されます。
同じPDFに何度も質問する場合はプロンプトキャッシュが効きます。また、大量処理ならclaude-sonnet-5 や claude-haiku-4-5 のような下位モデルで十分かどうかを自分のデータで試す価値があります。今回はOpus 5で検証しましたが、活字の請求書ならより安いモデルでも読める可能性があります。
ハードな制限
| 項目 | 上限 |
|---|---|
| リクエスト全体のサイズ | 32MB(プラットフォームにより変動) |
| 1リクエストあたりのページ数 | 600ページ(コンテキストが100万トークン未満なら100ページ) |
| 形式 | 標準PDFのみ。パスワード保護・暗号化は不可 |
公式が注意しているのは、ページ数の上限より先にコンテキストが埋まるケースです。小さい文字が詰まったページ、複雑な表、重いグラフィックが多いPDFは、100ページに達する前に失敗することがあります。その場合は分割してください。
よくある質問
Q. パスワード付きのPDFは読めますか?
読めません。標準PDFのみが対象で、パスワード保護・暗号化されたファイルは受け付けられません。先にパスワードを解除したコピーを作る必要があります。取引先から暗号化PDFで送られてくる運用なら、そこが自動化の最初の壁になります。
Q. 手書きの伝票でも読めますか?
今回は検証していません。活字のスキャン・低解像度・回転までは問題なく読めましたが、手書きは条件がまったく違います。Claudeの視覚的な読み取り能力に依存するため、実際の自社の伝票で10枚ほど試して精度を測ってから判断してください。手書きの場合は、検算と人間のレビューを必ず組み込む前提で考えるべきです。
Q. Vertex AIやBedrock経由のClaudeでもPDFは使えますか?
使えます。PDF対応はClaude API・Amazon Bedrock・Claude Platform on AWS・Google Cloud・Microsoft Foundryのすべてで利用可能です。ただしBedrock・Google Cloudではbase64での送信のみで、URL参照とFiles APIは使えません。またBedrockの旧Converse APIを使う場合、citations(引用)を有効にしないと画像を伴う視覚的な解析が行われず、単純なテキスト抽出にフォールバックします。表やレイアウトが崩れるなら、まずここを確認してください。
Q. 「読めなかった」ことに気づけますか?
今回の検証では、読み取りに失敗したとき Claude は明確に「読めていないため出力できません」と報告し、別ファイルの数値で埋めることを拒否しました。とはいえ運用上は出力が期待した形式(CSVのヘッダー、JSONのキー)になっているかをスクリプト側で必ず検査してください。空だった・形式が違ったら異常として止める、が基本です。
Q. 精度を上げるために何をすればいいですか?
公式が挙げているベストプラクティスは、PDFをテキストより前に置く・標準的なフォントを使う・文字が読める品質を確保する・ページを正しい向きにする・プロンプトではPDFビューア上のページ番号で指示する・大きいPDFは分割する・繰り返し解析するならプロンプトキャッシュを使うです。加えて実務的には、この記事で書いたように抽出させる項目名に「何の合計か」まで書き込むのが効きます。
まとめ
- テキストPDF・スキャン・90度回転・低解像度・3ページ分割の5パターンすべてで金額と数量は全問正解
- 崩れたのは文字。低解像度で全角括弧が半角に変化し、これは検算では検出できない
- スキャンPDFはむしろコストが安かった(テキスト層がないぶん情報量が減る)
- ページをまたいだ小計の足し算も正解し、ダミーの「前回請求額」にも釣られなかった
- 沈黙を指示しても金額の矛盾を自発的に報告することがある。ただし毎回ではない
- 読めなかったときは黙って推測せず、明確に失敗を報告した
- 実測コストは1回 $0.098〜$0.178(A4・1〜3ページ)
今日やれる最初の一歩は、自社の請求書PDFを1枚、Claude Codeに読ませてCSVを出させてみることです。そのうえで「数量×単価=金額」を検算するだけのスクリプトを書いてください。10行程度で書けますし、これがあるかないかで自動化に踏み出せるかが決まります。表記揺れの正規化は、マスタ照合を始める段階で足せば十分です。


