Claude Media
e-Gov法令APIとClaude Codeで法改正の施行日と条文差分を毎週追う

e-Gov法令APIとClaude Codeで法改正の施行日と条文差分を毎週追う

e-Gov法令API(Version 2)で改正履歴と未施行版の本文を取り、前回との差分と施行日を影響メモにする週次タスクの組み方。定期実行の選び方と取得時の注意つき。

法改正の確認は、官報や所管官庁の発表を眺めるだけでは漏れが出ます。公布されても施行日が先で、気づいたときには社内の準備が間に合わないことがあるためです。

e-Gov法令検索のデータはHTTP APIで取れます。監視したい法令を決めて週に1回APIを叩き、前回との条文差分と施行日を社内向けのメモにまとめる。この作業はClaude Codeの定期実行と相性がよいです。ここでは、取得スクリプト、差分の読み方、週次で回す方法を順に扱います。

法令API Version 2で使う3つのエンドポイント

法令API Version 2のベースURLはhttps://laws.e-gov.go.jp/api/2です。仕様書(OpenAPI形式のYAML)には認証方式の記載がなく、この記事のスクリプトもキーなしで動きます。

法改正の追跡に使うのは、次の3つです。

エンドポイント役割追跡での使いどころ
/laws役割法令一覧の取得・検索追跡での使いどころ法令名からlaw_idを調べる
/law_revisions/{law_id}役割改正履歴の一覧追跡での使いどころ未施行の改正と施行日を拾う
/law_data/{law_revision_id}役割法令本文の取得追跡での使いどころ版ごとの条文を保存して比べる

/lawsの取得件数は既定で100件、limitとoffsetで区切れます。/law_revisionsは新しい履歴から順に返します。

履歴の状態はcurrent_revision_statusで判別します。CurrentEnforcedが現施行、UnEnforcedが未施行、PreviousEnforcedが過去の施行版、Repealが廃止・失効です。法改正の追跡では、現施行と未施行の2つを見れば足ります。

法令IDを調べる

監視対象はlaw_idで指定します。法令名の部分一致で探せます。

curl -s "https://laws.e-gov.go.jp/api/2/laws?limit=3\
&law_title=個人情報の保護に関する法律" \
  | python3 -c "import json,sys; \
[print(x['law_info']['law_id'], x['revision_info']['law_title']) \
for x in json.load(sys.stdin)['laws']]"

個人情報の保護に関する法律のIDは415AC0000000057です。法令番号を渡しても履歴は引けますが、漢数字の表記ゆれが入りやすいので、監視リストにはIDを置くのが扱いやすいです。

改正履歴と未施行版の本文を保存するスクリプト

追跡の核は、法令を版(law_revision_id)ごとにテキストで保存し、Gitで差分を取る構成です。履歴IDは「法令ID_施行日_改正法令ID」の形をしているので、同じ改正は同じファイル名になります。新しい改正が公布されれば、新しいファイルが増えます。

監視リストを置きます。

{"law_ids": ["415AC0000000057"]}

取得スクリプトは次のとおりです。標準ライブラリだけで動きます。

#!/usr/bin/env python3
"""監視対象の法令の改正履歴と、現施行・未施行版の本文を保存する。"""
import json, sys, urllib.parse, urllib.request
from pathlib import Path
 
BASE = "https://laws.e-gov.go.jp/api/2"
OUT = Path("snapshots")
 
 
def get(path, **params):
    url = f"{BASE}/{path}?{urllib.parse.urlencode(params)}"
    with urllib.request.urlopen(url, timeout=60) as r:
        return json.load(r)
 
 
def flatten(node, lines):
    """law_full_text(JSON詳細版)を、条ごとのテキストに直す。"""
    if isinstance(node, str):
        return node
    text = "".join(flatten(c, lines) for c in node.get("children", []))
    if node.get("tag") == "Article":
        lines.append(text.replace("。", "。\n").rstrip("\n"))
        return ""
    return text
 
 
def article_lines(revision_id):
    d = get(f"law_data/{revision_id}", law_full_text_format="json")
    lines = []
    flatten(d["law_full_text"], lines)
    return lines
 
 
def main():
    OUT.mkdir(exist_ok=True)
    ids = json.loads(Path("watchlist.json").read_text())["law_ids"]
    for law_id in ids:
        revs = get(f"law_revisions/{law_id}")["revisions"]
        keep = [r for r in revs if r["current_revision_status"]
                in ("CurrentEnforced", "UnEnforced")]
        summary = [{k: r[k] for k in (
            "law_revision_id", "law_title", "current_revision_status",
            "amendment_enforcement_date", "amendment_enforcement_comment",
            "amendment_promulgate_date", "amendment_law_title")}
            for r in keep]
        (OUT / f"{law_id}.revisions.json").write_text(
            json.dumps(summary, ensure_ascii=False, indent=2) + "\n")
        for r in keep:
            lines = article_lines(r["law_revision_id"])
            name = f"{r['law_revision_id']}.txt"
            (OUT / name).write_text("\n".join(lines) + "\n")
 
 
if __name__ == "__main__":
    sys.exit(main())

本文はlaw_full_text_format=jsonで取り、Article要素ごとにテキストへ潰しています。1つの条が長い一行になると差分が読みにくいため、句点で改行を入れました。

実行すると、法令ごとの履歴サマリ(<法令ID>.revisions.json)と、版ごとの本文(<履歴ID>.txt)がsnapshots/に並びます。個人情報の保護に関する法律で試すと、現施行版に加えて未施行の版が複数返りました。

施行日と改正法令名はrevisions.jsonから読む

サマリに残すフィールドは、判断に使うものに絞っています。

フィールド中身
amendment_law_title中身改正した法令の名前
amendment_promulgate_date中身改正法令の公布日
amendment_enforcement_date中身改正法令の施行日
amendment_enforcement_comment中身施行日についての注記
current_revision_status中身現施行か未施行か

実行結果の一例を示します。取得するたびに内容は更新されるので、値は例として読んでください。

{
  "law_revision_id": "415AC0000000057_20280716_508AC0000000056",
  "current_revision_status": "UnEnforced",
  "amendment_enforcement_date": "2028-07-16",
  "amendment_enforcement_comment": "公布の日から起算して二年を超えない範囲内において政令で定める日",
  "amendment_promulgate_date": "2026-07-17",
  "amendment_law_title": "個人情報の保護に関する法律等の一部を改正する法律"
}

注意したいのは、コメントが「政令で定める日」の履歴です。日付欄には値が入っていますが、コメントは施行日がまだ確定していないことを示しています。この例では日付が「公布から二年」の末日に当たり、上限として入っているように見えます。仕様書のスキーマ説明には、この欄の意味を定めた記述がありません。影響メモに書くときは、日付だけを転記せず、コメントを併記して「確定日ではない可能性がある」と明示します。

改正の区分はamendment_typeで分かれます。1が新規、3が被改正、8が廃止です。ある法令が他の法律の改正に伴って書き換わる場合は3になるので、改正法令名を見ると、何の改正に連動した変更かが分かります。

条文差分はGitに任せ、読むのはClaude Codeに任せる

スクリプトの出力は、リポジトリにコミットしておきます。次回の実行で何が変わったかは、git statusとgit diffで出ます。

  • 新しいファイルが増えた: 新しい改正が公布された
  • revisions.jsonの行が変わった: 未施行だった版が施行された、など状態が動いた
  • 既存の.txtが書き換わった: 同じ版の本文データが更新された

未施行の版と現施行版の条文差分は、diffで直接出せます。

diff -u snapshots/415AC0000000057_20261001_507AC0000000070.txt \
        snapshots/415AC0000000057_20261102_508AC0000000062.txt

差分の出力は条番号と行単位です。「どの条の何が変わったか」を人が読める要約にするのが、Claude Codeの仕事になります。方針はCLAUDE.mdに固定しておくと、毎回の指示がぶれません。

## 法改正メモの書き方
 
- 入力は snapshots/ の差分と revisions.json。条文は推測で補わない
- 1改正につき、法令名・改正法令名・公布日・施行日・施行日コメントを書く
- 変わった条番号を挙げ、どう変わったかを1〜2文で述べる
- 施行日コメントに「政令で定める日」とあれば、確定日として扱わない
- 業務への影響や対応の要否は書かない。判断は担当者が行う
- 出力先は memos/YYYY-MM-DD.md。差分が無ければ「変更なし」の1行

最後の「判断は担当者が行う」が要です。法令の解釈や対応要否は、APIデータの差分からは決まりません。メモは「どこが変わったか」の整理にとどめ、読む人が元の条文に戻れるよう、法令ID・履歴IDを必ず載せる構成にします。

毎週回す方法 — /loopは向かない

週次で回す定期実行には、Claude Codeの3つの方法があります。

Routines(クラウド)Desktop/loop
実行場所Routines(クラウド)クラウドDesktop自分のマシン/loop自分のマシン
マシンの電源Routines(クラウド)不要Desktop必要/loop必要
セッションを開いておくRoutines(クラウド)不要Desktop不要/loop必要
最短間隔Routines(クラウド)1時間Desktop1分/loop1分

/loopは週次に向きません。定期タスクは作成から7日で期限切れになり、最後に1回実行されたあと自動で削除されます。週1回の設定だと、動くのは多くても数回です。手順は/loopコマンドの解説にあります。

Desktopのスケジュールタスクは、週次のプリセットがあります。アプリが起動していて、PCが起きているときだけ動く点に注意が要ります。スリープ中に過ぎた回はスキップされ、起動時に直近の取りこぼしが1回だけ補われます。設定はDesktopのスケジュールタスクで扱っています。

スクリプトとsnapshots/をリポジトリに置くなら、Routinesが筋のよい選択です。クラウドの実行は毎回リポジトリのデフォルトブランチを新しくクローンし、変更はclaude/で始まるブランチに積まれます。そのため、次回の比較基準にするには、前回分のブランチをデフォルトブランチへマージしておく必要があります。マージを忘れると、毎回同じ差分が出続けます。詳しい設計はRoutines完全ガイドにあります。

Routinesではネットワーク許可を足す

Routinesのクラウド環境は、既定のネットワーク設定(Trusted)だと許可リストにあるドメインにしか出られません。許可リスト外のホストへのリクエストは、403とx-deny-reason: host_not_allowedで失敗します。laws.e-gov.go.jpを使うには、環境のネットワークアクセスをCustomにして、許可ドメインに加えます。コネクタ経由の通信はこの許可リストの対象外なので、コネクタの設定とは別に考えます。

実行時刻は、ちょうど0分を避けて数分ずらします。Routinesはちょうどの時刻だと数分遅れて始まることがあり、/loop系のジョブも起動のずれ(ジッター)が入ります。

定期実行に渡す指示は短くて足ります。

watchlist.json の法令について law_watch.py を実行し、snapshots/ の
差分を読んで memos/ に今日付けの法改正メモを作る。書き方は CLAUDE.md に従う。

施行が近い改正だけを先に拾う

全差分を読む前に、「施行日が近い未施行の改正」を一覧にしておくと、メモの優先順位がつきます。revisions.jsonを読むだけなので、APIを再度叩く必要はありません。

import json, sys
from datetime import date, timedelta
from pathlib import Path
 
days = int(sys.argv[1]) if len(sys.argv) > 1 else 90
limit = date.today() + timedelta(days=days)
for f in sorted(Path("snapshots").glob("*.revisions.json")):
    for r in json.loads(f.read_text()):
        if r["current_revision_status"] != "UnEnforced":
            continue
        d = date.fromisoformat(r["amendment_enforcement_date"])
        if d <= limit:
            print(d, r["law_title"], "/", r["amendment_law_title"],
                  "/", r["amendment_enforcement_comment"] or "-")

UnEnforcedだけを対象にしているのは、すでに施行された改正を何度も拾わないためです。コメント欄に「政令で定める日」のような記述がある行は、日付が上限の可能性があります。出力にコメントを並べているので、確定日かどうかを目で分けられます。

初回の動作確認

定期実行に載せる前に、手で1回通します。

手順

初回の確認

  1. 1

    監視リストを1法令にして実行する

    watchlist.jsonに法令を1つだけ書き、スクリプトを実行します。snapshots/に履歴サマリと版ごとの.txtが並べば取得は成功です。

  2. 2

    コミットして基準を作る

    初回の出力をそのままコミットします。これが次回の比較基準になります。

  3. 3

    Claude Codeにメモを書かせる

    CLAUDE.mdの方針を置いた状態で、未施行の版どうしの差分を読ませ、memos/に出力させます。メモの条番号が、元の.txtの行と一致するかを自分で突き合わせます。

  4. 4

    定期実行に載せる

    メモの出来を確かめてから、RoutinesかDesktopに登録します。登録後は「今すぐ実行」で1回通し、権限の確認やネットワーク拒否が出ないかを見ます。

メモの突き合わせは省かないほうがよい工程です。要約はClaude Codeが書くので、条番号の取り違えや、差分に無い内容の補足が混ざる可能性があります。CLAUDE.mdで「条文は推測で補わない」と縛っても、人が一度は元データと見比べて確かめます。

取得時に気をつけること

  • JSONの本文は試行版: 法令本文取得APIが返すJSON形式のデータは、仕様書で試行版とされ、仕様変更がありえます。スクリプトが動かなくなったら、law_full_text_format=xmlへの切り替えを検討します
  • 本文が大きいとエラーになる: 仕様書は、データサイズが大きい法令でエラーが出ることがあるとしています。リトライを入れるか、elmパラメータで条を絞って取ります(例はMainProvision-Paragraph[1])
  • 時点を指定した本文: asofに日付を渡すと、その時点で最新の履歴の本文が取れます。履歴IDを指定する場合、asofは無視されます
  • 大量の法令を見るとき: 監視対象が多いなら、XML一括ダウンロードの「最新の更新法令データ」(file_section=3とupdate_date)が使えます。取得できる範囲は過去3か月分です
  • 取得できる法令の範囲: 仕様書の冒頭は、取得可能な範囲をe-Gov法令検索のヘルプで確認するよう案内しています

他の定点観測との違い

法令の追跡は、順位を毎週取る作業と型が同じです。蓄積したデータの差分を読む点は、Search Console APIの定点観測と共通しています。一方、法令データは数字ではなく条文なので、要約の方針をCLAUDE.mdで縛っておかないと、メモに解釈が混ざります。

試験勉強の文脈で法改正を確かめる方法は、Claudeの学習モードによる条文問答で扱っています。業務での追跡は、そちらと違って、条文の出どころが分かる形で残すことが前提になります。

まとめ

e-Gov法令APIは、履歴(/law_revisions)と本文(/law_data)を版ごとに取れるので、法改正の追跡に向いています。版ごとのテキストをGitで蓄積すれば、差分の検出はgit diffで済みます。Claude Codeには、差分を条番号つきの要約にする部分を任せます。

週次の実行では、/loopの7日期限がネックです。リポジトリに結果を置くならRoutines、手元で完結させるならDesktopが候補になります。いずれも、施行日の注記は確定日として扱わず、メモには元の履歴IDを残します。

この記事を共有:XはてブLinkedIn