前回(Part 1)で Claude Code と e-Stat API の初期セットアップを終えました。appId を取得し、curl で軽く叩いてレスポンスが返ってくることまで確認したはずです。
ここまで来て最初にぶつかる壁が 「目的の統計表 ID(statsDataId)が見つからない」 という問題です。e-Stat には 8,000 を超える統計表が登録されており、UI で探すには分類体系が大きすぎる。API の getStatsList を毎回叩くスクリプトを書くのも面倒。
本記事では、この 「統計表 ID 探し」を Claude Code のスキル機能で自動化 する手順を解説します。一度 SKILL.md を書いてしまえば、以降は /search-estat 人口 のような自然な指示で Claude が候補を絞り込んでくれる状態になります。
筆者は元県庁職員で、現在はstats47.jp(47 都道府県の統計サイト)を 1 人で運営しています。サイトには 530 を超えるランキングがありますが、その全てを支えているのが本記事で紹介する「スキル化」の発想です。実例集の Part 2 として、Claude Code 未経験のソフトウェアエンジニア向けに、再利用可能な手順書としてのスキルを書く流れを共有します。
e-Stat の統計表 ID 探しはなぜ難しいか
e-Stat(政府統計の総合窓口)は、国勢調査・住民基本台帳・経済センサスなど、府省庁が公表する統計を一元的に集約したポータルです。データはほぼ全てが API 経由でも取得できるため、エンジニアにとっては最高クラスのオープンデータ供給源と言えます。
ただし「最高クラス」と「使いやすい」は別問題です。具体的なつらみは 3 つあります。
- 統計表が 8,000 件超: 同じ「人口」というキーワードでも国勢調査・住民基本台帳・推計人口・将来推計人口とソースが複数ある
- 公式 UI の検索が階層型: 分野 → 統計調査 → 統計表 → 表番号、と 4 段階のドリルダウンが必要。1 統計表に辿り着くまでに 10 クリックかかることもある
- statsDataId の命名規則が不透明:
0003448237のような数字 ID で、人間が見ても何のデータか判別できない
API 側で用意されているのが getStatsList というエンドポイントです。キーワード検索もできますが、生のレスポンス JSON は数千行になることもあり、目視で「これだ」と決めるには疲れます。
curl "https://api.e-stat.go.jp/rest/3.0/app/json/getStatsList?appId=$ESTAT_APP_ID&searchWord=人口&limit=5"
このレスポンスをそのまま読むのではなく、「AI に要約させて候補リストにする」 のがスキル化の出発点です。
Claude Code のスキル機能とは
Claude Code には 「スキル(Skill)」 という機能があります。ざっくり言うと、プロジェクト固有の手順書を Markdown ファイルで書いておき、slash command として呼び出せる仕組み です。
特徴を 3 つにまとめます。
| 観点 | 内容 |
|---|---|
| ファイルベース | .claude/skills/<name>/SKILL.md に書く。バイナリ依存なし、Git で管理可能 |
| slash command | /<skill-name> で呼び出せる。Claude Code セッション内で自然に使える |
| 引数フリー | プロンプトは自然言語のまま渡せる。/search-estat 人口の年次推移 のような書き方が可能 |
スキルの実体は SKILL.md という Markdown ファイルです。冒頭に YAML frontmatter で name と description を書き、本文に手順を書く。それだけです。
Claude Code は session 開始時に .claude/skills/ 配下を走査し、見つかった SKILL.md を「呼び出し可能なツール」として認識します。利用者が /search-estat と打つと、その SKILL.md の本文が Claude のシステムプロンプトに合流し、本文に従って動作する流れです。
note: スキル機能は Claude Code 公式の機能です(2025 年後半に正式リリース)。Anthropic のドキュメント上は "Skills" と表記されています。プロジェクト個別のスキルは
.claude/skills/に、グローバル(ユーザー全体)で使うものは~/.claude/skills/に置くのが基本構成です。
SKILL.md の書き方|テンプレート
最小構成の SKILL.md はこんな形になります。
---
name: search-estat
description: e-Stat API の getStatsList を呼び出し、キーワードに一致する統計表の候補を要約して返す。
---
# /search-estat
ユーザーから渡されたキーワードを `searchWord` として e-Stat API に投げ、上位 5 件の統計表を「statsDataId・統計表名・公表機関・調査年」の表形式で返却する。
## 手順
1. ユーザーのプロンプトからキーワードを抽出する(例: 「人口の年次推移」→ `人口`)
2. 環境変数 `ESTAT_APP_ID` を確認する。未設定ならエラーとして停止する
3. `getStatsList` を `searchWord=<キーワード>&limit=5` で呼び出す
4. レスポンス JSON の `LIST_INF` 配列から各表の `@id` / `TITLE` / `GOV_ORG` / `SURVEY_DATE` を抽出する
5. Markdown 表として整形し、最後に「次のアクション例: `/fetch-estat-data <id>` で取得」と添える
## エラー処理
- API がエラーステータスを返した場合は `RESULT.STATUS` と `RESULT.ERROR_MSG` をそのまま提示する
- 該当 0 件の場合は別のキーワード候補を 3 つ提案する(同義語・上位概念・関連分野)
YAML frontmatter の description は、Claude が「いつこのスキルを呼ぶべきか」を判断する材料になります。動詞を含めて、利用シーンが想像できる文章にする のが鉄則です。「e-Stat に関する何か」のような曖昧な記述だと呼び出し精度が落ちます。
本文側は普通の Markdown でよく、装飾やコードブロックも自由に書けます。手順を箇条書きで明文化しておくと、Claude が手順スキップを起こしにくくなります。
/search-estat スキルを書く 5 ステップ
実際に手を動かして /search-estat を作る流れを 5 ステップで追います。
Step 1: スキル用ディレクトリを切る
プロジェクトルートで以下を実行します。
mkdir -p .claude/skills/search-estat
touch .claude/skills/search-estat/SKILL.md
Claude Code は .claude/skills/<name>/SKILL.md という配置を期待します。<name> がそのまま slash command 名になるので、ハイフン区切りで分かりやすい名前を付けます。今回は search-estat としました。
Step 2: frontmatter を書く
エディタで SKILL.md を開き、まず frontmatter から書きます。
---
name: search-estat
description: e-Stat API の getStatsList を呼び出し、キーワードに一致する統計表 ID 候補を要約して返す。データ取得前の調査ステップで使う。
---
description は 1〜2 文で具体的に書きます。「データ取得前の調査ステップで使う」のように利用シーンを添えると、Claude が自動でスキルを選んでくれるシーンが増えます。
Step 3: 検索フローを設計する
スキル本文に書く手順を整理します。今回のフローは以下のとおりです。
文章で書くなら次の 5 アクションです。
- プロンプトからキーワード抽出
ESTAT_APP_IDの存在確認getStatsList呼び出し(searchWord,limit=5)- レスポンスから必要フィールド抽出
- Markdown 表に整形して返却
この各ステップを SKILL.md の ## 手順 セクションに書きます。
Step 4: 利用する API パラメータを表で明文化する
スキル内でどの API パラメータを使うかを表で書いておくと、後から読み返したときに分かりやすいです。getStatsList の主要パラメータは以下のとおり。
| パラメータ | 必須 | 型 | 説明 |
|---|---|---|---|
appId | 必須 | string | e-Stat の発行する API キー |
searchWord | 任意 | string | 検索キーワード。スペース区切りで AND 検索 |
statsCode | 任意 | string | 政府統計コード(8 桁)。府省庁単位で絞り込む際に使用 |
surveyYears | 任意 | string | 調査年。YYYY または YYYYMM-YYYYMM のレンジ指定 |
openYears | 任意 | string | 公開年。新しいデータだけ欲しい時に有効 |
limit | 任意 | int | 返却件数上限。デフォルト 10 万、検索用途なら 5〜20 程度 |
startPosition | 任意 | int | ページネーション用の開始位置。1 起点 |
レスポンス側で抽出するフィールドも整理します。
| JSON パス | 中身 |
|---|---|
GET_STATS_LIST.DATALIST_INF.LIST_INF[].@id | statsDataId(10 桁の数字 ID) |
GET_STATS_LIST.DATALIST_INF.LIST_INF[].TITLE.$ | 統計表名 |
GET_STATS_LIST.DATALIST_INF.LIST_INF[].GOV_ORG.$ | 公表機関名(例: 総務省統計局) |
GET_STATS_LIST.DATALIST_INF.LIST_INF[].SURVEY_DATE | 調査年(YYYY または YYYYMM) |
GET_STATS_LIST.DATALIST_INF.LIST_INF[].STATISTICS_NAME | 統計調査名(例: 国勢調査) |
Step 5: 完成版 SKILL.md を書く
ここまでの設計をまとめると、最終的な SKILL.md は次のようになります。
---
name: search-estat
description: e-Stat API の getStatsList を呼び出し、キーワードに一致する統計表 ID 候補を要約して返す。データ取得前の調査ステップで使う。
---
# /search-estat
## 目的
ユーザーが指定したキーワードに対して、e-Stat の統計表 ID(statsDataId)を上位 5 件まで提案する。データ取得スキル(/fetch-estat-data)の前段として使う。
## 前提
- 環境変数 `ESTAT_APP_ID` に有効な API キーが設定されていること
- Node.js 18 以上(fetch 標準搭載)または Python 3.9 以上
## 手順
1. ユーザーのプロンプトからキーワードを抽出する。複数語ある場合はスペース区切りで連結(例: 「県民所得 最新」→ `searchWord=県民所得 最新`)
2. `ESTAT_APP_ID` を `process.env` から取得。未設定なら以下を出力して終了:
- `Error: ESTAT_APP_ID が未設定です。https://www.e-stat.go.jp/api/ で取得し、.env に追記してください。`
3. 以下の Node.js コードを実行する:
```javascript
const url = new URL("https://api.e-stat.go.jp/rest/3.0/app/json/getStatsList");
url.searchParams.set("appId", process.env.ESTAT_APP_ID);
url.searchParams.set("searchWord", keyword);
url.searchParams.set("limit", "5");
const res = await fetch(url);
const json = await res.json();
-
json.GET_STATS_LIST.RESULT.STATUSを確認し、0 以外ならエラーメッセージ(ERROR_MSG)をユーザーに提示して停止 -
json.GET_STATS_LIST.DATALIST_INF.LIST_INFを最大 5 件まで取り出し、以下の Markdown 表を作成:# statsDataId 統計表名 公表機関 調査年 -
表の末尾に次のフォローアップを追加:
次のアクション例: /fetch-estat-data <statsDataId> で実データを取得できます。
エラー処理
- ネットワークエラー時はリトライせず、エラー内容をそのまま出力する
- 検索結果が 0 件の場合は、同義語・上位概念・関連分野のキーワード候補を 3 つ提案する(例: 「賃金」が 0 件なら「給与」「所得」「報酬」)
- API のレートリミット(HTTP 429)に当たった場合は 60 秒待機を提案し、自動リトライは行わない
出力例
ユーザー: /search-estat 人口
応答:
| # | statsDataId | 統計表名 | 公表機関 | 調査年 |
|---|---|---|---|---|
| 1 | 0003448237 | 人口推計 / 都道府県、年齢階級別人口 | 総務省統計局 | 2024 |
| 2 | 0003410379 | 国勢調査 / 男女別人口・世帯数 | 総務省統計局 | 2020 |
| ... | ... | ... | ... | ... |
次のアクション例: /fetch-estat-data 0003448237 で実データを取得できます。
これで `/search-estat` の準備は完了です。Claude Code セッションを再起動するか、スキル一覧を更新すれば呼び出せるようになります。
## getStatsList のレスポンス構造
スキル本文に書いた `LIST_INF` の構造を、もう少し具体的に確認しておきます。`getStatsList?searchWord=人口&limit=2` を叩いた場合、概ね以下のような JSON が返ります。
```json
{
"GET_STATS_LIST": {
"RESULT": {
"STATUS": 0,
"ERROR_MSG": "正常に終了しました。",
"DATE": "2026-05-19T10:00:00.000+09:00"
},
"PARAMETER": {
"LANG": "J",
"SEARCH_WORD": "人口",
"LIMIT": 2,
"DATA_FORMAT": "J"
},
"DATALIST_INF": {
"NUMBER": 2,
"RESULT_INF": {
"FROM_NUMBER": 1,
"TO_NUMBER": 2
},
"LIST_INF": [
{
"@id": "0003448237",
"STAT_NAME": { "@code": "00200524", "$": "人口推計" },
"GOV_ORG": { "@code": "00200", "$": "総務省" },
"STATISTICS_NAME": "人口推計 都道府県、年齢階級別人口",
"TITLE": { "@no": "01", "$": "都道府県、年齢階級別人口" },
"SURVEY_DATE": "202410",
"OPEN_DATE": "2025-04-15"
},
{
"@id": "0003410379",
"STAT_NAME": { "@code": "00200521", "$": "国勢調査" },
"GOV_ORG": { "@code": "00200", "$": "総務省" },
"STATISTICS_NAME": "令和2年国勢調査",
"TITLE": { "@no": "1-1", "$": "男女別人口・世帯数及び世帯人員" },
"SURVEY_DATE": "202010",
"OPEN_DATE": "2021-11-30"
}
]
}
}
}
特徴的なのは、テキスト値が { "@code": "...", "$": "..." } のような構造で返ってくる点です。これは XML 由来の名残で、$ が値本体、@xxx が属性に相当します。慣れないとアクセスパスを間違えやすいので、要約スクリプトを書くときは慎重に。
Python で同じ呼び出しをする場合は次のようになります。
import os
import requests
APP_ID = os.environ["ESTAT_APP_ID"]
url = "https://api.e-stat.go.jp/rest/3.0/app/json/getStatsList"
params = {"appId": APP_ID, "searchWord": "人口", "limit": 5}
res = requests.get(url, params=params, timeout=30)
data = res.json()
list_inf = data["GET_STATS_LIST"]["DATALIST_INF"]["LIST_INF"]
for item in list_inf:
print(f"{item['@id']} | {item['STATISTICS_NAME']} | {item['GOV_ORG']['$']}")
このスニペットは SKILL.md の手順 3 に Python 版として併記しておくと、Python 派の開発者でも同じスキルを再利用できます。
実行例|「人口」で検索してみる
実際に Claude Code 上で /search-estat を呼び出すと、こんな対話になります。
あなた: /search-estat 人口
Claude: getStatsList を searchWord=人口, limit=5 で実行します。
| # | statsDataId | 統計表名 | 公表機関 | 調査年 |
| - | ----------- | ---------------------------------------------- | ------------ | -------- |
| 1 | 0003448237 | 人口推計 都道府県、年齢階級別人口 | 総務省 | 2024-10 |
| 2 | 0003410379 | 国勢調査 男女別人口・世帯数及び世帯人員 | 総務省 | 2020-10 |
| 3 | 0003448239 | 人口推計 年齢(5歳階級)、男女別人口 | 総務省 | 2024-10 |
| 4 | 0004021907 | 住民基本台帳人口・世帯数、人口動態(都道府県別) | 総務省 | 2024-01 |
| 5 | 0003337392 | 将来推計人口(都道府県・市区町村別) | 国立社人研 | 2018 |
次のアクション例: /fetch-estat-data 0003448237 で実データを取得できます。
5 件並べてみると、それぞれが微妙に違うデータセットだと一目で分かります。直近の都道府県別が欲しいなら 0003448237、5 年に 1 度の悉皆調査なら 0003410379、将来推計が欲しいなら 0003337392。「人間が選ぶ判断材料」だけを AI に整形してもらう という分業が綺麗にできています。
仮にこれを毎回手で curl していたら、JSON を読むのに 5 分、表に整形するのに 5 分かかります。スキル化すれば 10 秒で同じアウトプットが得られます。
スキル化の効果|なぜ毎回 prompt を書かないのか
「同じことを長いプロンプトで毎回頼めばいいのでは?」という疑問はもっともです。それでも筆者がスキル化に手間をかける理由は 3 つあります。
- プロンプトの揺れがなくなる: 自然言語で毎回頼むと、「上位 5 件で」を書き忘れて 20 件返ってきたり、Markdown 表でなく箇条書きになったりする。SKILL.md に手順を固定すると出力が安定する
- チームで共有できる: SKILL.md は Git にコミットすればチーム全員が同じスキルを使える。「あの分析、誰々さんのプロンプトじゃないと再現できない」問題が消える
- 改善が積み上がる: 「該当 0 件のときは同義語を 3 つ提案する」のような細かい工夫を SKILL.md に書き加えていける。プロンプトをコピペし続ける運用だと、こうした学びが個人の中に閉じてしまう
特に 3 つ目が大きいです。stats47.jp では現在 60 以上のスキルを運用していますが、それぞれが「過去のミスを踏まないためのチェックリスト」になっています。例えば /search-estat であれば「statsCode を指定すれば府省庁単位で絞れる」「surveyYears で古い表を除外できる」といった改善を、SKILL.md に追記していくだけで全員が恩恵を受けられます。
つまずきポイント 3 選
最後に、初めて SKILL.md を書く人が踏みやすい地雷を 3 つだけ。
1. slash command が認識されない
SKILL.md を作ったのに /search-estat がサジェストに出てこない場合、9 割は以下のどれかが原因です。
- ディレクトリ名と frontmatter の
nameが不一致(search-estatとsearch_estatの混在など) - SKILL.md が
.claude/skills/search-estat/直下ではなくサブディレクトリに入っている - Claude Code セッションを再起動していない(スキル一覧は session 起動時にスキャンされる)
ディレクトリ構造を ls .claude/skills/search-estat/ で確認し、SKILL.md がトップにあることを確認してください。
2. ESTAT_APP_ID が未設定でエラー
スキル本文に「環境変数を確認する」と書いてあっても、Claude が確認をスキップして API を叩いて 401 が返るケースがあります。対策は以下 2 つ。
.envファイルにESTAT_APP_ID=xxxxを書いておき、shell 側でsource .envする- SKILL.md 冒頭に 太字で 「実行前に必ず
echo $ESTAT_APP_IDで値を確認する」と明記する
文章を太字や警告ブロックで強調すると、Claude のスキップ率が体感で半減します。
3. 表数が多すぎてレスポンスが切れる
limit を指定せず叩くと、getStatsList は最大 10 万件返してきます。Claude のコンテキスト窓を圧迫してその先の処理が破綻するので、スキル本文に必ず limit=5 を書き込む のが安全です。多めに見たい時だけ limit=20 などに上書きする運用にします。
仮に検索結果が多すぎて目的の表が下位に埋もれる場合は、statsCode(府省庁コード)か surveyYears(年)で絞り込みを掛けます。SKILL.md に「結果が広すぎる場合は statsCode を聞き返す」のような分岐を書いておくと、対話がさらに賢くなります。
次回予告|取得した ID で人口データを棒グラフ化する
ここまでで「目的の statsDataId を Claude に探させる」が完了しました。次回 Part 3 では、取得した ID を使って getStatsData を呼び、47 都道府県の人口データを D3.js で棒グラフに変換する ところまでをやります。
/fetch-estat-dataスキルの設計- レスポンス JSON から都道府県別配列を作る整形ロジック
- D3.js での横棒グラフ実装(SVG 出力)
- 棒グラフを記事に貼るための画像化(puppeteer / sharp)
Claude Code を「データの検索」だけでなく「可視化までの一気通貫」に育てていく流れを共有します。引き続きお付き合いください。
関連ランキング・記事
- Claude Code で47都道府県分析を自動化|公務員のための AI × 統計 7 ステップ — シリーズの大元になった元県庁職員視点の全体像解説
- Claude Code × e-Stat API 環境構築|appId 取得から最初の curl まで — 本シリーズ Part 1。e-Stat 登録と最初の API 呼び出し
- Claude Code で人口データを棒グラフ化|D3.js × Skill の合わせ技 — 本シリーズ Part 3(公開予定)。/fetch-estat-data スキルと可視化
- 都道府県別 人口総数ランキング(最新年) — getStatsList で 1 位に出てくる人口推計の活用例
- 統計分野別 検索可能なデータセット一覧 — stats47 が登録している調査ごとの統計表ライブラリ