0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PDF見積書の確認漏れを減らすチェック補助ツールの作り方

0
Posted at

最近、PDFの見積書を見ながらExcelへ転記する作業を整理していて、あらためて感じたことがあります。

PDF読み取りは、いきなり完全自動化を狙うよりも、「確認すべき項目を一覧にする」くらいから始めたほうが現場に入りやすいです。特に見積書や注文書は、会社ごとにレイアウトが違いますし、同じ会社でも微妙に表記が変わることがあります。

この記事では、PythonでPDF見積書から必要な情報を抜き出し、確認用のExcelを作る小さな補助ツールの考え方を書きます。読み取り精度を過信せず、人が最後に確認しやすい形へ整えることを主目的にします。

PDF確認で起きやすいミス

PDF見積書の確認で多いのは、単純な転記ミスだけではないと思います。

たとえば、次のようなものです。

  • 見積番号を別案件のものと取り違える
  • 日付や有効期限を見落とす
  • 税抜、税込、消費税額の関係が合っていない
  • 明細の数量や単価を1行だけ読み飛ばす
  • PDFには書いてあるが、Excel側に転記されていない
  • 備考欄の条件を確認し忘れる

実際にやってみると、金額そのものよりも「確認したつもり」の項目が抜けることがあります。だからこそ、ツール側では正解を断定するより、要確認の場所を見えるようにするほうが扱いやすいと感じています。

完全自動化にしない理由

PDFは見た目が同じでも、中身のテキスト構造が同じとは限りません。

文字として埋め込まれているPDFなら、pdfplumberPyMuPDF でテキストを取り出せることがあります。一方で、スキャン画像のPDFではOCRが必要になります。さらに、表の罫線や改行位置によって、明細行がきれいに取れたり、1行が分割されたりします。

ただ、業務で最初にほしいのは「100%自動で登録される仕組み」ではなく、「確認に使える一覧」だったりします。

たとえば、次のようなExcelを出すだけでも、確認作業はかなり楽になります。

ファイル名 見積番号 取引先 見積日 合計金額 税額 要確認
estimate_001.pdf Q-2026-001 株式会社A 2026/07/01 110,000 10,000
estimate_002.pdf 未取得 株式会社B 2026/07/02 220,000 未取得 見積番号、税額

この形なら、ツールが取り切れなかった項目も人がすぐ気づけます。個人的には、この「未取得を隠さない」設計が地味に重要です。

抽出したい項目を決める

まずは、PDFから何を取りたいかを絞ります。最初から全項目を対象にすると、レイアウト差分に引っ張られて進みにくくなります。

最小版なら、次の項目くらいで十分だと思います。

  • ファイル名
  • 見積番号
  • 取引先名
  • 見積日
  • 有効期限
  • 小計
  • 消費税
  • 合計金額
  • 備考の有無
  • 要確認メモ

ここで大事なのは、「Excelに出す項目」と「自動判定したい項目」を分けることです。

たとえば、備考欄の文章を完全に解釈するのは難しいです。一方で、「備考」「条件」「納期」「支払」などの文字が含まれていたら、要確認にすることはできます。

最小構成

例として、テキストPDFを対象にした最小構成を考えます。

使うライブラリは、PDF読み取りに pdfplumber、Excel出力に openpyxl です。画像PDFやスキャンPDFを扱う場合は、別途OCRを組み合わせます。

pip install pdfplumber openpyxl

コードはかなり簡略化していますが、流れはこのようになります。

import re
from pathlib import Path

import pdfplumber
from openpyxl import Workbook

PDF_DIR = Path("pdfs")
OUT_FILE = "estimate_check.xlsx"

def extract_text(pdf_path: Path) -> str:
    texts = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            texts.append(page.extract_text() or "")
    return "\n".join(texts)

def find_value(pattern: str, text: str):
    match = re.search(pattern, text)
    return match.group(1).strip() if match else ""

def check_pdf(pdf_path: Path):
    text = extract_text(pdf_path)

    data = {
        "file": pdf_path.name,
        "estimate_no": find_value(r"見積番号[::]?\s*([A-Za-z0-9\-]+)", text),
        "date": find_value(r"見積日[::]?\s*([0-9]{4}[/-][0-9]{1,2}[/-][0-9]{1,2})", text),
        "total": find_value(r"合計金額[::]?\s*¥?\s*([0-9,]+)", text),
        "tax": find_value(r"消費税[::]?\s*¥?\s*([0-9,]+)", text),
    }

    warnings = []
    if not data["estimate_no"]:
        warnings.append("見積番号")
    if not data["date"]:
        warnings.append("見積日")
    if not data["total"]:
        warnings.append("合計金額")
    if not data["tax"]:
        warnings.append("消費税")
    if "備考" in text or "支払" in text or "納期" in text:
        warnings.append("備考確認")

    data["warnings"] = "".join(warnings)
    return data

wb = Workbook()
ws = wb.active
ws.title = "確認一覧"
ws.append(["ファイル名", "見積番号", "見積日", "合計金額", "消費税", "要確認"])

for pdf_path in PDF_DIR.glob("*.pdf"):
    row = check_pdf(pdf_path)
    ws.append([
        row["file"],
        row["estimate_no"],
        row["date"],
        row["total"],
        row["tax"],
        row["warnings"],
    ])

wb.save(OUT_FILE)

このコードは万能ではありません。むしろ、最初のたたき台です。

ただ、実務ではこの段階でも見えるものがあります。どのPDFは読めるのか、どの項目が安定しないのか、どの取引先だけ別対応が必要なのかが分かります。

要確認を出す

確認補助ツールで大切なのは、値を抜く処理よりも、抜けたときの扱いです。

よくないのは、空欄のままExcelに出して終わる形です。空欄が「存在しない」のか「読み取れなかった」のかが分からないため、結局PDFを全部見直すことになります。

だからこそ、要確認列を作ります。

たとえば、次のようなルールです。

  • 見積番号が取れなければ「見積番号」
  • 合計金額が取れなければ「合計金額」
  • 合計金額は取れたが税額が取れなければ「税額」
  • 備考、条件、支払、納期という文字があれば「備考確認」
  • OCR対象になったPDFは「OCR結果確認」

この前提があると、ツールは「判断するもの」ではなく「確認箇所を減らすもの」になります。現場で使うには、このくらいの割り切りがちょうどよいことがあります。

失敗しやすい点

まず、PDFが画像かテキストかを確認したほうがよいです。

テキストPDFなら、文字列抽出である程度進められます。一方で、スキャンPDFはOCRが必要です。pytesseract を使う場合も、Pythonライブラリだけでなく、Tesseract本体のインストールやPATH設定が必要になります。

次に、正規表現を強くしすぎないことです。

最初から「見積番号は必ずこの形式」と決めると、少し違うPDFで取れなくなります。実際には、取引先ごとに表記が違うため、共通ルールと個別ルールを分けておくと保守しやすいです。

金額も注意が必要です。

110,000110000¥110,000税込 110,000円 のように表記が揺れます。抽出後にカンマや円記号を除去して数値化する処理を入れると、Excel側で比較しやすくなります。

進め方

個人的には、いきなり全PDFに対応させるより、次の順番で進めるのが現実的だと思います。

  1. よく使うPDFを10件ほど集める
  2. 取りたい項目を5〜8個に絞る
  3. まずはテキスト抽出だけで一覧化する
  4. 未取得項目を要確認として出す
  5. 取引先ごとの表記ゆれを追加する
  6. 必要になってからOCRを足す

実際にやってみると、全体の8割くらいは単純なルールで拾えて、残りの2割が個別対応になることがあります。最初から2割に合わせると作りが重くなるので、まずは一覧化して傾向を見るほうが判断しやすいです。

まだ迷っている点

PDF確認補助は、作り込みすぎると運用が難しくなります。

たとえば、取引先ごとに細かいルールを増やすと、精度は上がります。一方で、PDFレイアウトが変わったときに気づきにくくなります。どこまで個別対応するかは、件数と確認コストのバランスで決めるのがよさそうです。

また、OCRを入れるかどうかも迷いどころです。

OCRを入れると対象PDFは広がりますが、誤読も増えます。見積番号の O0、金額の桁、日付の区切りなどは特に確認が必要です。OCR結果をそのまま正として扱うより、「OCRで読んだので確認」という印を付けるほうが安心だと思います。

まとめ

PDF見積書の確認作業は、完全自動化よりも確認補助から始めると進めやすいです。

まずは、PDFから見積番号、日付、金額などを抜き出し、Excelに一覧化します。そのうえで、取れなかった項目や注意が必要な項目を「要確認」として出します。

この形にしておくと、人が見るべき場所が絞られます。読み取り精度を上げることも大事ですが、読み取れなかったことを分かりやすく出すほうが、実務では効くことがあります。

参考にした公式ドキュメントです。

同じようなPDF見積書や注文書の確認作業を、社内業務に合わせて小さく試作したい場合は、サンプルデータから無料相談できます。入力PDFと出力したいExcelの形を整理するところから一緒に確認できます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?