請求書、見積書、領収書、申込書、検査票などのPDF帳票を開き、金額や日付を探してExcelへ転記していませんか。
この作業は「慣れれば早い」と思われがちですが、件数が増えるほど次の問題が出ます。
- 入力ミスが起きる
- ファイル名を取り違える
- 確認漏れが発生する
- 担当者しか処理できない
- 毎月同じ作業に時間を取られる
PDF帳票処理は、Pythonで自動化しやすい業務の一つです。ただし、いきなりコードを書き始めると失敗します。重要なのは、PDFの種類を見分け、抽出項目を絞り、検証ルールとログまで含めて設計することです。
この記事では、初心者向けに PythonでPDF帳票から必要情報を抽出する基本設計 を、手順・失敗対策・KPIまで含めて解説します。
この記事で分かること
- PythonでPDF帳票を自動抽出する全体像
pdfplumberを使うべきPDFと、OCRが必要なPDFの見分け方- 請求番号、金額、日付を抽出する基本コード
- 抽出ミスを防ぐ検証ルール
- CSVやスプレッドシートへ出力する流れ
- 運用時に見るべきKPI
- 自動化してよい帳票、慎重に扱うべき帳票の判断基準
実行ログ:Hiro環境での最小検証
この記事では一般論だけでなく、Hiroのローカル環境で実行した最小検証ログを前提にします。
hiro_pdf_extract_smoke_test
date=2026-07-12 timezone=Asia/Tokyo
engine=python 3.11.9 pdfplumber
samples=3 elapsed_ms=8.6
texts=
- Invoice No: A-001 Amount: 12800 Due: 2026-07-31
- Invoice No: A-002 Amount: 9800 Due: 2026-08-15
- Invoice No: A-003 Amount: 45000 Due: 2026-08-31
検証内容は、メモリ上で作成した最小構成のPDFを3件読み込み、pdfplumberでテキスト抽出したものです。
注意点があります。このログは、実務帳票の処理速度や精度を保証するものではありません。実務のPDFには、罫線、複数ページ、縦書き、画像スキャン、文字化け、表の崩れ、発行元ごとのレイアウト差があります。
ただし、次の判断材料にはなります。
- テキスト情報を持つPDFなら、Pythonで抽出できる可能性が高い
- 最初の検証は小さく始められる
- 本番化する前に、成功数・失敗数・確認待ち件数をログ化すべき
PDF情報抽出の全体像
PythonでPDF帳票から情報を抽出する流れは、次の4段階です。
読む
PDFをPythonで開き、文字や表を取り出します。探す
抽出したテキストから、請求番号、金額、日付などを見つけます。整える
金額のカンマを外す、日付形式をそろえる、空欄をエラーにするなどの処理を行います。流す
CSV、Excel、Googleスプレッドシート、会計ソフト、通知ツールなどへ渡します。
ここまで作ると、人間の役割は「全件転記」ではなく「例外確認」に変わります。これがPDF帳票自動化の大きな価値です。
ステップ1:対象PDFの種類を判定する
最初に、PDFがどの種類かを確認します。
| 種類 | 特徴 | 主な対応 |
|---|---|---|
| テキストPDF | 文字を選択・コピーできる | pdfplumberなどで抽出 |
| 画像PDF | スキャン画像だけで文字選択できない | OCRが必要 |
| 混在PDF | 一部は文字、一部は画像 | テキスト抽出とOCRを併用 |
確認方法は簡単です。PDFビューアで金額や日付をドラッグし、コピーできるか試します。
コピーできるなら、テキストPDFの可能性が高いです。コピーできないなら、OCRが必要になる可能性があります。OCRとは、画像内の文字を読み取る技術です。たとえば、スキャンされた領収書画像から「税込 12,800円」を読み取る処理です。
ここを確認せずに進めると、「コードは正しいのに何も抽出できない」という失敗が起きます。
ステップ2:抽出項目を決める
初心者が失敗しやすいのは、「PDFの中身を全部取りたい」と考えることです。
最初は、業務に必要な項目だけに絞ります。
| 項目 | 例 | 必須か | エラー時の扱い |
|---|---|---|---|
| 請求番号 | A-001 | 必須 | 処理停止 |
| 請求日 | 2026-07-12 | 必須 | 要確認リストへ |
| 支払期限 | 2026-07-31 | 任意 | 空欄許可 |
| 金額 | 12800 | 必須 | 処理停止 |
| 取引先名 | ABC株式会社 | 任意 | 空欄許可 |
設計のポイントは、必須項目と任意項目を分けることです。
必須項目が欠けたPDFは自動処理せず、確認待ちに回します。任意項目は空欄を許可します。この切り分けがあると、1件の例外で全体の処理が止まることを防げます。
ステップ3:PDFからテキストを取り出す
テキストPDFなら、まずpdfplumberで抽出を試します。
import pdfplumber
pdf_path = "invoice.pdf"
with pdfplumber.open(pdf_path) as pdf:
text = "\n".join(page.extract_text() or "" for page in pdf.pages)
print(text)
この段階では、まだデータを整えません。まずは生の抽出結果を見ます。
確認するポイントは次の通りです。
- 請求番号が取れているか
- 金額が取れているか
- 日付が取れているか
- 表の列順が崩れていないか
- 改行位置が不自然ではないか
- 全角スペースや余計な記号が混ざっていないか
抽出結果はファイルに保存しておくと、後で正規表現を調整しやすくなります。
from pathlib import Path
Path("debug_extracted_text.txt").write_text(text, encoding="utf-8")
ステップ4:正規表現で必要項目を抜き出す
正規表現とは、文字のパターンを指定して検索する方法です。
たとえば、次の文字列から請求番号、金額、支払期限を取り出します。
Invoice No: A-001 Amount: 12800 Due: 2026-07-31
基本コードは次の通りです。
import re
text = "Invoice No: A-001 Amount: 12800 Due: 2026-07-31"
invoice_no = re.search(r"Invoice No:\s*(\S+)", text)
amount = re.search(r"Amount:\s*([0-9,]+)", text)
due = re.search(r"Due:\s*([0-9]{4}-[0-9]{2}-[0-9]{2})", text)
row = {
"invoice_no": invoice_no.group(1) if invoice_no else None,
"amount": int(amount.group(1).replace(",", "")) if amount else None,
"due": due.group(1) if due else None,
}
print(row)
日本語帳票では、表記ゆれを想定します。
amount = re.search(r"請求金額[::]?\s*([0-9,]+)\s*円?", text)
date = re.search(
r"請求日[::]?\s*([0-9]{4})年([0-9]{1,2})月([0-9]{1,2})日",
text,
)
正規表現は、1本で全部取ろうとしない方が安全です。請求番号、金額、日付、取引先名を別々に抽出し、それぞれ検証します。
ステップ5:抽出結果を検証する
PDF抽出で最も重要なのは、抽出後の検証です。
「文字が取れた」だけでは不十分です。間違った金額や日付をそのままCSVに流すと、手作業より危険になります。
検証ルールの例です。
| 項目 | 検証ルール | 異常時の扱い |
|---|---|---|
| 請求番号 | 空欄ではない、過去データと重複しない | 確認待ち |
| 金額 | 0円より大きい、上限額を超えない | 処理停止または確認待ち |
| 日付 | 想定期間内にある | 確認待ち |
| 明細合計 | 合計金額と一致する | 確認待ち |
| 取引先名 | 登録済み取引先と一致する | 確認待ち |
簡単な検証コードは次のように書けます。
def validate_row(row):
errors = []
if not row.get("invoice_no"):
errors.append("invoice_no is missing")
if row.get("amount") is None:
errors.append("amount is missing")
elif row["amount"] <= 0:
errors.append("amount must be greater than 0")
if not row.get("due"):
errors.append("due date is missing")
return errors
検証結果によって、処理先を分けます。
success/
needs_review/
failed/
この分類にすると、人間は全PDFを確認する必要がありません。確認すべきPDFだけに集中できます。
ステップ6:CSVに出力する
最初の出力先はCSVがおすすめです。Excel、Googleスプレッドシート、BIツール、会計ソフト連携の入口にしやすいからです。
import csv
rows = [
{"invoice_no": "A-001", "amount": 12800, "due": "2026-07-31"},
{"invoice_no": "A-002", "amount": 9800, "due": "2026-08-15"},
]
with open("extracted_invoices.csv", "w", newline="", encoding="utf-8-sig") as f:
writer = csv.DictWriter(f, fieldnames=["invoice_no", "amount", "due"])
writer.writeheader()
writer.writerows(rows)
encoding="utf-8-sig"にしておくと、Excelで開いたときに文字化けしにくくなります。
出力ファイルには、抽出結果だけでなく、元PDFのファイル名も入れると後から確認しやすくなります。
source_file,invoice_no,amount,due,status
invoice_A001.pdf,A-001,12800,2026-07-31,success
ステップ7:ログを残す
定期運用するなら、ログは必須です。
ログがないと、次のことが分かりません。
- 何件処理したか
- 何件成功したか
- 何件確認待ちになったか
- どのPDFで失敗したか
- 前回より改善したか
最低限、次の形式で残します。
run_date=2026-07-12
input_files=42
success=39
needs_review=3
failed=0
output=extracted_invoices.csv
実務ではJSON形式にすると、後から集計しやすくなります。
{
"run_date": "2026-07-12",
"input_files": 42,
"success": 39,
"needs_review": 3,
"failed": 0,
"output": "extracted_invoices.csv"
}
ログは「動いた証拠」ではなく、改善の材料です。確認待ちが多い帳票を見れば、正規表現を直すべきか、OCRを入れるべきか、帳票フォーマットを変えるべきか判断できます。
ステップ8:定期実行する
手作業でPythonを実行するだけでは、自動化の効果は限定的です。定期実行まで設計します。
代表的な方法は次の通りです。
| 実行環境 | 方法 |
|---|---|
| Windows | タスクスケジューラ |
| Linuxサーバー | cron |
| GitHub | GitHub Actionsのスケジュール実行 |
| クラウド | Cloud Run、Cloud Functionsなど |
初心者は、まずローカルPCの決まったフォルダで試すのが現実的です。
例です。
input/
invoice_A001.pdf
invoice_A002.pdf
output/
extracted_invoices.csv
logs/
run_2026-07-12.json
needs_review/
invoice_error_001.pdf
このようにフォルダを分けると、処理済み、確認待ち、失敗が見分けやすくなります。
専門家目線のチェックポイント
帳票フォーマットは本当に固定か
同じ会社の請求書でも、部署、発行システム、月、ページ数によってレイアウトが変わることがあります。
最低でも、次のパターンを集めて確認します。
- 金額の桁数が違うPDF
- 明細行が1行のPDF
- 明細行が複数行のPDF
- 2ページ以上のPDF
- 取引先名が長いPDF
- 消費税や割引が含まれるPDF
Hiro環境の検証は3件の最小PDFでした。これは動作確認としては十分ですが、本番判断には足りません。実務では、10件から30件程度のサンプルを集め、抽出成功率と要確認率を測る方が安全です。
OCR前提の帳票は誤認識を見込む
画像PDFではOCRが必要です。ただし、OCRは必ず誤認識します。
よくある誤認識は次の通りです。
1とI0とO8とB円の欠落- 桁区切りカンマの欠落
- 日付の区切り文字の読み違い
金額、契約番号、請求番号のように誤りの影響が大きい項目は、OCR結果をそのまま使わず、検証ルールを必ず入れます。
最初から完全自動化を狙うより、次の順序が堅実です。
- 全件を人間確認する
- 抽出結果と人間確認結果を比較する
- 誤抽出パターンを記録する
- 異常値だけ確認する運用に変える
- 一定期間問題がなければ自動承認範囲を広げる
後続アクションまで設計する
PDF抽出そのものはゴールではありません。抽出したデータを何に使うかが重要です。
例です。
| 抽出項目 | 後続アクション | |
|---|---|---|
| 請求書PDF | 請求番号、金額、支払期限 | 入金予定表、未回収アラート |
| 仕入れ明細PDF | 商品名、単価、数量 | 単価差異検出 |
| 広告レポートPDF | 費用、CV数、CPA | 停止候補広告の抽出 |
| ポイント明細PDF | 利用額、付与ポイント | 還元率集計 |
収益やポイントの改善を狙う場合も、利益を保証するものではありません。価値があるのは、人間が毎回PDFを開いて判断する状態から、機械が候補を出す状態へ変えられることです。
画像で説明すべき処理フロー
PDF抽出の記事では、処理フローを画像で示すと理解しやすくなります。
含める要素は次の通りです。
- 左:請求書PDF、領収書PDF、レポートPDF
- 中央:Python処理、テキスト抽出、正規表現、検証
- 右:CSV、Googleスプレッドシート、通知、会計ソフト
- 下部:ログ、エラーリスト、人間確認キュー
説得力を上げるなら、次の3点を並べるとよいです。
- 抽出前のPDF
- 抽出後のCSV
- 実行ログ
特に、成功数、確認待ち数、失敗数が見えるログは重要です。単なるAI風の説明ではなく、実際に運用できる仕組みとして伝わります。
よくある失敗と対策
失敗1:PDFなら全部同じ方法で読めると思う
テキストPDFと画像PDFでは処理方法が違います。画像PDFにpdfplumberを使っても、文字が取れないことがあります。
対策は、最初に文字選択できるか確認することです。文字選択できない場合は、OCR前提で設計します。
失敗2:抽出項目を増やしすぎる
最初から全項目を抽出しようとすると、設計が複雑になります。
対策は、業務上必要な項目から始めることです。請求番号、金額、日付のように、後続処理に必要な項目を優先します。
失敗3:正規表現を複雑にしすぎる
1本の巨大な正規表現で全部取ろうとすると、修正が難しくなります。
対策は、項目ごとに小さく分けることです。抽出できなかった項目だけを個別に調整できるようにします。
失敗4:例外処理がない
1件の形式違いで全体が止まる設計は危険です。
対策は、成功、確認待ち、失敗を分けることです。確認待ちだけを人間が見ればよい状態にします。
失敗5:ログを残していない
ログがないと、どのPDFで失敗したのか、改善したのかが分かりません。
対策は、毎回の処理件数、成功件数、確認待ち件数、失敗件数、出力先を記録することです。
失敗6:完全自動化を急ぎすぎる
帳票の品質が安定していない段階で完全自動化すると、誤抽出に気づけません。
対策は、段階的に自動化率を上げることです。
- 抽出だけ自動化する
- 全件を人間確認する
- 異常値だけ人間確認する
- 一定期間のログを見て自動承認範囲を広げる
- 例外だけ通知する
成果を測るKPI
PDF抽出の改善は、感覚ではなくKPIで測ります。
| KPI | 見る理由 | 例 |
|---|---|---|
| 抽出成功率 | 自動処理できた割合を見る | 100件中92件成功 |
| 要確認率 | 人間作業の残量を見る | 100件中8件確認 |
| 誤抽出件数 | 自動化の危険度を見る | 金額誤り1件 |
| 1件あたり処理時間 | 時間削減効果を見る | 手作業3分、Python処理数秒 |
| 再実行回数 | 運用の安定度を見る | 月3回再実行 |
| 修正にかかった時間 | 保守コストを見る | 月30分 |
| 後続アクション検知件数 | 業務効果を見る | 未回収候補2件、単価差異5件 |
数字を書くときは、必ず前提条件を添えます。
悪い例です。
抽出成功率92%
良い例です。
2026年7月の請求書PDF100件を対象に、請求番号・金額・支払期限の3項目を抽出した結果、92件が自動処理成功、8件が確認待ち。
前提がある数字は、改善にも比較にも使えます。
使えないケースと限界
PythonによるPDF情報抽出は強力ですが、万能ではありません。
次のケースでは慎重に設計します。
- 手書き文字が多い帳票
- 解像度が低いスキャンPDF
- レイアウトが毎回変わるPDF
- 縦書きや複雑な表が多いPDF
- 法務、税務、医療など高リスク領域の帳票
- 発行元システムの変更でレイアウトが変わる帳票
特に、金額や契約内容に関わる帳票では、監視なしの完全自動化は危険です。
現実的な運用は、次の形です。
- 正常値は自動処理する
- 異常値は確認待ちにする
- 失敗したPDFはログに残す
- 定期的にサンプル検査する
- フォーマット変更があったら抽出ルールを見直す
反論:手作業の方が早いのでは?
少量のPDFなら、手作業の方が早い場合があります。
たとえば、月に3件だけの請求書なら、Python自動化に時間をかける必要はないかもしれません。
自動化を検討すべき目安は次の通りです。
- 毎月同じ種類のPDFが10件以上ある
- 転記ミスが起きると影響が大きい
- 確認項目が毎回同じ
- 担当者以外でも処理できるようにしたい
- 後続の集計や通知まで自動化したい
逆に、帳票形式が毎回違い、件数も少なく、後続処理もないなら、無理に自動化しない判断も正しいです。
読了後すぐに取れるアクション
今日やることは、コードを書くことではありません。まず対象PDFを5件集めて、次の表を埋めます。
| チェック項目 | 記入例 |
|---|---|
| PDFの種類 | テキストPDF / 画像PDF / 混在PDF |
| 抽出したい項目 | 請求番号、金額、支払期限 |
| 必須項目 | 請求番号、金額 |
| 任意項目 | 取引先名、備考 |
| 例外条件 | 金額空欄、日付なし、重複番号 |
| 出力先 | CSV、Googleスプレッドシート |
| 後続アクション | 未回収通知、利益率チェック |
| 確認担当 | 経理担当、運用担当 |
| 成功基準 | 抽出成功率90%以上、誤抽出0件 |
この表が埋まれば、設計の半分は終わっています。逆に、この表が曖昧なままコードを書き始めると、途中で作り直しになりやすいです。
まとめ:PDF抽出は「転記の自動化」ではなく「例外だけを見る仕組み」
PythonでPDF帳票から情報抽出する基本設計は、次の流れです。
- PDFの種類を判定する
- 抽出項目を決める
- Pythonでテキストを取り出す
- 正規表現や表抽出で必要情報を抜く
- 必須項目と異常値を検証する
- CSVやスプレッドシートへ出力する
- ログを残す
- 定期実行する
- KPIを見て改善する
- 後続アクションへ接続する
PDF抽出の目的は、単にCSVを作ることではありません。毎月発生する帳票処理を、人間が全件見る状態から、機械が大半を処理し、人間は例外だけを見る状態へ変えることです。
そのためには、コードだけでなく、検証ルール、ログ、確認待ちフロー、KPIまで含めて設計する必要があります。
まずは5件のPDFで小さく試し、抽出結果とログを見ながら改善してください。そこから、定期実行、通知、スプレッドシート連携へ広げるのが、失敗しにくい進め方です。
本気で自動化・不労所得を構築したい方向けの実践マニュアル
PDF帳票の情報抽出は、自動化資産づくりの入口です。
本当に狙うべきは、データ収集、判定、通知、実行、記録までが人間の手を離れて回り続ける仕組みです。
「毎日PDFを開く」「毎月Excelに転記する」「利益が出そうな情報を目視で探す」
この繰り返しから抜け出したい方は、次に実践マニュアルで具体的な型を確認してください。