🌱 初級⏱ 所要時間の目安:1〜2時間Claude Code / Python(pandas・openpyxl・matplotlib)

Excel・CSVの面倒な集計をAIエージェントとPythonで自動化【2026】コピペ作業を1コマンドに

毎月、支店から届く売上Excelを開いて、コピーして、貼り付けて、合計して、グラフを作る——。この「毎月30分〜数時間のコピペ作業」は、AIエージェントにPythonスクリプトを書かせると、次の月からはコマンド1つ(またはダブルクリック1回)で終わるようになります。この記事では、Claude Code(ターミナルで動くAnthropicのコーディングエージェント)との実際のやりとりを時系列で再現しながら、途中で出るエラーとその直し方、原本データを壊さないための安全策まで、初めての方でも真似できる形で解説します。

🔬
調査・編集:AIエージェント研究所 編集部
運営=広告運用・生成AIエージェント導入支援の現役コンサル。このサイト自体も、AIエージェントと一緒に作り・公開・運用しています。

記事中のPythonコードは、編集部でダミーの売上Excelを作成し、実際に実行して動作を確認したものです。→ 運営者・編集方針について

公開:2026年9月26日/最終更新:2026年9月26日
この記事の結論(要点まとめ)
  • 「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/(完成後のフォルダ構成)フォルダ
sales-report/
├── data/                  ← 支店から届いた原本(読むだけ・絶対に書き換えない)
│   ├── 渋谷店_売上.xlsx
│   ├── 新宿店_売上.xlsx
│   └── 横浜店_売上.xlsx
├── output/                ← スクリプトが作る結果(何度でも作り直せる)
│   ├── 月次売上集計.xlsx    (シート:支店×月/商品別/統合データ)
│   ├── 月次売上グラフ.png
│   └── 除外した行.csv       (読めなかった行の記録)
├── merge_sales.py         ← AIが書いた集計スクリプト
├── check_totals.py        ← 検算スクリプト
├── 集計する.bat / 集計する.command  ← ダブルクリック用
└── CLAUDE.md              ← AIへの「このフォルダのルール」
① data/(原本)渋谷店_売上新宿店_売上横浜店_売上② 1コマンドまたはダブルクリック③ 読み込み・整えるmerge_sales.py全シートを統合列名・全角数字を整える読むだけ④ output/集計Excelグラフ画像除外した行書き出す原本(data/)は書き換えず、結果はいつでも作り直せる
支店のExcelを data/ にコピーし、1コマンド(py merge_sales.py、またはダブルクリック)を実行すると、全ファイル・全シートを統合し、列名や全角数字をそろえて、集計Excel・グラフ画像・除外した行の記録を output/ に出力します。

出力される「支店×月」シートは、たとえば次のような表です(編集部がダミーデータで実行した結果)。

支店2026-072026-08合計
新宿店77,722113,880191,602
横浜店99,02195,381194,402
渋谷店115,13698,052213,188
合計291,879307,313599,192
助手アイ
助手アイこれ、毎月手作業でやってました……。でもPythonって書いたことがないんです。本当に私でもできますか?
エージェント博士
エージェント博士できるとも。コードを書くのはAIの仕事じゃ。アイくんの仕事は「何をしたいか」を正確に伝えることと、「出てきた数字が正しいか」を確かめること。この2つは、毎月その作業をしてきた人にしかできんのじゃぞ

準備:Python・Claude Code・作業フォルダ

1. Pythonを入れる

Pythonは、今回の集計を実際に実行する「計算係」です。python.org から最新版をインストールします。Windowsではインストーラーの「Add python.exe to PATH」にチェックを入れておくと後が楽です。インストールできたら、ターミナル(Windowsは「ターミナル」または「PowerShell」、Macは「ターミナル」)で確認します。

ターミナルBash
# Windows(python.orgのインストーラーで入れた場合は py コマンドが使える)
py --version
py -m pip install pandas openpyxl matplotlib

# Mac
python3 --version
python3 -m pip install pandas openpyxl matplotlib

pandasは表データを扱うライブラリ(Excelで言えば「関数とピボットテーブルの詰め合わせ」)、openpyxlはpandasが.xlsxを読み書きするときに使う部品、matplotlibはグラフを描くライブラリです。実はこのインストールも、Claude Codeに「必要なライブラリを入れて」と頼めばやってくれます。

2. Claude Codeを入れる

Claude Codeは、ターミナルで動くAIエージェントです。フォルダの中のファイルを読み、コードを書き、コマンドを実行し、エラーを見て直すところまで自分で進めます。インストール方法は公式ドキュメント(Anthropic公式ドキュメント)に従ってください(執筆時点では npm install -g @anthropic-ai/claude-code などの方法が案内されています)。利用にはAnthropicの有料プランかAPIの利用契約が必要です。料金・プランは変わることがあるので公式で確認してください。

Cursor・Codexなどでも同じ流れでできます この記事ではClaude Codeを例にしますが、Cursor、OpenAIのCodex、GitHub Copilotのエージェント機能など、「ファイルを読み、コードを書き、コマンドを実行できる」AIエージェントなら同じ進め方ができます。大事なのはツールよりも「頼み方」と「確かめ方」です。

3. 作業フォルダを作り、Gitで記録を始める

本番の売上ファイルを直接使うのではなく、コピーを置いた作業用フォルダを作ります。最初はダミーデータでも構いません。

ターミナルBash
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に見せる前に 会社の生成AI利用ルールと、使うAIサービスのデータの扱い(学習に使われるか・保存期間)を確認してください。迷う場合は、列名と形式だけ同じダミーデータでスクリプトを作り、完成したスクリプトを本番データに対して自分で実行する方法が安全です。集計はあなたのPCの中のPythonが行うので、AIが全件を読む必要はありません。

AIとの実際のやりとりを再現(依頼→エラー→修正→検算)

ここからは、編集部がダミーデータで実際に行った流れをもとに、Claude Codeとのやりとりを時系列で再現します。プロンプトはそのままコピーして使えます。

Step 1:やりたいことを「完成形」で伝える

最初の依頼では、入力(どこに何があるか)・出力(何をどこに出すか)・守ってほしいことの3点を伝えます。いきなり書かせず、まず計画を出させるのがポイントです(Claude Codeでは Shift+Tab で「Plan Mode」に切り替えると、コードを変更する前に計画を提示してくれます)。

あなた → Claude Code(プロンプト①)プロンプト
data/ にある売上ファイル(.xlsx、各ファイルに月ごとのシートがある)を全部まとめて、
次のものを output/ に出すPythonスクリプト merge_sales.py を作ってください。

- 支店×月の売上合計表(行:支店、列:月、合計つき)
- 商品別・月別の売上合計
- 支店別の月次売上の棒グラフ(PNG)
- 支店名はファイル名の「_」より前(例:渋谷店_売上.xlsx → 渋谷店)

守ってほしいこと:
- data/ の中のファイルは絶対に書き換えない(読むだけ)
- pandas と openpyxl を使う
- まず data/ のファイルの中身(シート名・列名)を確認して報告し、
  作り方の計画を見せてから書き始めてください

Claude Codeは、まず短いPythonをその場で実行して各ファイルのシート名と先頭数行を調べ、次のような計画を返してきました(要約)。

Claude Code の返答(要約)出力
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 で棒グラフを保存
この計画で進めてよいですか?
ここで気づけると一流 実はこの報告、横浜店だけ列名が「売上金額」であることを見落としています(AIは最初の数ファイルを見て「全部同じ」と判断しがちです)。人間が「全ファイルの列名を一覧にして」と一言返せば、この時点で防げます。今回はあえてそのまま進め、何が起きるかを見てみましょう。

Step 2:最初のスクリプトを実行 → エラー

「OK、進めて」と返すと、Claude Codeは最初の版を書いて実行しました。核になる部分は次のようなシンプルなものです。

merge_sales.py(最初の版・核の部分)Python
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:「原因を説明してから直して」と頼む

エラーが出たとき、「直して」だけでも直してはくれます。しかし原因を説明させると、あなた自身がデータの癖を理解でき、次に同じことが起きても判断できるようになります。

あなた → Claude Code(プロンプト②)プロンプト
エラーの原因を、Excelしか使ったことがない人にも分かるように説明してから直してください。
同じ種類の問題がほかのファイルやシートにもないか、全ファイル・全シートを確認してください。
data/ の原本は変更しないこと。

Claude Codeは全シートの列名と値の型を調べ、次のように説明しました(要約)。

Claude Code の返答(要約)出力
原因は3つありました。
1. 新宿店の7月シートに「12,500」「8800円」のような全角数字・円付きの値があり、
   Excelでは数値に見えても実際は「文字」として入っています。数値と文字は足せないのでエラーになりました。
2. 横浜店だけ列名が「売上金額」でした。このまま連結すると、横浜店の「売上」列が空になり、
   エラーは出ないまま横浜店の合計が 0 円になります(こちらのほうが危険です)。
3. 新宿店の8月シートに空行と、最終行に「合計」という行がありました。
   合計行を足すと二重計上になります。

対応:列名の対応表で「売上金額」→「売上」にそろえ、全角→半角変換(NFKC)と「,」「円」の除去をしてから
数値に変換します。日付として読めない行(合計行など)は集計から外し、output/除外した行.csv に記録します。
助手アイ
助手アイ2番目、怖いですね……。エラーが出ないのに横浜店が0円って、気づかずに会議に出しちゃいそう。
エージェント博士
エージェント博士そうじゃ。エラーは親切、静かな間違いは不親切なんじゃ。編集部で試したときも、全角数字だけ直した段階では本当に「横浜店 0.0」と出ておった。だから次の「検算」が欠かせんのじゃぞ

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:検算させる(ここが一番大事)

あなた → Claude Code(プロンプト③)プロンプト
集計が正しいか確かめたいです。元ファイル・シートごとの行数と売上合計を出し、
集計表の総合計と一致するかを確認する check_totals.py を作って実行してください。
新宿店7月の「12,500」の行が 12500 として入っているかも見せてください。
check_totals.pyPython
"""検算:元ファイル・シートごとの合計と、集計表の総合計が一致するかを確かめる"""
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の標準フォントに日本語が入っていないためです。

あなた → Claude Code(プロンプト④)プロンプト
グラフの日本語が□になります。WindowsでもMacでも日本語が表示されるように、
OSに入っている日本語フォントを使う設定にしてください。

Claude Codeは、plt.rcParams["font.family"] に「Yu Gothic(Windows)」「Hiragino Sans(Mac)」「Noto Sans CJK JP(Linux等)」などの候補を並べる修正をしました。候補のうち、そのPCに入っているフォントが使われます。

Step 7:Gitで保存する

あなた → Claude Code(プロンプト⑤)プロンプト
ここまでの変更をGitにコミットしてください。data/ と output/ はコミットに含めないよう
.gitignore に追加してください。コミットメッセージは日本語で、何を直したか分かるように。

これで「スクリプトの変更履歴」だけがGitに残ります。次に何か直して壊れても、いつでもこの動く状態に戻れます。売上データ自体は個人情報や機密を含むことが多いので、Gitには入れず、元の保管場所で管理するのが基本です。

完成したスクリプトの解説

修正を重ねて完成した merge_sales.py の全文です。編集部でダミーデータ(3支店×2か月、全角数字・列名の揺れ・空行・合計行を含む)に対して実行し、上の結果が出ることを確認しています(Python 3.11、pandas 3.0、openpyxl 3.1、matplotlib 3.11 で確認)。

merge_sales.py(完成版)Python
"""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_excel1つのExcelファイルに複数シートで書き出す新しいブックにシートを作って貼り付け

「なぜこう作るか」の判断ポイント

  • 変換できない値はエラーで止めずに「除外+記録」:1行の入力ミスで全体が止まると毎月の運用がつらくなります。一方で黙って捨てると数字が合わなくなるので、除外した行.csv に残す折衷案にしています。逆に「1行でもおかしければ止めたい」(経理の締めなど)なら、除外行があったら SystemExit で止める方針に変えるよう頼みましょう。
  • 列名の揺れは「対応表」で吸収:AIに「列名を推測して」と任せるより、対応表を明示したほうが、なぜその列が売上として扱われたのかを後から説明できます。
  • パスの扱いは pathlib で:最初の版の path.split("/") は、区切り文字が \ になるWindowsでは支店名を正しく取り出せません。完成版は pathlib の path.stem(拡張子を除いたファイル名)を使い、OSに依存しないようにしています。「WindowsとMacの両方で動くように」と最初に伝えておくと、AIもこうした書き方を選びます。
  • 統合データもシートとして出力:集計結果だけでなく、集計前の整えたデータも残すと、「この数字はどの行から来たのか」をExcelのフィルターで追えます。
CSVの場合は文字コードに注意 国内の業務システムから出力したCSVは、Shift_JIS(Windowsでは cp932)で保存されていることがよくあります。pd.read_csv(path, encoding="cp932") のように文字コードを指定しないと、UnicodeDecodeError で読めません。逆にPythonからCSVを出力してExcelで開くなら、encoding="utf-8-sig" にすると文字化けしにくくなります(上のスクリプトの 除外した行.csv もこの指定です)。古い .xls 形式は、追加のライブラリ(xlrd)が必要になる点も覚えておきましょう。

原本を壊さないための安全策

AIエージェントは、ファイルの作成・変更・削除ができます。便利な反面、「原本を上書きしてしまった」が一番怖い事故です。次の3層で守ります。

AIエージェントClaude Codemerge_sales.py集計スクリプトdata/原本output/出力①フォルダで分ける② CLAUDE.md読むだけと明記お願い③ settings.json編集・rmを拒否強制ブロック上書き読むだけ書くのはoutput/だけ
原本は data/、出力は output/ に分け、スクリプトは output/ にしか書きません(①)。CLAUDE.md に「data/ は読むだけ」と明記し(②)、さらに .claude/settings.json で data/ の編集や rm を拒否しておけば(③)、AIが原本を書き換えようとしても設定のレベルで止まります。

CLAUDE.md は「このフォルダで働くときのお願いと手順書」です。Claude Codeは起動するたびにこれを読みます。

CLAUDE.mdMarkdown
# 売上集計プロジェクト

## 目的
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 は禁止する操作です。

.claude/settings.jsonJSON
{
  "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 は禁止しています。設定の書き方は変わることがあるので、公式ドキュメントも確認してください。

設定は「完璧な壁」ではない 権限設定はClaude Codeの操作を制限するものですが、たとえばAIが書いたPythonスクリプトの中身まで検査するわけではありません。原本のバックアップは、AIとは関係のない場所(共有ドライブの元フォルダなど)に必ず残しておくこと。「data/ にはコピーを置く」は、そのための最初のルールです。
エージェント博士
エージェント博士「バイブコーディング(vibe coding)」という言葉を聞いたことはあるかの?2025年2月にAndrej Karpathy氏が広めた、雰囲気でAIに任せきりにする作り方のことじゃ。遊びならそれもいい。だが売上の数字は会社の意思決定に使われる。このシリーズでは、仕様を伝え、結果を確かめ、記録を残す進め方をすすめておるんじゃぞ

つまずきポイントとAIへの頼み方

初めてのときに出会いやすいトラブルと、そのときの頼み方です。エラーメッセージは全文をそのまま貼り付けるのが一番の近道です。

症状よくある原因AIへの頼み方の例
ModuleNotFoundError: No module named 'openpyxl'ライブラリが未インストール、またはPythonが複数入っていて別のほうに入った「このエラーが出ます。どのPythonで実行されているか確認して、同じPythonにライブラリを入れてください」
PermissionError(書き込み時)output の集計ExcelをExcelで開いたまま実行した「出力ファイルが開いているときは、分かりやすいメッセージを出して終了するようにして」
数値が文字扱いになる/合計が合わない全角数字、「円」「,」付き、前後の空白、文字列として保存された数値「売上列で数値に変換できない値を、ファイル名・シート名・行番号つきで一覧にして」
日付が 45870 のような数字になるExcelの日付が「シリアル値」のまま読まれている「日付列にExcelのシリアル値が混ざっているようです。正しい日付に変換して」
グラフの日本語が□になるmatplotlibの標準フォントに日本語がない「グラフの日本語が□になるので、OSの日本語フォントを使うようにして」
CSVで UnicodeDecodeErrorShift_JIS(cp932)のCSVをUTF-8として読んでいる「このCSVの文字コードを判定して、正しく読めるようにして」
ある支店だけ数字が0/空になる列名の揺れ(エラーにならない)「全ファイル・全シートの列名を一覧表にして、揺れがないか確認して」
AIへの頼み方・3つの型
  • 説明させてから直させる:「原因を説明してから直して」
  • 範囲を広げて点検させる:「同じ問題がほかのファイルにもないか全部確認して」
  • 確かめる手段を作らせる:「正しいことを確認するスクリプト(検算)も作って実行して」

会話が長くなってAIの返答がちぐはぐになってきたら、/clear で会話をリセットし、CLAUDE.md と現在のコードを前提に仕切り直すのも有効です。作業中に止めたいときは Esc キーで中断できます。

発展:ファイル名の一括変換・PDF請求書・ダブルクリック実行

発展1:ファイル名の一括変換(まず「表示だけ」→確認して実行)

「請求書 2026年8月 (株)ABC商事.pdf」のようなバラバラのファイル名を、「2026-08_株式会社ABC商事_請求書.pdf」に統一する例です。ファイル名の変更は取り消しにくいので、既定では変更予定を表示するだけ、--run を付けたときだけ実行する作りにしてもらいます。

あなた → Claude Code(プロンプト)プロンプト
scans/ のPDFのファイル名を「YYYY-MM_会社名_請求書.pdf」にそろえるスクリプトを作ってください。
全角数字や全角スペースが混ざっています。「(株)」は「株式会社」にしてください。
いきなり変更せず、まず変更前→変更後の一覧を表示するだけのモードで動かして、私に見せてください。
同じ名前のファイルがすでにある場合は上書きしないこと。
rename_files.pyPython
"""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)

毎月の担当者がターミナルに慣れていない場合は、ダブルクリックで集計が走るファイルを置いておくと便利です。スクリプトと同じフォルダに置きます。

集計する.bat(Windows)バッチ
@echo off
cd /d "%~dp0"
py merge_sales.py
pause

cd /d "%~dp0" は「このファイルが置いてあるフォルダに移動する」という意味で、どこからダブルクリックしても正しいフォルダで動くようにしています。最後の pause は、結果を読む前に黒い画面が閉じないようにするためです。Microsoft Store版のPythonなど py コマンドがない環境では python に書き換えます。なお.batに日本語のコメントを書くと文字化けで誤動作することがあるため、この例ではコメントを入れていません。

集計する.command(Mac)シェル
#!/bin/bash
# このファイルがあるフォルダに移動してから実行する
cd "$(dirname "$0")"
python3 merge_sales.py
read -p "Enterキーで閉じます"

Macの .command ファイルは、作成後にターミナルで chmod +x 集計する.command を1回実行して「実行してよいファイル」にしておく必要があります(これもAIに頼めます)。初回はセキュリティの確認が出ることがあります。

さらに自動化するなら 「毎月1日の朝に自動で集計して共有フォルダに置く」なら、Windowsのタスクスケジューラ、Macのlaunchd、Linuxのcronで定期実行できます。設定方法もAIエージェントに「このスクリプトを毎月1日9時に実行する設定をして。設定内容を説明してから」と頼めば案内してくれます。PCが起動していないと動かない点には注意しましょう。

VBA・Power Queryとの使い分け

Excelの自動化には、昔からVBA(マクロ)や、Excelに組み込まれたPower Query(データの取得と変換)もあります。AIエージェントはどれでも書けるので、「誰が・どこで・何回使うか」で選ぶのがおすすめです。

観点Python(本記事)Power QueryVBA(マクロ)
向いている作業多数のファイル・CSV・PDFの横断処理、グラフ画像、フォルダ整理まで一括フォルダ内のファイル結合、列の整形、定型のデータ取り込みExcelの画面操作の自動化、ボタン1つの社内ツール
使う人の環境Pythonのインストールが必要ExcelだけでよいExcelだけでよい(マクロ有効ブック)
処理の見える化コードとGitで変更履歴を追える「適用したステップ」として画面で見えるコードはブック内。履歴管理はしにくい
データ量大きめのデータも扱いやすい中程度まで快適行ごとの処理だと遅くなりやすい
社内配布実行環境の準備が必要ブックを渡せば使えるマクロのセキュリティ設定・社内ポリシーに注意
AIエージェントとの相性◎ ファイルを直接読み、実行・検証まで自走できる△ M言語のコードは書けるが、画面操作は人が行う○ コードは書けるが、実行・動作確認は人がExcelで行う

判断に迷ったら、「Excelを開いた人が使う」ならPower Query/VBA、「ファイルが置かれたら処理する」ならPythonと覚えておくとよいでしょう。Power Queryで「支店ファイルの結合」だけを行い、Pythonは使わない、という選択も立派な正解です。

助手アイ
助手アイAIエージェントが実行まで自分でできるから、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で独立するには?未経験から案件を取る6ステップ【2026】自動化・開発スキルを案件にする。フリーランスエージェントの選び方も
記事を読む

次の一歩

姉妹サイトの記事で、次に気になりやすいことを調べられます。