この記事で決められること
この記事を読むと、手元にあるVBAマクロを1本ずつ見て、そのまま残すか、Pythonに渡すか、両方を併用するかをその場で判断できるようになります。
判断に使うのは難しい理論ではなく、「入力は1ブックで足りるか」「出力はExcel以外に行くか」「決まった時刻に無人で動かす必要があるか」という3つの質問で済みます。マクロの数が増えてきて、どれを直すべきか、どれを書き換えるべきかが曖昧になっている担当者ほど、1本ごとに機械的に仕分ける手順を持つ方が迷いが減ります。全部をVBAのまま、あるいは全部をPythonに書き直す、という両極端のどちらも選ばずに済みます。
判断基準:3つの質問で仕分ける
結論として、3つの質問にYESで答えた数が0〜1ならVBA継続、2ならPython移行の検討、3なら併用構成に進むのが妥当です。
この3問を選んだ理由は、VBAが得意な範囲とPythonが得意な範囲の境界が、ファイルの数・出力先・実行方法の3点にほぼ集約されるためです。1つのブックの中だけで完結し、人がExcelを開いてボタンを押して使う運用であれば、VBAのままで問題は起きません。逆にこの3つのどれかが変わった瞬間に、VBA単体では無理が出てきます。
| 質問 | YESの例 | NOの例 |
|---|---|---|
| 入力は1ブックで足りるか | 他部署のファイルを毎回開いてコピーしている | 自分のブック内の表だけで完結している |
| 出力はExcel以外に行くか | LINE通知やデータベースへの登録が必要 | 集計結果をExcelのシートに表示するだけ |
| 決まった時刻に無人で動かす必要があるか | 毎朝9時に誰も触らず処理を終わらせたい | 月末に自分が開いてボタンを押せば済む |
| YESの数 | 判定 |
|---|---|
| 0〜1 | VBAのまま継続 |
| 2 | Pythonへの移行を検討 |
| 3 | VBAとPythonの併用構成 |
この表は、マクロ1本ごとに当てはめて使うものです。1つのブックにマクロが5本あるなら、5回この表を埋めることになります。全部まとめて「このブックはPythonにする」と判断すると、本当は残してよかった単純な集計マクロまで巻き込んで書き換えることになり、作業量が無駄に増えます。
VBAに残してよい処理と最小の作り方
3問すべてNOに近いマクロは、作り直す必要はなく、シート構成とSubを1本に整えるだけで十分に安定します。
シート構成は「入力」「集計」「出力」の3枚に固定します。入力シートには生データだけを置き、集計シートには計算結果だけを書き、出力シートは印刷や配布用の体裁だけを整える役割に限定します。この3枚を混在させると、どこに手を入れればよいかが分からなくなり、他の人が引き継げなくなります。
Sub 集計実行()
Dim wsIn As Worksheet, wsOut As Worksheet
Dim i As Long, lastRow As Long
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Set wsIn = ThisWorkbook.Worksheets("入力")
Set wsOut = ThisWorkbook.Worksheets("集計")
lastRow = wsIn.Cells(wsIn.Rows.Count, "A").End(xlUp).Row
Dim dept As String, amt As Double
For i = 2 To lastRow
dept = wsIn.Cells(i, "A").Value
amt = wsIn.Cells(i, "C").Value
If dict.Exists(dept) Then
dict(dept) = dict(dept) + amt
Else
dict.Add dept, amt
End If
Next i
wsOut.Cells.ClearContents
wsOut.Cells(1, 1).Value = "部署"
wsOut.Cells(1, 2).Value = "金額"
Dim r As Long, total As Double
r = 2
Dim key As Variant
For Each key In dict.Keys
wsOut.Cells(r, 1).Value = key
wsOut.Cells(r, 2).Value = dict(key)
total = total + dict(key)
r = r + 1
Next key
wsOut.Cells(r, 1).Value = "合計"
wsOut.Cells(r, 2).Value = total
Dim checkTotal As Double
checkTotal = Application.WorksheetFunction.Sum(wsIn.Range("C2:C" & lastRow))
If Abs(checkTotal - total) > 0.01 Then
MsgBox "検算エラー: 入力合計と集計合計が一致しません"
End If
End Sub
最後にSum関数で入力シートの合計を取り直し、集計結果の合計と比較する検算を必ず入れておきます。ループの途中で1件だけ条件から漏れていても、この検算がないと気づかずに提出してしまいます。
実際に作ると詰まりやすい点が4つあります。1つ目は保存形式です。マクロを含むブックは拡張子をxlsmにしないと保存できず、気づかずxlsxのまま閉じるとマクロごと消えます。保存時に出る警告は読み飛ばさずに「いいえ」を選び、ファイルの種類を手動でxlsmに変え直します。2つ目はセキュリティ警告です。社内PCのセキュリティ設定によっては開くたびに「マクロを有効にする」を押す必要があり、共有フォルダに置いたファイルは信頼済み場所に追加しないと毎回警告が出ます。3つ目は相対参照の崩れです。マクロの記録機能で作ったコードは、記録時の列位置や選択範囲に依存していることが多く、入力シートに1列追加しただけで集計がずれます。Cells(i, "A")のように列を明示して書くのはこのためです。4つ目は他人のPCで動かない問題です。CreateObject("Scripting.Dictionary")のように遅延バインディングで書けば、参照設定(ツール→参照設定)を事前にチェックしてもらう必要がなく、配布先のPCで参照が外れてエラーになる事故を避けられます。
VBAとPythonの機能的な違いについては、CODENESTの比較が参考になります。集計処理自体のサンプルはfastclassinfoにも月末処理向けの実装例があります。
併用し始めてから起きる事故と対処
VBAとPythonを同じファイルで併用し始めると、どちらか単体のときには起きなかった事故が発生するため、仕組みで防ぐ対処をあらかじめ決めておく必要があります。
- Pythonがopenpyxlでブックを開いて書き込もうとした瞬間に、担当者がExcelでそのファイルを開いたままになっていると、ファイルロックにより書き込みが失敗します。対処は、Python側の処理時間を固定し、その時間帯はExcelを閉じておくルールを決めるか、PythonからExcelファイルを直接触らず、一度CSVやデータベース経由にしてVBA側が最後にExcelへ反映する構成に変えることです。
- 手動でVBAのボタンを押す運用と、Pythonをタスクスケジューラで定時実行する運用が同じファイルに同居すると、同じ時間帯に人が手動実行し、裏でスケジュール実行も走って二重に処理してしまうことがあります。対処は、処理の開始時にロックファイルを作り、既にロックファイルが存在する場合は処理を中断してログに残す、という単純な仕組みを両方の起動経路に入れることです。
- シート名や列位置をPython側とVBA側で別々に決め打ちしていると、どちらか一方だけシート名を変更した時に他方が壊れ、集計結果が崩れます。対処は、シート名や列番号を定数やコンフィグファイルにまとめて、VBA側とPython側の両方から同じ定義を参照する、もしくは少なくとも変更時に両方を同時に直すチェックリストを作っておくことです。
これらはいずれも、VBA単体で動いていた時には存在しなかった種類の不具合です。Pythonに処理を渡すと決めた時点で、この3つをどう防ぐかをセットで決めておくと、移行後に原因不明のエラーに時間を取られずに済みます。
自社で実際にPythonへ渡している処理
私が実際にPythonへ渡しているのは、入力が複数ファイルにまたがる処理と、決まった時刻に無人で動かす処理の2種類です。
1つは、請求書や領収書、名簿のPDFや写真から項目と明細を取り出し、CSVやTSVに変換する公開ツールです。ファイルは保存しない仕様で動かしており、AI転記ツールとして公開しています。手入力でExcelに転記していた部分をこのツールの出力に置き換えれば、入力収集の工程だけをPythonに渡し、その後の集計は既存のVBAのシートにそのまま読み込ませる構成にできます。
もう1つは、Webの収集、AIによる分類と下書き作成、LINE webhook、Cloudflare Worker、Supabaseを組み合わせた定時処理です。実行はローカルPCのWindowsタスクスケジューラとPythonで、データの保存先はSupabaseです。公開や送信は人が最終確認する構成にしており、無人化しているのは収集と下書き作成までで、送信の判断は残しています。詳しい構成は受託の実績ページに記載しています。
この他に、手書きの点検記録を生成AIで読み取って業務ツールへ登録する作業を、2026年7月から継続して請けています。週10時間ほどの規模で、読み取りの後に必ず人の確認を挟む構成にしています。無人化できる部分(読み取りと項目への変換)と、人が見るべき部分(内容の確認と登録の実行)を分けているという点は、今回の判断基準の「誰が直すか」「決まった時刻に無人で動かすか」の考え方と同じです。
移行の順番:どこから手をつけるか
既存のVBAを一度に捨てずに、入力収集→出力先の切り替え→無人の定時実行、という順番で手をつけるのが詰まりにくい進め方です。
- まず、複数ファイルやPDF・写真から手入力している部分だけをPythonに置き換えます。出力はCSVやExcelファイルのままにしておき、既存のVBAの集計処理はそのまま使います。ここでは併用時の事故対策(ロックファイル、シート名の共有定義)は不要で、ファイルが受け渡せれば十分です。
- 次に、集計結果の出力先をExcel以外(データベースやLINE通知)に広げます。この段階で初めて、VBAとPythonが同じファイルを同時に触る場面が出てくるため、前章で挙げたファイルロックとシート名のズレの対策を入れます。
- 最後に、決まった時刻に無人で動かす定時実行に進みます。手動実行とスケジュール実行の二重起動対策(ロックファイルによる中断)は、この段階で必ず入れてから無人化に切り替えます。通知先を追加するのも、無人実行が安定して1〜2週間止まらずに動いたことを確認してからにします。
この順番を逆にする、つまり最初から無人の定時実行を作ろうとすると、入力収集でつまずいた時に原因がPython側なのかVBA側なのか切り分けられず、復旧に時間がかかります。入力収集だけを先に独立させて動かしておくと、問題が起きた時の切り分けが早くなります。
次にやること
手元のVBAマクロの一覧を出し、1本ずつ「入力は1ブックで足りるか」「出力はExcel以外に行くか」「決まった時刻に無人で動かす必要があるか」の3問に当てはめてみることが、今日できる作業です。
YESが2つ以上ついたマクロから優先して、入力収集の置き換えに着手します。openpyxlでExcelファイルを直接操作する具体的な書き方はopenpyxlの記事で扱っており、タスクスケジューラでPythonを定時実行する手順はNotion連携の記事の定時更新の節にまとめています。併せて確認しながら進めてください。

openpyxlでExcel自動化、学んだ後に詰まる運用を実例で埋める
Pythonのスクレイピング自動化が数日で止まる原因と動かし続ける作り方
CSVの文字化けと列ずれが止まる場所をPythonのコードで具体的に潰す手順