AWSの請求書管理、特に複数アカウントの請求書を扱う場合、手作業での処理は時間がかかり、ミスも発生しやすいものです。この記事では、Pythonを使ってAWSの請求書PDFから必要な情報を自動で抽出し、CSV形式で出力する方法をご紹介します。
本スクリプトの主な特徴
- PDF形式の請求書から直接データを抽出
- 日本円(税抜)の金額を自動計算
- 複数PDFの一括処理が可能
- 顧客名、請求書番号、請求日などの情報も同時に取得
- 結果をCSV形式で出力(Excel等での後続の処理が容易)
目次
開発環境の準備
Pythonのインストール
- Python公式サイト (https://www.python.org/downloads/) にアクセス
- 最新版のPythonをダウンロード
- インストーラーを実行
- 重要:「Add Python to PATH」にチェックを入れる
- インストールの確認
python --version
推奨エディタ:VSCode
- Visual Studio Code (https://code.visualstudio.com/)
- Python拡張機能をインストール
必要なライブラリのインストール
コマンドプロンプトで以下のコマンドを実行:
pip install pdfplumber
完成版スクリプト
import pdfplumber
import re
import os
from datetime import datetime
import tkinter as tk
from tkinter import filedialog, messagebox
import csv
def extract_jpy_amount(text):
"""テキストから税抜きJPY金額を抽出する関数"""
pattern = r"Net Charges \(After Credits/Discounts, excl\. Tax\).*?JPY\s+([0-9,]+)"
match = re.search(pattern, text)
return int(match.group(1).replace(',', '')) if match else None
def extract_customer_name(filename):
"""ファイル名から顧客名を抽出する関数"""
match = re.search(r'【(.+?)】', filename)
return match.group(1) if match else "Unknown"
def process_pdf_invoice(pdf_path):
"""PDFファイルから請求情報を抽出する関数"""
try:
with pdfplumber.open(pdf_path) as pdf:
text = ''
for page in pdf.pages:
text += page.extract_text()
invoice_number = re.search(r"Tax Invoice Number: ([\w-]+)", text)
invoice_number = invoice_number.group(1) if invoice_number else "Unknown"
invoice_date = re.search(r"Tax Invoice Date: ([^\n]+)", text)
invoice_date = invoice_date.group(1) if invoice_date else "Unknown"
amount = extract_jpy_amount(text)
customer_name = extract_customer_name(os.path.basename(pdf_path))
return {
'customer_name': customer_name,
'invoice_number': invoice_number,
'invoice_date': invoice_date,
'amount': amount,
'filename': os.path.basename(pdf_path)
}
except Exception as e:
return {'error': str(e)}
def select_file_or_folder():
"""ファイルまたはフォルダを選択するダイアログを表示"""
root = tk.Tk()
root.withdraw()
print("\n処理方法を選択してください:")
print("1: 単一のPDFファイルを処理")
print("2: フォルダ内のすべてのPDFを処理")
choice = input("選択 (1 or 2): ")
if choice == "1":
file_path = filedialog.askopenfilename(
title="AWS請求書PDFを選択",
filetypes=[("PDF files", "*.pdf")]
)
return [file_path] if file_path else []
else:
folder_path = filedialog.askdirectory(
title="PDFファイルが含まれるフォルダを選択"
)
if folder_path:
return [os.path.join(folder_path, f) for f in os.listdir(folder_path)
if f.endswith('.pdf')]
return []
def main():
"""メイン処理"""
print("AWS請求書PDF解析ツール")
print("-" * 50)
if not os.path.exists('results'):
os.makedirs('results')
pdf_files = select_file_or_folder()
if not pdf_files:
print("PDFファイルが選択されていません。")
return
print(f"\n{len(pdf_files)}個のPDFファイルを処理します。")
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
text_result_file = f'results/aws_invoice_summary_{timestamp}.txt'
csv_result_file = f'results/aws_invoice_summary_{timestamp}.csv'
results = []
for pdf_file in pdf_files:
print(f"\n処理中: {os.path.basename(pdf_file)}")
result = process_pdf_invoice(pdf_file)
results.append(result)
# CSV出力
with open(csv_result_file, 'w', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
writer.writerow(['顧客名', '請求書番号', '請求日', '税抜き金額', 'ファイル名'])
for result in results:
if 'error' not in result:
writer.writerow([
result['customer_name'],
result['invoice_number'],
result['invoice_date'],
result['amount'],
result['filename']
])
# テキスト出力
with open(text_result_file, 'w', encoding='utf-8') as f:
f.write("AWS請求書解析結果\n")
f.write("-" * 50 + "\n")
for result in results:
if 'error' in result:
f.write(f"\nファイル: {os.path.basename(pdf_file)}: "
f"エラー - {result['error']}\n")
else:
output = (
f"\n請求書: {result['filename']}\n"
f"顧客名: {result['customer_name']}\n"
f"請求書番号: {result['invoice_number']}\n"
f"請求日: {result['invoice_date']}\n"
f"税抜き金額: ¥{result['amount']:,}\n"
)
print(output)
f.write(output)
print(f"\n処理が完了しました。")
print(f"テキスト形式の結果: {os.path.abspath(text_result_file)}")
print(f"CSV形式の結果: {os.path.abspath(csv_result_file)}")
if __name__ == "__main__":
main()
print("\nEnterキーを押して終了してください...")
input()
フォルダ構成
C:\Users[ユーザー名]\Desktop\aws_invoice\ # メインフォルダ
│
├── aws_pdf_parser.py # メインスクリプト
│
├── input/ # 入力PDFファイル用フォルダ(オプション)
│ ├── 【顧客A】_Invoice_JPIN24_xxxx.pdf
│ ├── 【顧客B】_Invoice_JPIN24_yyyy.pdf
│ └── 【顧客C】_Invoice_JPIN24_zzzz.pdf
│
├── results/ # 出力ファイル用フォルダ(自動作成)
│ ├── aws_invoice_summary_20240423_121530.csv # CSV形式の結果
│ └── aws_invoice_summary_20240423_121530.txt # テキスト形式の結果
│
└── requirements.txt # 必要なPythonライブラリの一覧
フォルダとファイルの説明
- メインフォルダ (
aws_invoice
)- デスクトップ上に作成
- スクリプトの実行環境の基点
- メインスクリプト (
aws_pdf_parser.py
)- PDF解析と結果出力を行うPythonスクリプト
- フォルダのルートに配置
- 入力フォルダ (
input/
)- AWS請求書のPDFファイルを配置
- フォルダの使用は任意(GUIで別の場所も選択可能)
- 出力フォルダ (
results/
)- スクリプト実行時に自動作成
- CSV形式とテキスト形式の結果ファイルが保存
- ファイル名には実行時のタイムスタンプが付与
スクリプトの解説
主な機能
- PDFファイルからのテキスト抽出
- 請求情報の取得
- 顧客名(ファイル名から抽出)
- 請求書番号
- 請求日
- 税抜き金額
- CSV形式での出力
コードの重要部分の解説
PDFからのテキスト抽出
def process_pdf_invoice(pdf_path):
with pdfplumber.open(pdf_path) as pdf:
text = ''
for page in pdf.pages:
text += page.extract_text()
金額の抽出
def extract_jpy_amount(text):
pattern = r"Net Charges \(After Credits/Discounts, excl\. Tax\).*?JPY\s+([0-9,]+)"
match = re.search(pattern, text)
return int(match.group(1).replace(',', '')) if match else None
顧客名の抽出
def extract_customer_name(filename):
match = re.search(r'【(.+?)】', filename)
return match.group(1) if match else "Unknown"
使用方法
- スクリプトの実行
aws_pdf_parser.py
- 処理方法の選択
- 単一のPDFファイル処理
- フォルダ内の全PDFファイル処理
- 出力ファイル
- テキスト形式(詳細な情報)
- CSV形式(一覧表示)
カスタマイズのポイント
抽出項目の追加
- 為替レート
- サービス別の利用額
- アカウントID
出力形式の変更
- Excel形式への出力
- 日付形式のカスタマイズ
- 金額のフォーマット調整
自動化の設定
- Windowsタスクスケジューラーでの定期実行
- 特定フォルダの監視による自動処理
注意点
- 社内のセキュリティポリシーに従ってご利用ください
- PDFの形式が変更された場合、抽出パターンの調整が必要になる可能性があります
- 処理前にバックアップを取ることをお勧めします
コメント