PR

PythonでExcelをPDFに変換する方法|openpyxlとpywin32で請求書を自動作成【第1回】

Python

Python業務自動化 Invoice Maker 第1回

スポンサーリンク

はじめに:PythonでExcelから請求書を作りPDFに変換する

こんにちは、VBA・Python業務自動化ラボ(py-vbalab.com)のニンジンです🥕

この記事では、openpyxlpywin32(win32com) を使って、Excelの「受注管理表」からデータを読み取り、「請求書の雛形」に書き込んでPDFに変換するPythonスクリプトの作り方を、初心者向けに解説します。全3回シリーズの第1回で、まずは1枚の請求書を自動作成してPDF化する基本ロジックを作ります。

毎月末、「受注一覧のExcelから会社名や金額をコピーして、請求書の雛形に貼り付けて、PDFで保存する」——数件ならまだしも、数十件・数百件になると完全に苦行です。コピペミスによる作り直しなどのヒューマンエラーも増えます。VBAでも自動化できますが、ここではより拡張性の高いPythonで進めます。

この記事で分かること

  • openpyxl と pywin32(win32com)のインストール方法と、それぞれの役割
  • Excelのセルの値を読み取り、別のExcel(雛形)に書き込むPythonコード
  • openpyxlだけではできない「PDFへの変換」を、win32comで実現する手順
  • data_only=True で数式ではなく「計算結果の数値」を読み込む理由
  • 一時ファイル(temp.xlsx)を経由して、雛形のレイアウトを崩さずPDF化する仕組み
全3回で完成させる請求書自動作成ツールのGUI画面

▲ 全3回で目指す完成形(第3回でこのGUIまで作ります)

「Pythonの環境構築が面倒」「コードを書かずに今すぐ業務で使える完成品が欲しい」という方向けに、本シリーズで作るツールの完成版(設定不要のフルパッケージ)【Invoice Maker (NINJIN EDITION)】をnoteで頒布しています。

👉 noteでチェックする

スポンサーリンク

PythonでExcelをPDFに変換するための事前準備

準備1:openpyxl と pywin32 のインストール

Excelの読み書きとPDF化のために、2つのライブラリを使います。コマンドプロンプト(またはターミナル)で以下を実行します。

pip install openpyxl
pip install pywin32
  • openpyxl:Excelファイル(.xlsx)のデータを読み書きする定番ライブラリ
  • pywin32(win32com):PythonからExcel本体を裏側で直接操作するためのライブラリ。PDF化はこれが担当します
コマンドプロンプトでpip install openpyxlを実行した画面

▲ pip install openpyxl / pywin32 の実行

2つとも「Successfully installed」と表示されればOKです。うまくいかない場合は python -m pip install ... を試してください。

準備2:サンプルExcelファイル(受注管理表・請求書雛形)のダウンロード

お手持ちの管理表と書類フォーマットを使うか、下記のサンプルをダウンロードしてください。

⬇ 受注管理表_Sample.xlsx ⬇ 請求書_Sample.xlsx


スポンサーリンク

1枚の請求書を自動作成する完成コード(openpyxl+win32comでExcel→PDF)

今回作成する「1枚の請求書を自動作成する」Pythonスクリプトの全体です。受注管理表の4行目のデータを読み取り、請求書の雛形の所定のセルに書き込んでPDF化します。テストコードとExcel2ファイルを同じフォルダに置いて実行してください。

⬇ テストコード一式をダウンロード(Invoice_Maker_test01.zip)

VS Codeでテストコードと2つのExcelファイルを同じフォルダに置いた状態

▲ コードとExcelファイルを同一フォルダに配置

VS Codeでフォルダを開き、invoice_maker_test01.py・受注管理表・請求書雛形を同じ階層に置きます。こうするとコード内のパス指定がファイル名だけで済みます。

# invoice_maker_test01.py
# 受注管理表のExcelファイルからデータを読み込み、請求書の雛形となるExcelファイルに書き込んでPDF化するサンプルコード
# 基本的なコードで、1行目のデータを処理するだけの例です

import openpyxl #Excelファイルを操作するためのライブラリopenpyxlをインポート
import win32com.client #WindowsのCOMオブジェクトを操作するためのライブラリwin32com.clientをインポート
import os   #ファイルやパスを操作するための標準ライブラリosをインポート

# 1. 設定
KANRI_PATH = "受注管理表_Sample.xlsx"   #変数KANRI_PATHに受注管理表のExcelファイルのパスを指定
HINAGATA_PATH = "請求書_Sample.xlsx"    #変数HINAGATA_PATHに請求書の雛形となるExcelファイルのパスを指定
OUTPUT_PATH = os.path.abspath("請求書_出力.pdf")    #変数OUTPUT_PATHに出力するPDFファイルのパスを指定。abspathで絶対パスを取得

# 2. データの読み込み openpyxlを使用してExcelファイルを読み込み
wb_kanri = openpyxl.load_workbook(KANRI_PATH, data_only=True)   #data_only=Trueで数式の結果を値で取得
ws_kanri = wb_kanri["Sheet1"]  # シート名を指定してシートを取得
company_name = ws_kanri["C4"].value  # 会社名 KANRI_PATHのC列4行目を取得
amount = ws_kanri["H4"].value        # 金額 KANRI_PATHのH列4行目を取得
count = ws_kanri["G4"].value        # 数量  KANRI_PATHのG列4行目を取得
s_name = ws_kanri["F4"].value       # 商品名    KANRI_PATHのF列4行目を取得

# 3. 雛形へ書き込み opnepyxlを使用して請求書の雛形となるExcelファイルにデータを書き込み
wb_hina = openpyxl.load_workbook(HINAGATA_PATH) #雛形のExcelファイルを読み込み
ws_hina = wb_hina["Sheet1"]  # シート名を指定してシートを取得
ws_hina["A5"] = company_name    #HINAGATA_PATHのA列5行目に会社名を書き込み
ws_hina["B18"] = s_name     #HINAGATA_PATHのB列18行目に商品名を書き込み
ws_hina["L18"] = amount     #HINAGATA_PATHのL列18行目に金額を書き込み
ws_hina["J18"] = count      #HINAGATA_PATHのJ列18行目に数量を書き込み

# 4.雛形への書き込みが完了したら、一時的なExcelファイルとして保存する必要があるため、以下のコードで保存します。            
temp_excel = os.path.abspath("temp.xlsx")   #abspathで絶対パス(temp.xlsxという名前で)を取得
wb_hina.save(temp_excel)    #保存してからPDF化する必要があるため、一時的なExcelファイルを保存

# 5. PDF化 (pywin32を使用)
excel = win32com.client.Dispatch("Excel.Application")   #DispatchでExcelアプリケーションを起動
excel.Visible = False   #Excelのウィンドウを表示しないように設定
try:    #エラー発生時もExcelを確実に終了させるためにtryブロックを使用
    doc = excel.Workbooks.Open(temp_excel)  #Openで先ほど保存した一時的なExcelファイル(temp.xlsx)を開く
    doc.RefreshAll()  #Excelのデータを更新(数式がある場合に必要)
    doc.ExportAsFixedFormat(0, OUTPUT_PATH) #ExportAsFixedFormatでPDF形式で保存。第1引数は0でPDF、第2引数は保存先のパス
    doc.Close(False)    #Closeでtemp.xlsxを閉じる。引数は変更を保存するかどうか(Falseで保存しない)
except Exception as e:
    print(f"エラーが発生しました: {e}")
finally:    #必ずExcelを終了させるためのfinallyブロック
    excel.Quit()    #QuitでExcelアプリケーションを終了

if os.path.exists(temp_excel):  #念のため、一時的なExcelファイルが存在するかチェックしてから削除
    os.remove(temp_excel)   #一時的なExcelファイルを削除

print(f"作成完了: {OUTPUT_PATH}")   #ターミナルに作成完了のメッセージを表示

テストコードの実行結果と確認方法

  • コードを実行し、VS Codeのターミナルに 作成完了: ...請求書_出力.pdf と表示されれば成功です
  • Pythonコードと同じフォルダにPDFが生成されています
実行後にターミナルへ作成完了メッセージが表示され、フォルダにPDFが生成された画面

▲ ターミナルに「作成完了」、フォルダにPDFが出る

「作成完了: …pdf」が出て、フォルダに請求書のPDFができていれば成功です。エラーが出た場合は次のセクションの2つの罠を確認してください。


スポンサーリンク

openpyxl・pywin32初心者がハマりやすい2つの罠と対策

一見シンプルなコードですが、実務で使ううえで知っておくべき「工夫」が2つ隠れています。

① data_only=True で数式ではなく「計算結果の数値」を読み込む

Excelを読み込むとき、ただ load_workbook を使うと、金額などの計算式が入ったセルは "=SUM(H2:H3)" のような文字列の数式として取得されてしまいます。これを別のExcelに転記すると値が合いません。

openpyxl.load_workbook(KANRI_PATH, data_only=True) と指定すると、Excelが計算したあとの結果の値(数値)だけをクリーンに取り出せます。データ自動化の前処理では必須のテクニックです(対象のExcelが一度も保存・再計算されていないと None が返る点には注意)。

② 一時ファイル(temp.xlsx)に一度保存する理由:雛形のレイアウトを崩さない

openpyxlは高速にExcelを編集できますが、「PDFとして書き出す」機能は持っていません。PDF化は、パソコンにインストールされた本物のExcelに任せる必要があります(これが win32com の役割です)。

そこでこのコードでは、

  • openpyxlでデータを書き込んだ後、temp.xlsx という仮の名前で保存する
  • win32comでExcelアプリを起動し、その temp.xlsx を開いてPDFとして書き出す
  • 用済みの temp.xlsxos.remove で削除する

という手順を踏んでいます。これにより、元の雛形のレイアウト(罫線・書式)を一切崩さずにPDFを生成できます。


スポンサーリンク

まとめ:1枚の自動化ができれば大量処理まであと一歩

数十行のコードを実行するだけで、指定フォルダに請求書のPDFが生成されました。手作業のコピペから解放された瞬間です。

ただ、勘のいい方はこう思うはずです。「コードで C4H4 を直接指定しているけれど、100社分あったらどうするの?」——その通りで、今のままでは1枚しか作れません。次回は for文(ループ処理) を組み込み、フォルダ内に大量の請求書を一気に出力するスクリプトへ発展させます。途中でエラーが起きても止まらない書き方も解説します。

PR

「次回の解説まで待てない」「自分でコードを組む時間がない」という方は、noteで完成版のGUIアプリ【Invoice Maker (NINJIN EDITION)】を頒布中です。Python環境がないパソコンでも、ダウンロード後すぐに起動して使えます。

👉 noteで確認する

スポンサーリンク

よくある質問(openpyxl・pywin32でのExcel→PDF)

QExportAsFixedFormat でエラーが出る/PDFが作られません

Awin32com(pywin32)は、パソコンにインストールされた「本物のExcel」を操作してPDF化します。そのため、Excelが入っていない環境では動きません。pip install pywin32 が済んでいるか、import win32com.client が通るかも確認してください。

Qdata_only=True にしたのにセルの値が None になります

Adata_only=True は「Excelが最後に計算して保存した結果」を返します。openpyxlで作った直後のファイルや、数式が再計算されていないファイルでは None になることがあります。対象のExcelを一度手動で開いて上書き保存すると、計算結果が保存されて値が取れるようになります。

QModuleNotFoundError: No module named ‘openpyxl’(または win32com)が出ます

Aライブラリが未インストールです。pip install openpyxl と pip install pywin32 を実行します。パソコンに複数のPythonが入っている場合は、python -m pip install … の形で、実行に使うPythonへ確実にインストールしてください。

Q出力したPDFで、請求書の雛形のレイアウト(罫線・書式)が崩れます

Aopenpyxlで雛形に直接書き込んでPDF化しようとすると起きがちです。この記事の手順(openpyxlで値を書き込む → temp.xlsxに保存 → win32comでそのファイルを開いてPDF化 → temp.xlsxを削除)にすると、元の雛形ファイル自体は触らないため、レイアウトを保ったままPDFになります。

Q出力されるPDFの保存先(フォルダ)を変えたいです

Aコードの OUTPUT_PATH を書き換えます。os.path.abspath(“請求書_出力.pdf”) の部分を、r”C:\\Users\\…\\請求書.pdf” のようにフルパスで指定すれば、任意の場所に保存できます。


ニンジン🥕アイコン

Follow me on X

本ブログの中の人「ニンジン🥕」はXやってます。新着記事はいち早くポストでお知らせしているので、見逃したくない方は @ninjin_py_vba をフォローしてみてください🥕

@ninjin_py_vba をフォロー

この記事が役に立ったら、シェアしてもらえると嬉しいです🥕

Xでポスト はてブ LINE Pocket

PROJECT LOG — SERIES INDEX
スポンサーリンク

シリーズ記事一覧

電子工作・自動化ツールの製作記録をシリーズごとにまとめています。気になるテーマからお読みください。

超音波距離センサーHC-SR04をRaspberry Pi Picoで使う|仕組み・配線・精度検証
.uds1-block { position: relative; overflow: hidden; border-radius: 12px; border: 1px solid #f0cba8; background: linear-g…
今週の注目ガジェット〜09/07週〜|電子工作・自作向け新製品まとめ(TickrCast/Radxa Linkr ほか)
ニンジンのガジェット通信 09/07週。ESP32-P4の自作気象モニター、極小IP-KVM「Radxa Linkr」、ESP32のDINレール型PLC、LTE開発キットなど、電子工作で使えそうな新製品5つを解説。
サーボモータの角度をタクトスイッチで可変|OLED(SSD1306)に現在角度をリアルタイム表示
Raspberry Pi Pico 2W×MG996RにタクトスイッチとOLED(SSD1306)を追加。ボタンで角度を可変しながら現在角度をリアルタイム表示するMicroPython実装を、framebufの文字拡大やサーボの遊び対策まで実機ベースで解説します。
MG996RサーボモーターをRaspberry Pi Pico 2Wで動かす:PWM制御とキャリブレーション実践
MG996RサーボモーターをRaspberry Pi Pico 2Wで動かす方法を解説。公称180度のはずが実測198度だった個体差の原因究明から、ホーンのズレ補正、タクトスイッチでの角度制御まで実機検証の様子を紹介します。
Tapo P110Mの消費電力をExcelレポート化する【年次集計・電気代試算・セキュリティ判断編】
FastAPI+openpyxlでTapo P110Mの消費電力をExcelレポート化。15秒間隔の生ログを日次集計する設計や、31円/kWhでの電気代試算、外部公開を見送った理由まで解説します。

コメント