Pythonでレシート・請求書のPDFをExcelの表に変換する方法

python
自動化・詳細手順

Pythonでレシート・請求書のPDFをExcelの表に変換する方法

PDF内の表を読み取り、Excelにまとめて書き出します

プログラミング未経験OK 所要時間の目安:30分程度

この記事は、「Pythonでできる日常の自動化6選」で紹介した④PDFの明細書をExcelの表に変換の詳しい作り方をまとめた記事です。

医療費控除の集計や、請求書・レシートの整理で、PDFの中身を1つずつExcelに手入力していませんか?Pythonのpdfplumberというライブラリを使えば、PDF内の表を読み取り、Excelの表としてまとめて書き出すことができます。

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5

用意するもの

  • Python本体
  • コードを書くためのエディタ(VS Codeなど)
  • pdfplumber(PDFの中身を読み取るライブラリ)
  • openpyxl(Excelファイルを作成するライブラリ)
INFO

Pythonのインストール、コードを書くためのエディタ(VS Code)の準備、コードの書き方・実行方法がまだの方は、先に「Pythonを始める前に:インストールとエディタの準備」を済ませてから、この続きに進んでください。

ターミナルで以下のコマンドを実行し、2つのライブラリをまとめてインストールします。

pip install pdfplumber openpyxl

対応できるPDFを知っておく

PDFには、大きく分けて2つの種類があります。

種類この記事の方法で扱えるか
パソコンで作成されたPDF(請求書・明細書など、文字を選択・コピーできるもの)○ 扱える
紙の書類をスキャン・撮影しただけの画像PDF(文字を選択できないもの)× 扱えない(別途OCRが必要)
注意

お使いのPDFがどちらのタイプかは、PDFを開いて文字をドラッグして選択できるかどうかで確認できます。選択できない場合は、この記事の方法では表を読み取れません。

PDFの中身を確認してみる

まずは、PDFの中の文字情報をそのまま取得してみましょう。

import pdfplumber

with pdfplumber.open("invoice.pdf") as pdf:
    page = pdf.pages[0]  # 1ページ目
    text = page.extract_text()
    print(text)

実行すると、PDFの1ページ目に含まれる文字が、そのままテキストとして表示されます。

MEMO

invoice.pdfの部分は、実際に読み込みたいPDFファイルの名前に書き換えてください。コードと同じフォルダにPDFを置いておくとスムーズです。

PDFから表を抜き出す

文字全体ではなく、罫線で区切られた表の部分だけを抜き出したい場合は、extract_tableを使います。

import pdfplumber

with pdfplumber.open("invoice.pdf") as pdf:
    page = pdf.pages[0]
    table = page.extract_table()

for row in table:
    print(row)

実行すると、表の1行ずつがリストの形で表示されます。tableは「行のリストの中に、セルの値のリストが入っている」という二重のリスト構造になっています。

注意

PDF内に罫線などの明確な表構造がない場合、extract_tableがうまく表を認識できず、Noneが返ってくることがあります。その場合は、前のステップのextract_textで文字を取得し、自分で行ごとに分割する方法に切り替える必要があります。

MEMO

罫線を引いていない請求書のPDFを作って試したところ、Noneはエラーを出さずに返ってきて、次のfor row in table:の行でTypeError: 'NoneType' object is not iterableが出ました。このエラーが出たら、表が見つからなかったという意味です。同じPDFでもpage.extract_table({"vertical_strategy": "text", "horizontal_strategy": "text"})と書くと、文字の並びから表を拾えました。ただし中身が空の行が1行混ざったので、書き出したあとで確かめてください。

もう一つ、1ページに表が2つある(明細の下に振込先の表がある、など)と、extract_table()は大きいほうの1つだけを返します。エラーは出ず、振込先の表は黙って消えました。全部ほしいときはextract_tables()(最後に s が付く)を使うと、表の数だけリストで返ってきます。

抜き出した表をExcelに書き出す

取得した表のデータを、openpyxlでそのままExcelファイルに書き出します。

import pdfplumber
import openpyxl

with pdfplumber.open("invoice.pdf") as pdf:
    page = pdf.pages[0]
    table = page.extract_table()

wb = openpyxl.Workbook()
ws = wb.active
ws.title = "明細"

for row in table:
    ws.append(row)

wb.save("invoice.xlsx")
print("Excelへの変換が完了しました")

実行すると、PDFの表と同じ内容のinvoice.xlsxが作成されます。ws.append(row)は、リストの中身を1行分のデータとしてそのままシートに追加してくれる書き方です。

実際に動かすと、こうなります

請求書のPDF。品名・数量・単価・金額の4列の表に、事務用品4点と合計6680円が並んでいる
読み込ませたPDFです。品名・数量・単価・金額の4列で、いちばん下が合計6,680円。よくある請求書の形です。
Excelに変換された結果。PDFと同じ4列6行の表がセルに入っている
できあがった invoice.xlsx です。PDFの表がそのままセルに入りました。数字の左上に緑の三角が付いているのは、「数値ではなく文字列として入っている」という Excel の印です。extract_table()は中身を文字列で返すので、こうなります。計算に使いたいときは、Excel側で数値に変換してください。

Python側で数値にしておくこともできます。"1,100"のようにカンマが入っているので、カンマを取ってからint()で変換します。

def to_num(value):
    try:
        return int(value.replace(",", ""))
    except (ValueError, AttributeError):
        return value  # 品名や空欄は、そのまま残す

for row in table:
    ws.append([to_num(v) for v in row])

上のコードのfor row in table: ws.append(row)の部分を、これに置き換えます。試したPDFでは、品名はそのまま、"1,100"は数値の1100になり、緑の三角も付かなくなりました。

複数のPDFをまとめて処理する

同じ形式のPDFが複数枚あるとき(月ごとの請求書や、複数のレシートなど)は、フォルダ内のすべてのPDFをまとめて1つのExcelにできます。

from pathlib import Path
import pdfplumber
import openpyxl

pdf_dir = Path("receipts")  # PDFが入っているフォルダ

wb = openpyxl.Workbook()
ws = wb.active
ws.title = "明細一覧"

for pdf_file in pdf_dir.glob("*.pdf"):
    with pdfplumber.open(pdf_file) as pdf:
        for page in pdf.pages:
            table = page.extract_table()
            if table:
                for row in table:
                    ws.append(row)

wb.save("receipts_summary.xlsx")
print("すべてのPDFの変換が完了しました")

pdf_dir.glob("*.pdf")で、指定したフォルダ内のPDFファイルを1つずつ順番に処理しています。PDFが何ページあっても、すべてのページの表がまとめてreceipts_summary.xlsxに書き出されます。

MEMO

2ページの請求書と1ページの請求書(2ファイル・計3ページ)で試すと、「品名・数量・単価・金額」の見出し行が3回入りました。表はページごとに見出しから始まるためです。また、できた一覧にはどのPDFの行なのかが残りません。ws.append([pdf_file.name] + row)と書くと、A列にファイル名が入ります。

ファイルを処理する順番は、glob()では決まっていません。月の順に並べたいときはfor pdf_file in sorted(pdf_dir.glob("*.pdf")):のようにsorted()で囲み、ファイル名を「2026-07.pdf」のような日付の形にしておくと、その順になります。

うまくいかないときのトラブルシューティング

extract_table()がNoneを返してきます▼
PDF内に罫線などの明確な表構造がないと、表として認識されないことがあります。「PDFから表を抜き出す」の注意書きの通り、extract_text()で文字を取得し、行ごとに手動で分割する方法に切り替えてください。
スキャンした紙のレシートを撮影したPDFでも使えますか?▼
画像だけで構成されたPDF(文字情報を持たないもの)には、この記事の方法は使えません。文字を認識するには、OCR(光学文字認識)という別の技術が必要になります(この記事の範囲外です)。
日本語がうまく取得できません▼
pdfplumberは日本語のPDFにも基本的に対応していますが、PDF作成時のフォントの埋め込み方によっては、まれにうまく取得できないことがあります。その場合は、別のPDFで試すか、文字が正しく選択・コピーできるPDFかどうかを確認してください。

まとめ

pdfplumberとopenpyxlを使って、PDF内の表を読み取りExcelに変換する方法、複数のPDFをまとめて処理する方法を紹介しました。医療費控除の集計や請求書整理など、手入力が面倒な作業ほど自動化のメリットを実感しやすくなります。

他の自動化アイデアも見てみる

家計簿の自動集計やファイル整理など、Pythonでできる生活の自動化アイデアを6つ紹介しています。

6テーマ一覧を見る

コメント

タイトルとURLをコピーしました