Pythonでレシート・請求書のPDFをExcelの表に変換する方法
PDF内の表を読み取り、Excelにまとめて書き出します
この記事は、「Pythonでできる日常の自動化6選」で紹介した④PDFの明細書をExcelの表に変換の詳しい作り方をまとめた記事です。
医療費控除の集計や、請求書・レシートの整理で、PDFの中身を1つずつExcelに手入力していませんか?Pythonのpdfplumberというライブラリを使えば、PDF内の表を読み取り、Excelの表としてまとめて書き出すことができます。
- 1
- 2
- 3
- 4
- 5
用意するもの
- Python本体
- コードを書くためのエディタ(VS Codeなど)
- pdfplumber(PDFの中身を読み取るライブラリ)
- openpyxl(Excelファイルを作成するライブラリ)
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ページ目に含まれる文字が、そのままテキストとして表示されます。
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で文字を取得し、自分で行ごとに分割する方法に切り替える必要があります。
罫線を引いていない請求書の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行分のデータとしてそのままシートに追加してくれる書き方です。
実際に動かすと、こうなります
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に書き出されます。
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を返してきます▼extract_text()で文字を取得し、行ごとに手動で分割する方法に切り替えてください。まとめ
pdfplumberとopenpyxlを使って、PDF内の表を読み取りExcelに変換する方法、複数のPDFをまとめて処理する方法を紹介しました。医療費控除の集計や請求書整理など、手入力が面倒な作業ほど自動化のメリットを実感しやすくなります。


コメント