Excel・CSVの面倒な集計をAIエージェントとPythonで自動化【2026】コピペ作業を1コマンドに
毎月、支店から届く売上Excelを開いて、コピーして、貼り付けて、合計して、グラフを作る——。この「毎月30分〜数時間のコピペ作業」は、AIエージェントにPythonスクリプトを書かせると、次の月からはコマンド1つ(またはダブルクリック1回)で終わるようになります。この記事では、Claude Code(ターミナルで動くAnthropicのコーディングエージェント)との実際のやりとりを時系列で再現しながら、途中で出るエラーとその直し方、原本データを壊さないための安全策まで、初めての方でも真似できる形で解説します。
- 「data/ のExcelを全部まとめて、支店×月の集計表とグラフを output/ に出して」と頼むだけで、AIエージェントがpandasを使った集計スクリプトを書き、実行まで進めてくれる
- 現実のExcelには列名の揺れ・全角数字・空行・合計行がつきもの。エラーが出たら「原因を説明してから直して」と頼むのがコツ。エラーが出ない“静かな間違い”は検算で見つける
- 安全策は3つ:原本は読むだけ(出力は output/)・Gitで変更履歴を残す・本番の前にダミーデータで作る
- 完成したら.bat/.commandにしてダブルクリックで動く形に。Excelの中で完結するならPower Query/VBA、ファイル横断・定期処理ならPython、と使い分ける
完成イメージ:何ができるようになるか
今回の題材は、どの会社にもありそうな次の作業です。
- 渋谷店・新宿店・横浜店から、毎月売上Excelが届く(1ファイルに「7月」「8月」など月ごとのシート)
- 支店によって列名が微妙に違う(「売上」と「売上金額」)、全角数字で入力されたセルや空行・合計行が混ざっている
- これを1つにまとめて、支店×月の売上表と商品別の集計、棒グラフを作り、会議資料に貼る
完成後のフォルダは次のようになります。data/ にファイルを置いてコマンドを1回実行すると、output/ に結果がそろいます。
sales-report/
├── data/ ← 支店から届いた原本(読むだけ・絶対に書き換えない)
│ ├── 渋谷店_売上.xlsx
│ ├── 新宿店_売上.xlsx
│ └── 横浜店_売上.xlsx
├── output/ ← スクリプトが作る結果(何度でも作り直せる)
│ ├── 月次売上集計.xlsx (シート:支店×月/商品別/統合データ)
│ ├── 月次売上グラフ.png
│ └── 除外した行.csv (読めなかった行の記録)
├── merge_sales.py ← AIが書いた集計スクリプト
├── check_totals.py ← 検算スクリプト
├── 集計する.bat / 集計する.command ← ダブルクリック用
└── CLAUDE.md ← AIへの「このフォルダのルール」出力される「支店×月」シートは、たとえば次のような表です(編集部がダミーデータで実行した結果)。
| 支店 | 2026-07 | 2026-08 | 合計 |
|---|---|---|---|
| 新宿店 | 77,722 | 113,880 | 191,602 |
| 横浜店 | 99,021 | 95,381 | 194,402 |
| 渋谷店 | 115,136 | 98,052 | 213,188 |
| 合計 | 291,879 | 307,313 | 599,192 |


準備:Python・Claude Code・作業フォルダ
1. Pythonを入れる
Pythonは、今回の集計を実際に実行する「計算係」です。python.org から最新版をインストールします。Windowsではインストーラーの「Add python.exe to PATH」にチェックを入れておくと後が楽です。インストールできたら、ターミナル(Windowsは「ターミナル」または「PowerShell」、Macは「ターミナル」)で確認します。
# Windows(python.orgのインストーラーで入れた場合は py コマンドが使える)
py --version
py -m pip install pandas openpyxl matplotlib
# Mac
python3 --version
python3 -m pip install pandas openpyxl matplotlibpandasは表データを扱うライブラリ(Excelで言えば「関数とピボットテーブルの詰め合わせ」)、openpyxlはpandasが.xlsxを読み書きするときに使う部品、matplotlibはグラフを描くライブラリです。実はこのインストールも、Claude Codeに「必要なライブラリを入れて」と頼めばやってくれます。
2. Claude Codeを入れる
Claude Codeは、ターミナルで動くAIエージェントです。フォルダの中のファイルを読み、コードを書き、コマンドを実行し、エラーを見て直すところまで自分で進めます。インストール方法は公式ドキュメント(Anthropic公式ドキュメント)に従ってください(執筆時点では npm install -g @anthropic-ai/claude-code などの方法が案内されています)。利用にはAnthropicの有料プランかAPIの利用契約が必要です。料金・プランは変わることがあるので公式で確認してください。
3. 作業フォルダを作り、Gitで記録を始める
本番の売上ファイルを直接使うのではなく、コピーを置いた作業用フォルダを作ります。最初はダミーデータでも構いません。
mkdir sales-report
cd sales-report
mkdir data output
# ここで data/ に支店のExcelを「コピー」して置く(原本は元の場所に残す)
git init # 変更履歴を記録する準備(やり直しできるようにする)
claude # Claude Code を起動起動したら、まず /init と入力すると、Claude Codeがフォルダを調べて CLAUDE.md(このフォルダで守るルールや手順を書いておくファイル。Claude Codeが毎回読み込みます)の雛形を作ってくれます。中身は安全策の章で整えます。Gitが初めての方はIT基礎シリーズ第7章「Git・GitHub・デプロイ入門」もどうぞ。
AIとの実際のやりとりを再現(依頼→エラー→修正→検算)
ここからは、編集部がダミーデータで実際に行った流れをもとに、Claude Codeとのやりとりを時系列で再現します。プロンプトはそのままコピーして使えます。
Step 1:やりたいことを「完成形」で伝える
最初の依頼では、入力(どこに何があるか)・出力(何をどこに出すか)・守ってほしいことの3点を伝えます。いきなり書かせず、まず計画を出させるのがポイントです(Claude Codeでは Shift+Tab で「Plan Mode」に切り替えると、コードを変更する前に計画を提示してくれます)。
data/ にある売上ファイル(.xlsx、各ファイルに月ごとのシートがある)を全部まとめて、
次のものを output/ に出すPythonスクリプト merge_sales.py を作ってください。
- 支店×月の売上合計表(行:支店、列:月、合計つき)
- 商品別・月別の売上合計
- 支店別の月次売上の棒グラフ(PNG)
- 支店名はファイル名の「_」より前(例:渋谷店_売上.xlsx → 渋谷店)
守ってほしいこと:
- data/ の中のファイルは絶対に書き換えない(読むだけ)
- pandas と openpyxl を使う
- まず data/ のファイルの中身(シート名・列名)を確認して報告し、
作り方の計画を見せてから書き始めてくださいClaude Codeは、まず短いPythonをその場で実行して各ファイルのシート名と先頭数行を調べ、次のような計画を返してきました(要約)。
data/ に3ファイル、各2シート(7月・8月)がありました。列は「日付・商品・売上」です。
計画:
1. glob で data/*.xlsx を列挙し、read_excel(sheet_name=None) で全シートを読む
2. ファイル名から支店列を追加して1つの表に連結
3. groupby / pivot_table で集計し、to_excel で output/ に書き出す
4. matplotlib で棒グラフを保存
この計画で進めてよいですか?Step 2:最初のスクリプトを実行 → エラー
「OK、進めて」と返すと、Claude Codeは最初の版を書いて実行しました。核になる部分は次のようなシンプルなものです。
import glob
import pandas as pd
frames = []
for path in glob.glob("data/*.xlsx"):
sheets = pd.read_excel(path, sheet_name=None) # 全シートを辞書で読む
for name, df in sheets.items():
df["支店"] = path.split("/")[-1].split("_")[0]
frames.append(df)
df = pd.concat(frames, ignore_index=True)
print(df.groupby("支店")["売上"].sum())実行結果は、エラーでした。
Traceback (most recent call last):
File "merge_sales.py", line 12, in <module>
print(df.groupby("支店")["売上"].sum())
...
TypeError: unsupported operand type(s) for +: 'int' and 'str'「整数(int)と文字列(str)は足し算できません」という意味です。Pythonのエラーは一番下の行から読むのが基本です。
Step 3:「原因を説明してから直して」と頼む
エラーが出たとき、「直して」だけでも直してはくれます。しかし原因を説明させると、あなた自身がデータの癖を理解でき、次に同じことが起きても判断できるようになります。
エラーの原因を、Excelしか使ったことがない人にも分かるように説明してから直してください。
同じ種類の問題がほかのファイルやシートにもないか、全ファイル・全シートを確認してください。
data/ の原本は変更しないこと。Claude Codeは全シートの列名と値の型を調べ、次のように説明しました(要約)。
原因は3つありました。
1. 新宿店の7月シートに「12,500」「8800円」のような全角数字・円付きの値があり、
Excelでは数値に見えても実際は「文字」として入っています。数値と文字は足せないのでエラーになりました。
2. 横浜店だけ列名が「売上金額」でした。このまま連結すると、横浜店の「売上」列が空になり、
エラーは出ないまま横浜店の合計が 0 円になります(こちらのほうが危険です)。
3. 新宿店の8月シートに空行と、最終行に「合計」という行がありました。
合計行を足すと二重計上になります。
対応:列名の対応表で「売上金額」→「売上」にそろえ、全角→半角変換(NFKC)と「,」「円」の除去をしてから
数値に変換します。日付として読めない行(合計行など)は集計から外し、output/除外した行.csv に記録します。

Step 4:修正版を実行 → 集計表ができる
修正版(全文は次の章)を実行すると、次のように表示されました。
$ python merge_sales.py
[除外] 日付か売上が読めない行: 1件(output/除外した行.csv を確認)
月 2026-07 2026-08 合計
支店
新宿店 77722.0 113880.0 191602.0
横浜店 99021.0 95381.0 194402.0
渋谷店 115136.0 98052.0 213188.0
合計 291879.0 307313.0 599192.0
保存しました: output/月次売上集計.xlsx「除外した行」が1件あるのは、新宿店8月シートの「合計」行です。output/除外した行.csv を開くと、どのファイルのどのシートから除外されたかが分かります。黙って捨てずに記録を残すのは、あとで「数字が合わない」と言われたときに説明できるようにするためです。
Step 5:検算させる(ここが一番大事)
集計が正しいか確かめたいです。元ファイル・シートごとの行数と売上合計を出し、
集計表の総合計と一致するかを確認する check_totals.py を作って実行してください。
新宿店7月の「12,500」の行が 12500 として入っているかも見せてください。"""検算:元ファイル・シートごとの合計と、集計表の総合計が一致するかを確かめる"""
import pandas as pd
df = pd.read_excel("output/月次売上集計.xlsx", sheet_name="統合データ")
by_source = df.groupby("元ファイル")["売上"].agg(["count", "sum"])
print(by_source)
print("統合データの合計:", int(df["売上"].sum()))
monthly = pd.read_excel("output/月次売上集計.xlsx", sheet_name="支店×月", index_col=0)
print("集計表の総合計 :", int(monthly.loc["合計", "合計"])) count sum
元ファイル
新宿店_売上.xlsx/7月 8 77722
新宿店_売上.xlsx/8月 8 113880
横浜店_売上.xlsx/7月 8 99021
横浜店_売上.xlsx/8月 8 95381
渋谷店_売上.xlsx/7月 8 115136
渋谷店_売上.xlsx/8月 8 98052
統合データの合計: 599192
集計表の総合計 : 599192最後に、1つのシートだけはExcelで開いて自分の目で合計を確認します(ExcelのSUMと一致すればOK)。AIが書いた検算コードをAIの集計と突き合わせるだけでは、同じ思い込みを共有している可能性があるからです。人間の目による「1か所の手検算」は、少ない手間で大きな安心が得られます。
Step 6:グラフの文字化け(□□□)を直す
グラフ画像を開くと、日本語のタイトルや支店名が「□□□」(通称「豆腐」)になっていることがあります。実行時に Glyph ... missing from font(s) DejaVu Sans という警告が出ていたら、これが原因です。matplotlibの標準フォントに日本語が入っていないためです。
グラフの日本語が□になります。WindowsでもMacでも日本語が表示されるように、
OSに入っている日本語フォントを使う設定にしてください。Claude Codeは、plt.rcParams["font.family"] に「Yu Gothic(Windows)」「Hiragino Sans(Mac)」「Noto Sans CJK JP(Linux等)」などの候補を並べる修正をしました。候補のうち、そのPCに入っているフォントが使われます。
Step 7:Gitで保存する
ここまでの変更をGitにコミットしてください。data/ と output/ はコミットに含めないよう
.gitignore に追加してください。コミットメッセージは日本語で、何を直したか分かるように。これで「スクリプトの変更履歴」だけがGitに残ります。次に何か直して壊れても、いつでもこの動く状態に戻れます。売上データ自体は個人情報や機密を含むことが多いので、Gitには入れず、元の保管場所で管理するのが基本です。
完成したスクリプトの解説
修正を重ねて完成した merge_sales.py の全文です。編集部でダミーデータ(3支店×2か月、全角数字・列名の揺れ・空行・合計行を含む)に対して実行し、上の結果が出ることを確認しています(Python 3.11、pandas 3.0、openpyxl 3.1、matplotlib 3.11 で確認)。
"""data/ の売上Excel(全ファイル・全シート)を統合し、月次集計表とグラフを output/ に出力する"""
from pathlib import Path
import unicodedata
import pandas as pd
import matplotlib
matplotlib.use("Agg") # 画面を開かずに画像だけ保存する
import matplotlib.pyplot as plt
DATA_DIR = Path("data")
OUT_DIR = Path("output")
# 列名の揺れを吸収する対応表(左の名前が来たら右に統一)
COLUMN_ALIASES = {
"売上金額": "売上", "売上高": "売上", "金額": "売上",
"年月日": "日付", "販売日": "日付",
"品名": "商品", "商品名": "商品",
}
REQUIRED = ["日付", "商品", "売上"]
def normalize_text(value) -> str:
"""全角英数字・全角記号を半角にそろえ、前後の空白を消す"""
return unicodedata.normalize("NFKC", str(value)).strip()
def to_number(value):
"""'12,500' や '8800円' のような値を数値にする。変換できなければ NaN"""
if pd.isna(value):
return float("nan")
text = normalize_text(value).replace(",", "").replace("円", "").replace("¥", "")
return pd.to_numeric(text, errors="coerce")
def load_all() -> pd.DataFrame:
frames = []
for path in sorted(DATA_DIR.glob("*.xlsx")):
if path.name.startswith("~$"): # Excelで開いている間にできる一時ファイルは除外
continue
branch = path.stem.split("_")[0] # 「渋谷店_売上.xlsx」→「渋谷店」
for sheet_name, df in pd.read_excel(path, sheet_name=None).items():
df = df.rename(columns=normalize_text).rename(columns=COLUMN_ALIASES)
missing = [c for c in REQUIRED if c not in df.columns]
if missing:
print(f"[スキップ] {path.name} / {sheet_name}: 列が足りません {missing}")
continue
df = df[REQUIRED].copy()
df["支店"] = branch
df["元ファイル"] = f"{path.name}/{sheet_name}"
frames.append(df)
if not frames:
raise SystemExit("data/ に読み込める .xlsx がありません")
return pd.concat(frames, ignore_index=True)
def clean(df: pd.DataFrame) -> pd.DataFrame:
df = df.dropna(how="all", subset=REQUIRED) # 完全な空行を除く
df["売上"] = df["売上"].map(to_number)
df["日付"] = pd.to_datetime(df["日付"], errors="coerce") # 「合計」行などは NaT になる
bad = df[df["日付"].isna() | df["売上"].isna()]
if len(bad):
print(f"[除外] 日付か売上が読めない行: {len(bad)}件(output/除外した行.csv を確認)")
OUT_DIR.mkdir(exist_ok=True)
bad.to_csv(OUT_DIR / "除外した行.csv", index=False, encoding="utf-8-sig")
df = df.drop(bad.index)
df["月"] = df["日付"].dt.strftime("%Y-%m")
return df
def main():
OUT_DIR.mkdir(exist_ok=True)
df = clean(load_all())
monthly = df.pivot_table(index="支店", columns="月", values="売上",
aggfunc="sum", margins=True, margins_name="合計")
by_item = df.groupby(["月", "商品"], as_index=False)["売上"].sum()
out_xlsx = OUT_DIR / "月次売上集計.xlsx"
with pd.ExcelWriter(out_xlsx, engine="openpyxl") as writer:
monthly.to_excel(writer, sheet_name="支店×月")
by_item.to_excel(writer, sheet_name="商品別", index=False)
df.to_excel(writer, sheet_name="統合データ", index=False)
# グラフ(日本語フォントはOSに合わせて候補から使われる)
plt.rcParams["font.family"] = ["Yu Gothic", "Meiryo", "Hiragino Sans",
"Noto Sans CJK JP", "IPAexGothic", "sans-serif"]
chart = monthly.drop(index="合計", columns="合計")
ax = chart.T.plot(kind="bar", figsize=(8, 4.5))
ax.set_title("支店別 月次売上")
ax.set_ylabel("売上(円)")
plt.tight_layout()
plt.savefig(OUT_DIR / "月次売上グラフ.png", dpi=150)
print(monthly)
print(f"保存しました: {out_xlsx}")
if __name__ == "__main__":
main()AIが書いたコードを全部理解する必要はありませんが、要所の意味を知っておくと、次に頼むときの指示が正確になります。
| コード | 何をしているか | Excelで言うと |
|---|---|---|
DATA_DIR.glob("*.xlsx") | data/ の中の .xlsx を全部探す(~$ で始まるExcelの一時ファイルは除外) | フォルダを開いてファイルを1つずつ開く作業 |
pd.read_excel(path, sheet_name=None) | sheet_name=None で全シートを「シート名→表」の辞書として読む | 全シートを順番に開く |
unicodedata.normalize("NFKC", ...) | 全角英数字・全角記号・全角スペースを半角にそろえる | ASC関数・TRIM関数 |
COLUMN_ALIASES と rename | 「売上金額」「売上高」などを「売上」に統一。新しい揺れが見つかったらここに1行足す | 列見出しを手で書き直す |
dropna(how="all", ...) | 全部空の行を除く | 空行の削除 |
pd.to_datetime(..., errors="coerce") | 日付に変換。「合計」のような日付でない値は NaT(欠損)にして後で除外 | DATEVALUE関数+エラー行の目視チェック |
pivot_table(..., margins=True) | 支店×月のクロス集計。margins で合計行・列もつける | ピボットテーブル |
groupby([...])["売上"].sum() | 月・商品ごとの合計 | SUMIFS関数 |
pd.ExcelWriter + to_excel | 1つのExcelファイルに複数シートで書き出す | 新しいブックにシートを作って貼り付け |
「なぜこう作るか」の判断ポイント
- 変換できない値はエラーで止めずに「除外+記録」:1行の入力ミスで全体が止まると毎月の運用がつらくなります。一方で黙って捨てると数字が合わなくなるので、
除外した行.csvに残す折衷案にしています。逆に「1行でもおかしければ止めたい」(経理の締めなど)なら、除外行があったらSystemExitで止める方針に変えるよう頼みましょう。 - 列名の揺れは「対応表」で吸収:AIに「列名を推測して」と任せるより、対応表を明示したほうが、なぜその列が売上として扱われたのかを後から説明できます。
- パスの扱いは pathlib で:最初の版の
path.split("/")は、区切り文字が\になるWindowsでは支店名を正しく取り出せません。完成版はpathlibのpath.stem(拡張子を除いたファイル名)を使い、OSに依存しないようにしています。「WindowsとMacの両方で動くように」と最初に伝えておくと、AIもこうした書き方を選びます。 - 統合データもシートとして出力:集計結果だけでなく、集計前の整えたデータも残すと、「この数字はどの行から来たのか」をExcelのフィルターで追えます。
pd.read_csv(path, encoding="cp932") のように文字コードを指定しないと、UnicodeDecodeError で読めません。逆にPythonからCSVを出力してExcelで開くなら、encoding="utf-8-sig" にすると文字化けしにくくなります(上のスクリプトの 除外した行.csv もこの指定です)。古い .xls 形式は、追加のライブラリ(xlrd)が必要になる点も覚えておきましょう。
原本を壊さないための安全策
AIエージェントは、ファイルの作成・変更・削除ができます。便利な反面、「原本を上書きしてしまった」が一番怖い事故です。次の3層で守ります。
CLAUDE.md は「このフォルダで働くときのお願いと手順書」です。Claude Codeは起動するたびにこれを読みます。
# 売上集計プロジェクト
## 目的
data/ に届く支店別の売上Excelを統合し、output/ に月次集計表とグラフを出す。
## 絶対に守ること
- data/ の原本は読むだけ。上書き・移動・削除をしない
- 出力はすべて output/ に書く
- 集計ロジックを変えたら python check_totals.py で検算し、結果を報告する
## 実行方法
- 集計: python merge_sales.py
- 検算: python check_totals.py
## データの癖(わかっていること)
- 列名が支店によって違う(「売上」「売上金額」など)→ COLUMN_ALIASES に追加して吸収する
- 全角数字や「円」付きの金額が混ざる
- 末尾に「合計」行があるシートがあるただしCLAUDE.mdは「お願い」にすぎません。確実に守らせたいことは、Claude Codeの権限設定(.claude/settings.json)で「鍵」をかけます。allow は確認なしで実行してよい操作、ask は毎回確認する操作、deny は禁止する操作です。
{
"permissions": {
"allow": [
"Bash(python merge_sales.py)",
"Bash(python check_totals.py)",
"Bash(git status)",
"Bash(git diff:*)"
],
"ask": [
"Bash(git commit:*)"
],
"deny": [
"Edit(./data/**)",
"Bash(rm:*)",
"Bash(mv:*)"
]
}
}この設定では、集計と検算のコマンドは確認なしで実行でき、コミットは毎回確認、data/ 内のファイル編集と rm・mv は禁止しています。設定の書き方は変わることがあるので、公式ドキュメントも確認してください。

つまずきポイントとAIへの頼み方
初めてのときに出会いやすいトラブルと、そのときの頼み方です。エラーメッセージは全文をそのまま貼り付けるのが一番の近道です。
| 症状 | よくある原因 | AIへの頼み方の例 |
|---|---|---|
ModuleNotFoundError: No module named 'openpyxl' | ライブラリが未インストール、またはPythonが複数入っていて別のほうに入った | 「このエラーが出ます。どのPythonで実行されているか確認して、同じPythonにライブラリを入れてください」 |
PermissionError(書き込み時) | output の集計ExcelをExcelで開いたまま実行した | 「出力ファイルが開いているときは、分かりやすいメッセージを出して終了するようにして」 |
| 数値が文字扱いになる/合計が合わない | 全角数字、「円」「,」付き、前後の空白、文字列として保存された数値 | 「売上列で数値に変換できない値を、ファイル名・シート名・行番号つきで一覧にして」 |
| 日付が 45870 のような数字になる | Excelの日付が「シリアル値」のまま読まれている | 「日付列にExcelのシリアル値が混ざっているようです。正しい日付に変換して」 |
| グラフの日本語が□になる | matplotlibの標準フォントに日本語がない | 「グラフの日本語が□になるので、OSの日本語フォントを使うようにして」 |
CSVで UnicodeDecodeError | Shift_JIS(cp932)のCSVをUTF-8として読んでいる | 「このCSVの文字コードを判定して、正しく読めるようにして」 |
| ある支店だけ数字が0/空になる | 列名の揺れ(エラーにならない) | 「全ファイル・全シートの列名を一覧表にして、揺れがないか確認して」 |
- 説明させてから直させる:「原因を説明してから直して」
- 範囲を広げて点検させる:「同じ問題がほかのファイルにもないか全部確認して」
- 確かめる手段を作らせる:「正しいことを確認するスクリプト(検算)も作って実行して」
会話が長くなってAIの返答がちぐはぐになってきたら、/clear で会話をリセットし、CLAUDE.md と現在のコードを前提に仕切り直すのも有効です。作業中に止めたいときは Esc キーで中断できます。
発展:ファイル名の一括変換・PDF請求書・ダブルクリック実行
発展1:ファイル名の一括変換(まず「表示だけ」→確認して実行)
「請求書 2026年8月 (株)ABC商事.pdf」のようなバラバラのファイル名を、「2026-08_株式会社ABC商事_請求書.pdf」に統一する例です。ファイル名の変更は取り消しにくいので、既定では変更予定を表示するだけ、--run を付けたときだけ実行する作りにしてもらいます。
scans/ のPDFのファイル名を「YYYY-MM_会社名_請求書.pdf」にそろえるスクリプトを作ってください。
全角数字や全角スペースが混ざっています。「(株)」は「株式会社」にしてください。
いきなり変更せず、まず変更前→変更後の一覧を表示するだけのモードで動かして、私に見せてください。
同じ名前のファイルがすでにある場合は上書きしないこと。"""scans/ のPDFのファイル名を「2026-08_株式会社ABC商事_請求書.pdf」形式にそろえる"""
import re
import sys
import unicodedata
from pathlib import Path
TARGET = Path("scans")
DRY_RUN = "--run" not in sys.argv # 既定は「表示だけ」。--run を付けたときだけ実際に変更
for path in sorted(TARGET.glob("*.pdf")):
name = unicodedata.normalize("NFKC", path.stem) # 全角数字・全角スペースを半角に
m = re.search(r"(\d{4})年(\d{1,2})月", name)
if not m:
print(f"[そのまま] {path.name}(年月が見つかりません)")
continue
ym = f"{m.group(1)}-{int(m.group(2)):02d}"
company = re.sub(r"請求書|\d{4}年\d{1,2}月|\s+", "", name).replace("(株)", "株式会社")
new_path = path.with_name(f"{ym}_{company}_請求書.pdf")
if new_path.exists():
print(f"[衝突] {new_path.name} は既にあるので変更しません")
continue
print(f"{path.name} → {new_path.name}")
if not DRY_RUN:
path.rename(new_path)
if DRY_RUN:
print("\n※ 確認だけしました。問題なければ python rename_files.py --run で実行します")$ python rename_files.py
請求書 2026年8月 (株)ABC商事.pdf → 2026-08_株式会社ABC商事_請求書.pdf
請求書 2026年7月 (株)XYZ.pdf → 2026-07_株式会社XYZ_請求書.pdf
※ 確認だけしました。問題なければ python rename_files.py --run で実行します発展2:PDF請求書の整理
PDFの請求書から「請求元・請求日・金額」を抜き出して一覧Excelにする、というのもよくある依頼です。文字情報を持つPDFなら pdfplumber などのライブラリで本文テキストを取り出し、正規表現で項目を拾う、という作りをAIが提案してくれます。ただし、スキャンした画像のPDFは文字情報がないため、OCR(画像から文字を読み取る処理)が別途必要になり、読み取り誤りも起こります。金額を扱う以上、抽出結果は必ず人が元のPDFと照合する前提で、「読み取れなかったファイル」「金額が複数見つかったファイル」を別リストに出すよう頼むのがおすすめです。
発展3:ダブルクリックで動くようにする(.bat/.command)
毎月の担当者がターミナルに慣れていない場合は、ダブルクリックで集計が走るファイルを置いておくと便利です。スクリプトと同じフォルダに置きます。
@echo off
cd /d "%~dp0"
py merge_sales.py
pausecd /d "%~dp0" は「このファイルが置いてあるフォルダに移動する」という意味で、どこからダブルクリックしても正しいフォルダで動くようにしています。最後の pause は、結果を読む前に黒い画面が閉じないようにするためです。Microsoft Store版のPythonなど py コマンドがない環境では python に書き換えます。なお.batに日本語のコメントを書くと文字化けで誤動作することがあるため、この例ではコメントを入れていません。
#!/bin/bash
# このファイルがあるフォルダに移動してから実行する
cd "$(dirname "$0")"
python3 merge_sales.py
read -p "Enterキーで閉じます"Macの .command ファイルは、作成後にターミナルで chmod +x 集計する.command を1回実行して「実行してよいファイル」にしておく必要があります(これもAIに頼めます)。初回はセキュリティの確認が出ることがあります。
VBA・Power Queryとの使い分け
Excelの自動化には、昔からVBA(マクロ)や、Excelに組み込まれたPower Query(データの取得と変換)もあります。AIエージェントはどれでも書けるので、「誰が・どこで・何回使うか」で選ぶのがおすすめです。
| 観点 | Python(本記事) | Power Query | VBA(マクロ) |
|---|---|---|---|
| 向いている作業 | 多数のファイル・CSV・PDFの横断処理、グラフ画像、フォルダ整理まで一括 | フォルダ内のファイル結合、列の整形、定型のデータ取り込み | Excelの画面操作の自動化、ボタン1つの社内ツール |
| 使う人の環境 | Pythonのインストールが必要 | Excelだけでよい | Excelだけでよい(マクロ有効ブック) |
| 処理の見える化 | コードとGitで変更履歴を追える | 「適用したステップ」として画面で見える | コードはブック内。履歴管理はしにくい |
| データ量 | 大きめのデータも扱いやすい | 中程度まで快適 | 行ごとの処理だと遅くなりやすい |
| 社内配布 | 実行環境の準備が必要 | ブックを渡せば使える | マクロのセキュリティ設定・社内ポリシーに注意 |
| AIエージェントとの相性 | ◎ ファイルを直接読み、実行・検証まで自走できる | △ M言語のコードは書けるが、画面操作は人が行う | ○ コードは書けるが、実行・動作確認は人がExcelで行う |
判断に迷ったら、「Excelを開いた人が使う」ならPower Query/VBA、「ファイルが置かれたら処理する」ならPythonと覚えておくとよいでしょう。Power Queryで「支店ファイルの結合」だけを行い、Pythonは使わない、という選択も立派な正解です。

事例:自社と他社の取り組み
「機械的に確かめられることはスクリプトに」— 本サイトの運用
このサイト(約57ページの静的サイト)は、Claude Codeとの共同作業で作成・運用しています。その中で、今回の集計スクリプトと同じ考え方の小さなツールをAIと一緒に作ってきました。
- build.js:共通フッターを全ページに流し込むNode.jsスクリプト。フッター(広告表記)を入れられないページがあると、エラーで止まって公開させない作りにしています。今回の「除外した行を記録する/止めるべきときは止める」と同じ発想です
- keihyo-check.js:広告表記の有無や位置、リンクの属性などを機械的にチェックするスクリプト。重大な問題があれば止め、軽微なものは警告だけ表示します
- 変更は作業ブランチで行い、人が確認してから取り込む流れ。Gitの履歴に、AIとの共同作業の記録が残っています
「毎回人が目で確認していたこと」をAIにスクリプト化してもらい、人は最終判断に集中する——Excel集計の自動化も、構造は同じです。詳しくは【自社事例】AIエージェントでメディアサイトを運用する仕組みをご覧ください。
他社・業界の動き
- Anthropicは、社内でClaude Codeを広く使っており、Claude Code自体のコードの多くもClaude Codeで書いていると公表しています。
- エンジニアではない職種の人が、AIエージェントに頼んで自分の業務用の小さなツール(集計・整形・ファイル整理など)を作る動きが広がっています。今回のExcel集計は、その入口として最も取り組みやすい題材の1つです。
AIエージェントで作れるもの全体を知りたい方は「AIエージェントで開発してみよう」レベル別カタログへ。ファイルやフォルダ、ターミナルといった基礎から学びたい方はIT基礎ロードマップ(特に第5章 サーバー・Linux入門のコマンド操作)もおすすめです。
よくある質問
Pythonを一度も書いたことがなくてもできますか?
できます。コードを書くのはAIエージェントの役割で、あなたの役割は「何をしたいか」を伝え、出てきた集計結果が正しいかを確かめることです。ただし、Pythonのインストールとターミナルでのコマンド実行(python merge_sales.py のような1行)はできるようにしておきましょう。慣れてくると、AIが書いたコードのコメントを読むだけで何をしているか分かるようになります。
会社の売上データをAIに見せても大丈夫ですか?
まず社内のルール(生成AIの利用ガイドライン)と、使うAIサービスのデータの扱い(学習に使われるか、保存期間など)を確認してください。判断がつかない場合は、本番データの代わりに列名と形式だけ同じダミーデータでスクリプトを作らせ、完成したスクリプトを本番データに対して自分で実行する方法が安全です。集計そのものはPythonがあなたのPCの中で行うので、AIが全データを読む必要はありません。
VBAマクロやPower Queryとどちらを使えばいいですか?
Excelの中だけで完結し、他の人もExcelで開いて使う仕組みならPower QueryやVBAが向いています。ファイル数が多い、CSVやPDFも混ざる、グラフ画像やフォルダ整理までまとめて自動化したい、Gitで変更履歴を残したい、という場合はPythonが向いています。AIエージェントはどれも書けるので、「誰が・どこで・何回使うか」で選ぶのがおすすめです。
Macでも同じようにできますか?
できます。この記事のPythonスクリプトはWindowsでもMacでもそのまま動きます。違いはコマンド名(Windowsは py、Macは python3 が一般的)と、グラフの日本語フォント名、ダブルクリックで動かすファイルの形式(Windowsは .bat、Macは .command)くらいです。
まとめ|「毎月のコピペ」はAIに渡し、「数字の確認」は人が持つ
Excel・CSVの集計は、AIエージェントで作る最初の業務ツールとして最適です。やることは、①完成形を伝えて計画を出させる → ②エラーは原因を説明させてから直させる → ③検算スクリプトと1か所の手検算で確かめる → ④Gitで保存し、ダブルクリックで動く形にする、の4ステップ。原本は data/ に「コピー」を置いて読むだけにし、出力は output/ へ、という線引きさえ守れば、怖がる必要はありません。
次は、毎日のブラウザ作業をラクにするChrome拡張機能づくり(🌿中級)に挑戦してみましょう。まだ自分のサイトを作ったことがない方は、1つ前の自分のWebサイトを作って公開する(🌱初級)もどうぞ。
作れるようになったら、スキルを収入につなげる
AIエージェントで「作れる」ことは、それ自体が仕事になります。案件獲得や転職、作業環境づくりに役立つ記事をまとめました。
- AI・IT業界への転職ガイド【2026】:作ったものをポートフォリオに。未経験からの進め方と転職エージェントの選び方
- AIが快適に動くノートパソコンの選び方&おすすめ3選【2026】:開発・AIエージェントを動かすならメモリ16GB以上が目安