請求書や支払明細、売上レポートを受け取るたびに、金額や日付をExcelへ転記していないでしょうか。
PDFを開き、必要な箇所を探し、数字をコピーし、入力結果を確認する。この作業は1件なら短くても、毎月繰り返せば時間を奪います。入力ミスが請求漏れや集計誤差につながる危険もあります。
PythonでPDFから情報抽出する仕組みを作れば、帳票の受信からデータ保存、異常検知までを自動化できます。ただし、pdfplumberで文字を読み取るコードを書いたところで、すぐ無人運転できるわけではありません。PDFには文字を直接取得できるものと、OCRが必要な画像型があり、レイアウト変更や重複処理にも備える必要があるからです。
この記事では、初心者でも実装に着手できるように、次の成果を目指します。
- PDFの種類に合う抽出方法を選べる
- 誤抽出を後工程へ流さない検証ルールを作れる
- 失敗した帳票だけを安全に隔離できる
- 人間が毎回操作しなくても動く処理系を設計できる
- 抽出データを請求管理や収益監視へ接続できる
単発の時短ツールではなく、繰り返し働く自動化資産として設計する方法を扱います。
PythonによるPDF情報抽出の全体像
PDF情報抽出は、次の流れに分けると理解しやすくなります。
PDF受信
↓
重複判定
↓
テキスト型・画像型の判定
↓
テキスト抽出またはOCR
↓
項目抽出
↓
形式・金額・整合性の検証
├─ 正常 → CSV・DB・会計システムへ保存
└─ 異常 → 隔離フォルダへ移動して通知
OCRとは、画像内の文字を読み取る技術です。たとえば、紙の請求書をスキャンしたPDFでは、画面上に「請求金額 128,000円」と見えていても、内部に文字データがありません。この場合はOCRを利用します。
工程を分離する理由は、障害の影響範囲を狭くするためです。取引先が帳票デザインを変更しても、受信処理や保存処理まで作り直す必要はありません。抽出ルールだけを差し替えられます。
PDFは大きく3種類に分ける
| 種類 | 具体例 | 主な手段 | 注意点 |
|---|---|---|---|
| テキストPDF | 会計ソフトから出力した請求書 | pdfplumber、PyMuPDF | 読み順が見た目と異なることがある |
| 画像PDF | 紙をスキャンした領収書 | OCR、pytesseract | 傾きや低解像度で誤読しやすい |
| 混在PDF | 表紙は画像、明細はテキスト | ページ別判定 | ファイル単位の一律判定では取りこぼす |
PDF全体を一種類として扱わず、ページごとに抽出可能な文字数を調べる設計にすると混在PDFにも対応できます。
このサイトの一次データから見えた設計上の教訓
2026年7月22日に、このサイトの運用リポジトリをPowerShellで調査しました。調査対象は sites/ai-tech/content/posts にあるMarkdownファイルです。
(Get-ChildItem sites\ai-tech\content\posts -File -Filter *.md).Count
結果は363ファイルでした。さらにタイトルを確認すると、PythonによるPDF帳票抽出を直接扱う記事は3本ありました。これは一般市場の記事総数ではなく、当サイトの該当ディレクトリを同日に調べた結果です。
生成状態を保存する generator/.state.json には90件の生成履歴がありました。品質基準を管理する generator/ai_slop_guidelines.json には10項目の検査条件と、合格目安として8点が設定されています。同ファイルに記録された基準取得日時は2026年6月26日です。
この運用記録から得られる教訓は、データを作る処理と品質を確認する処理を分けることです。PDF抽出でも、「値らしい文字が取れた」と「業務に使える正しい値が取れた」は別の状態です。
既存の類似記事はOCR判定やライブラリ選定を中心にしていました。本稿では一歩進めて、次の4点を設計の中心に置きます。
- 項目単位の根拠保存
- 誤抽出時の停止条件
- 冪等性による二重処理防止
- 人間確認を減らす改善ループ
冪等性とは、同じ処理を複数回実行しても結果が重複しない性質です。たとえば同じ請求書PDFを2回受信しても、売上データを1件だけ登録する設計を指します。
ステップ・バイ・ステップ:PDF情報抽出を作る9工程
1. 実物のPDFを集めて分類する
最初に対象帳票を集めます。学習用のきれいなサンプルだけでは、実務で発生する例外を発見できません。
初期調査では、次の違いが分かるPDFを用意します。
- 発行元が異なる
- 1ページと複数ページがある
- テキスト型とスキャン型がある
- 金額表記に「円」「¥」「税込」が混在する
- パスワード付きや破損ファイルが含まれる
- 表の途中で改ページされる
- 訂正版や再発行版がある
仮に20件を検証用に集めるなら、「同じ発行元の請求書20件」なのか「10社から2件ずつ」なのかを記録してください。前提が違えば難易度も変わります。20件という数は業界標準ではなく、初期調査用の例です。
2. 必要項目と許容誤差を定義する
コードを書く前に、抽出仕様を表にします。
| 項目 | 値の例 | 必須 | 検証条件 | 失敗時 |
|---|---|---|---|---|
| 請求書番号 | INV-2026-0712 | 必須 | 空欄不可 | 処理停止 |
| 請求日 | 2026-07-12 | 必須 | 日付として解釈可能 | 処理停止 |
| 請求金額 | 128,000円 | 必須 | 数値化可能、0円以上 | 隔離 |
| 登録番号 | T1234567890123 | 任意 | Tと13桁 | 警告 |
| 備考 | 7月利用分 | 任意 | 条件なし | 空欄許可 |
金額や支払期限は、誤りが損失につながる項目です。備考と同じ扱いにしてはいけません。必須項目、検証方法、失敗時の動作をセットで決めます。
3. テキスト型か画像型かを自動判定する
まず通常のテキスト抽出を試し、取得文字数や必須ラベルの有無からOCRへ切り替えます。
import fitz # PyMuPDF
def extract_page_text(page) -> tuple[str, str]:
text = page.get_text("text").strip()
if len(text) >= 30:
return text, "embedded_text"
return run_ocr(page), "ocr"
30は説明用の仮値です。実際には、対象PDFからページ別文字数を計測し、空白ページや表紙が誤ってOCRへ送られない境界値を決めます。
文字数だけでなく、請求金額やInvoice No.など、想定ラベルが存在するかも確認すると判定が安定します。
4. 帳票テンプレートを識別する
取引先ごとにレイアウトが違う場合、すべてを一つの正規表現で処理するとルールが複雑になります。
そこで、会社名、帳票タイトル、固定ラベル、ページサイズなどからテンプレートIDを決めます。
def detect_template(text: str) -> str:
if "株式会社青空商事" in text and "御請求書" in text:
return "aozora_invoice_v1"
if "ACME SERVICE" in text and "INVOICE NO." in text:
return "acme_invoice_v2"
return "unknown"
unknownを無理に処理せず、未対応帳票として隔離します。誤ったルールを適用して正常扱いするより、調査対象として残すほうが安全です。
5. ラベル・座標・正規表現を使い分ける
抽出方法には向き不向きがあります。
- 正規表現:
請求番号: INV-1234のように形式が決まっている値 - ラベル近傍探索:
請求金額の右側や次の行に値がある帳票 - 座標抽出:毎回同じ位置に金額が印字される固定帳票
- 表抽出:品目、数量、単価が行列で並ぶ明細
- OCR:画像として保存された文字
- AI補助:レイアウトが多様で、ルール化が難しい補足欄
金額の単純な例は次のようになります。
import re
from decimal import Decimal
def extract_amount(text: str) -> Decimal | None:
match = re.search(r"請求金額[::\s]*[¥¥]?\s*([\d,]+)\s*円?", text)
if not match:
return None
return Decimal(match.group(1).replace(",", ""))
AIやLLMへ帳票全体を渡す方法は柔軟ですが、出力が毎回同じとは限らず、機密情報の取り扱いも必要です。日付、金額、番号など形式が明確な項目は、決定的に動くルールを優先します。
6. 値と一緒に抽出根拠を保存する
抽出結果には値だけでなく、出典となるページ番号、抽出方式、元文字列を持たせます。
{
"field": "invoice_total",
"value": 128000,
"page": 1,
"method": "label_regex",
"source_text": "ご請求金額 ¥128,000",
"template_id": "aozora_invoice_v1"
}
後から金額が違うと判明したとき、PDFを最初から読み直さなくても原因を追えます。この記録は監査ログ、つまり「いつ、どの根拠から値を登録したか」の履歴にもなります。
7. 業務ルールで検算する
形式が正しくても、値が正しいとは限りません。次の検算を組み合わせます。
- 明細の合計と請求合計が一致する
- 消費税額が前提の税率と矛盾しない
- 支払期限が請求日より前になっていない
- 請求書番号が過去データと重複していない
- 取引先名と振込先口座の組み合わせが登録情報と合う
- 通貨単位が前月と突然変わっていない
消費税の計算には端数処理の違いがあるため、「一致しない=必ず誤り」とは限りません。帳票の切り捨て・切り上げ規則を確認し、許容差を仕様に残します。
8. ハッシュで重複を防ぎ、処理状態を管理する
ファイル内容からSHA-256ハッシュを作り、処理済みか判定します。
from hashlib import sha256
from pathlib import Path
def file_hash(path: Path) -> str:
return sha256(path.read_bytes()).hexdigest()
同じハッシュが登録済みなら再処理しません。ただし、ファイル名が同じでも内容が更新される場合があります。そのため、ファイル名ではなく内容のハッシュを使います。
状態は少なくとも次のように分けます。
received → classified → extracted → validated → exported
└→ quarantined
途中で停止したPDFだけを再開できれば、正常な帳票まで処理し直さずに済みます。
9. 定期実行・通知・次工程まで接続する
最後に、Windowsタスクスケジューラ、cron、GitHub Actionsなどで定期実行します。メールや共有フォルダからPDFを取得し、正常データをCSVやデータベースへ保存します。
収益につなげるなら、抽出後の判断まで自動化します。
- 売上レポートから利益率低下を検知する
- 請求書と入金明細を照合して未入金候補を通知する
- 広告明細から費用対効果の悪化を検知する
- ポイント明細から失効予定を抽出して通知する
- 発注書から在庫不足候補を登録する
これらは収益を保証する仕組みではありません。規約違反となるポイント獲得操作や、サービスが禁止する自動アクセスは避けてください。ここで扱うのは、自分が適法に取得した帳票を整理し、判断に必要な情報を届ける自動化です。
専門家目線のチェックポイント
座標より「意味」を優先できるか
座標抽出は高速ですが、余白が数ミリ変わっただけで壊れる可能性があります。同じ発行元の固定帳票には有効でも、複数社の請求書にはラベル近傍探索が向いています。
判断基準は次の通りです。
- 年単位で様式が固定される帳票:座標を候補にする
- 項目の位置だけ変わる帳票:ラベルを基準にする
- 列順が変わる明細:見出し名から列を特定する
- 発行元が多い帳票:テンプレート分類を先に行う
- 手書き文字を含む帳票:無人確定の対象外も検討する
「読み取れない」と「誤って読み取る」を分ける
空欄なら処理を停止できます。一方、8を3として抽出すると、正常な数値に見えて後工程へ流れる危険があります。
特に金額、口座番号、契約番号では、OCRの信頼度だけに頼らず、明細合計やマスターデータとの照合を加えます。
人間確認をゼロにできないケースを認める
次のPDFは完全無人化に適さない場合があります。
- 手書きが多い
- 写真がぼやけている
- 表の上に印鑑が重なっている
- 毎回レイアウトが変わる
- 法的判断や承認を伴う
- 誤登録時の損失が大きい
- 外部サービスへの送信が規約や契約で制限される
この場合は、低信頼度データだけを確認画面へ回します。人間を全工程から外すのではなく、確認が必要な例外を減らし続ける設計が現実的です。
画像・スクリーンショットで説明すべき箇所
記事や社内手順書には、次の視覚資料を入れると理解が深まります。
テキストPDFと画像PDFの比較画面
左側に文字を選択できるPDF、右側にスキャン画像を配置し、抽出文字数も表示します。抽出根拠のレビュー画面
PDF上の「請求金額」を色枠で囲み、右側に抽出値、ページ番号、方式、検証結果を並べます。運用ログのスクリーンショット
成功、隔離、重複スキップ、未対応テンプレートを色分けします。視覚的証拠として、件数だけでなく対象期間と母数も写します。処理パイプライン図
受信から保存までの分岐と、失敗時にどこへ移動するかを示します。
機密情報があるPDFを掲載するときは、氏名、住所、口座番号、請求書番号をマスキングしてください。画像生成サービスへ実帳票を送信する場合も、利用規約とデータ保持条件の確認が必要です。
よくある失敗と対策
文字が一切取れない
原因: スキャンPDFをテキスト型として処理している。
対策: ページごとの抽出文字数を測り、OCRへ分岐します。OCR前に傾き補正とノイズ除去を行うと改善する場合があります。
「128,000円」を数値化できない
原因: カンマ、通貨記号、全角数字、空白が混在している。
対策: 抽出と正規化を分けます。128,000円を128000へ変換してから数値型にします。小数を扱う金額には浮動小数点ではなくDecimalを使います。
明細の列がずれる
原因: PDFにはExcelのようなセル構造がなく、文字が座標として配置されている。
対策: 見出し位置、文字のX座標、罫線を組み合わせます。複数ページの表では、各ページに繰り返されるヘッダー行を除外します。
帳票改訂のたびに停止する
原因: すべての取引先を一つのルールで処理している。
対策: テンプレートIDとバージョンを管理します。未知のレイアウトを自動確定せず、隔離して新しいルールの候補にします。
自動化したのに確認作業が減らない
原因: すべての抽出結果を人間が再確認している。
対策: 必須項目、検算結果、信頼度からレビュー条件を決めます。正常条件を満たす帳票は自動保存し、例外だけを確認対象にします。
失敗理由が分からず毎回PDFを開く
原因: 成否だけをログに残している。
対策: ファイルハッシュ、テンプレートID、失敗項目、ページ番号、元文字列、例外名を記録します。機密データをログへ出しすぎないよう、口座番号などは一部を伏せます。
成果を測るKPI
| KPI | 計算方法 | 改善の読み方 |
|---|---|---|
| 自動完了率 | 正常保存件数 ÷ 受信件数 | 無人で完結した割合 |
| 項目正解率 | 正しかった項目数 ÷ 確認項目数 | 抽出品質 |
| 隔離率 | 隔離件数 ÷ 受信件数 | 例外処理の負担 |
| 未対応テンプレート率 | 未対応件数 ÷ 受信件数 | ルール追加の優先度 |
| 重複防止件数 | ハッシュで除外した件数 | 二重登録の抑止効果 |
| 1件あたり人間作業時間 | 確認時間 ÷ 処理件数 | 時間消耗の残り具合 |
| 回収期間 | 初期構築時間 ÷ 月間削減時間 | 開発工数を時間で回収する目安 |
| 下流エラー率 | 出力後の訂正件数 ÷ 保存件数 | 業務影響を含む品質 |
たとえば「自動完了率90%」と記録する場合は、対象期間、母数、帳票の種類、手書きの有無も添えます。「A社のテキスト型請求書100件、2026年7月、手書きなし」のように条件を残せば、翌月と比較できます。
収益額をKPIにすると外部要因の影響が大きくなります。まずは削減時間、未入金候補の検知件数、転記訂正件数など、仕組みが直接動かせる指標を追います。投資判断や将来収益を保証するものではなく、業務改善を評価するための一般的な指標です。
実装前チェックリスト
- 実物PDFを発行元・形式・ページ数で分類した
- 必須項目と任意項目を分けた
- 項目ごとの停止条件を決めた
- テキスト型と画像型の分岐がある
- 未知の帳票を正常扱いしない
- 値と一緒に抽出根拠を保存する
- 明細合計などの業務検算がある
- ファイルハッシュで重複を防ぐ
- 例外PDFを隔離できる
- 途中から安全に再実行できる
- ログに機密情報を残しすぎていない
- 利用規約やデータ送信条件を確認した
今日すぐできる具体的アクション
まず、同じ種類のPDFを手元から集め、次の4列を持つ表を作ってください。
項目名 | 実際の値 | 必須か | 間違いを検知する方法
請求金額なら「128,000円|必須|明細合計と一致」、請求日なら「2026-07-12|必須|日付変換できる」と記載します。
その後、Pythonで1件だけテキストを抽出し、文字が取れるか確認します。ここまで進めれば、OCRが必要か、正規表現で対応できるか、テンプレート分類が必要かを判断できます。
まとめ:PDFを読むコードから、止まらず改善できる自動化資産へ
PythonによるPDF情報抽出では、抽出ライブラリの選択に加えて、分類、検算、重複防止、隔離、ログ、再実行まで設計する必要があります。
目指す処理の流れは明確です。
- PDFを自動受信する
- 種類とテンプレートを判定する
- 必要項目と抽出根拠を保存する
- 業務ルールで検算する
- 正常データだけを次工程へ渡す
- 例外だけを隔離して通知する
- ログから失敗の多い帳票を改善する
この循環が動けば、人間はすべてのPDFを開く作業から離れられます。請求漏れ、未入金、費用増加、ポイント失効などを検知する処理へ接続すれば、単なる転記ツールではなく、時間と機会損失を守る自動化資産になります。
完全放置や収益は保証できません。帳票改訂、OCR誤読、外部サービス障害への保守は残ります。それでも、失敗を隔離して再実行できる仕組みなら、手作業へ全面的に逆戻りする可能性を抑えられます。
本気で自動化・不労所得を構築したい方向けの実践マニュアル
PDF抽出を作っても、その後に人間がCSVを開き、数字を確認し、メールを送り、販売状況を集計していたら、時間は別の工程で消えていきます。
手離れのよい仕組みを作るには、データ取得、判定、通知、販売、記録、改善を一本の流れとして設計する必要があります。最初から巨大なシステムを作る必要はありません。毎月発生する一つの作業を選び、人間の操作が残る場所を順番に減らしていく方法があります。
「自分が作業し続けなければ止まる副業」から、「自分が離れている間も価値を生み続ける自動化資産」へ移行したい方へ、実装手順と収益導線をまとめた実践マニュアルを用意しています。
次に仕組み化する作業を、今日決めてください。