Claude Media
国会会議録APIとClaudeで国会審議を発言者別に要約・比較する

国会会議録APIとClaudeで国会審議を発言者別に要約・比較する

国立国会図書館の国会会議録検索APIで法案審議の発言を集め、会派・答弁者ごとに整理してClaudeに要約・比較させる手順。取得スクリプト、発言の癖、出典URLの検証、利用条件までを実例で示します。

国会会議録検索システムのAPIは、登録手続きなしで使えます。「発言」を条件に検索して本文をJSONで取れるので、法案ごとの審議を集めてClaudeに渡すところまでが短い距離でつながります。

ここでは、内閣委員会の審議から「サイバー対処」に触れた発言を集め、会派と答弁者ごとに束ね、論点の要約と比較をClaudeにさせる流れを組みます。取得用のPythonは標準ライブラリだけで動きます。

国会会議録検索APIは3種類ある

国会会議録検索APIは、国会会議録検索システムに登録されたデータを検索して取得するための、国立国会図書館が提供する外部インターフェースです。ウェブサイトの検索と同等の検索・返戻ができ、HTTPのGETで送るとXMLかJSONが返ります。

出力の単位で3つのエンドポイントに分かれ、検索条件の指定方法は共通です。

エンドポイント返るもの1回の最大件数
meeting_list返るもの会議の情報のみ。本文なし1回の最大件数100件
meeting返るもの会議の情報と全発言の本文1回の最大件数10件
speech返るものヒットした発言の本文と会議の情報1回の最大件数100件

要約用途で使いやすいのは speech です。ヒットした発言だけが本文付きで返るので、「サイバー対処」を含む発言だけを拾えます。meeting は会議の全発言が付いてくる分、1回で10会議までしか取れず、1会議が長いと不要な発言も多く含まれます。

meeting_list は本文が付かないので、まず件数と会議の一覧を確かめる下見に向いています。結果の並びは会議開催日の新しい順です。

curl -s "https://kokkai.ndl.go.jp/api/speech?\
any=%E3%82%B5%E3%82%A4%E3%83%90%E3%83%BC%E5%AF%BE%E5%87%A6\
&nameOfMeeting=%E5%86%85%E9%96%A3%E5%A7%94%E5%93%A1%E4%BC%9A\
&from=2025-01-01&maximumRecords=3&recordPacking=json"

日本語の検索語はUTF-8でURLエンコードします。検索条件の部分は全体で2000バイトが上限なので、会派名や会議名をたくさん並べる使い方には向きません。

検索パラメータは「発言の絞り込み」に使う

法案審議の論点を集める目的なら、使うパラメータはほぼ次の5つに絞れます。

パラメータ役割複数語を空白で区切ると
any役割発言内容に含まれる語。部分一致複数語を空白で区切るとAND検索
nameOfMeeting役割会議名(本会議・委員会)。部分一致複数語を空白で区切るとOR検索
speaker役割発言者名。議員名はひらがな可複数語を空白で区切るとOR検索
from / until役割会議開催日の始点・終点(YYYY-MM-DD)複数語を空白で区切ると同じ日を入れると特定日
sessionFrom / sessionTo役割国会回次の範囲複数語を空白で区切ると片方だけなら当該回次のみ

any がAND、nameOfMeeting と speaker がORになる点は、そろえて覚えておくと混乱しません。「サイバー 対処」と空白で区切れば両方を含む発言、「内閣委員会 総務委員会」と区切れば両方の委員会が対象です。

このほかに、会派で絞る speakerGroup、肩書きで絞る speakerPosition、「証人」「参考人」「公述人」から選ぶ speakerRole もあります。参考人質疑だけを集めて比べたいときは speakerRole=参考人 が使えます。

院名・会議名・検索語・発言者名・開会日付・国会回次・号数などの条件がいずれも無いリクエストは、エラーになります。

返ってくる発言データの癖

JSONの speech 出力には、発言本文のほかに発言者名、よみ、所属会派、肩書き、役割、発言番号、発言URL、会議録URLが入ります。出典を示す要約には、speechURL がそのまま使えます。

実際に叩くと、仕様の表だけでは気づきにくい点が3つ見つかります。次の観察は、2026年10月に nameOfMeeting=内閣委員会 と any=サイバー対処 で検索した応答に基づきます。院は指定していないので、衆議院と参議院の内閣委員会が両方入ります。

1つ目は、発言番号0の「会議録情報」です。検索語や会議名だけで絞った応答の先頭に、発言者名が「会議録情報」で、本文が出席委員の一覧になっている発言が混ざることがあります。審議の中身ではないので、要約に回す前に speechOrder が0のものを除きます。

2つ目は、会派と肩書きの欠け方です。議員の発言は speakerGroup に会派名が入り、speakerPosition はnullでした。政府参考人の発言は逆に、speakerGroup がnullで speakerPosition に内閣官房の審議官を示す肩書きが入っていました。会派だけで束ねると、政府側の答弁がまとめて落ちます。

3つ目は、発言の長さの幅です。本文は数百字の短い答弁から、数千字の趣旨説明まで幅があります。後で述べるとおり、束ねた全文を一度に渡すのは避けたほうが扱いやすくなります。

ここで書いたのは1つの検索条件での観察で、他の委員会や年代で同じ欠け方になるとは限りません。自分の条件で数件を目で見てから、整形の規則を決めてください。

取得スクリプトで発言をJSONLに保存する

startRecord で位置を送り、応答の nextRecordPosition が返らなくなるまで続けるのが基本形です。最大件数を超える指定や、条件の誤りはエラーメッセージ付きのJSONで返るので、message キーの有無で判定できます。

import json, sys, time, urllib.parse, urllib.request
 
BASE = "https://kokkai.ndl.go.jp/api/speech"
 
 
def fetch(params, limit=300):
    params = {**params, "maximumRecords": 100, "recordPacking": "json"}
    start, out = 1, []
    while start and len(out) < limit:
        q = urllib.parse.urlencode({**params, "startRecord": start})
        with urllib.request.urlopen(f"{BASE}?{q}", timeout=30) as r:
            data = json.load(r)
        if "message" in data:
            sys.exit(f"API error: {data['message']} {data.get('details')}")
        out += data.get("speechRecord", [])
        start = data.get("nextRecordPosition")
        time.sleep(5)  # 次のリクエストまで数秒空ける
    return out[:limit]
 
 
if __name__ == "__main__":
    rows = fetch({
        "any": "サイバー対処",
        "nameOfMeeting": "内閣委員会",
        "from": "2025-01-01",
    })
    rows = [r for r in rows if r["speechOrder"] > 0]  # 会議録情報を除く
    with open("speeches.jsonl", "w", encoding="utf-8") as f:
        for r in rows:
            f.write(json.dumps(r, ensure_ascii=False) + "\n")
    print(len(rows), "speeches")

time.sleep(5) は飾りではありません。国立国会図書館は、機械的なアクセスで多重リクエストを避け、データを取得し終えてから数秒空けて次を送るよう求めています。短時間の大量アクセスは、予告なくアクセスを遮断される場合があります。

上の条件で実行したところ、2025年1月以降の衆参の内閣委員会で、衆議院82件・参議院70件の計152件の発言が返り、会議録情報を除いても152件のままでした。ヒット件数は応答の numberOfRecords で先に分かるので、数千件になりそうなときは limit を小さく始めて、条件を絞り直してから全件を取ります。

発言者別に束ねてからClaudeへ渡す

取得した発言は、束ねてから渡すほうが比較しやすくなります。時系列のままだと「誰が何を主張したか」を読み取らせることになり、会派間の比較が曖昧になります。先にスクリプトで束ね、1つの発言に日付・会議名・発言者・URLを付けて渡します。

import json, collections
 
rows = [json.loads(l) for l in open("speeches.jsonl", encoding="utf-8")]
 
 
def label(r):
    # 議員は会派、政府側は肩書きで束ねる(会派が null の発言がある)
    return r["speakerGroup"] or r["speakerPosition"] or "所属不明"
 
 
groups = collections.defaultdict(list)
for r in rows:
    groups[label(r)].append(r)
 
with open("by_speaker.md", "w", encoding="utf-8") as f:
    for name, items in sorted(groups.items(), key=lambda x: -len(x[1])):
        f.write(f"\n# {name}({len(items)}発言)\n")
        for r in sorted(items, key=lambda r: (r["date"], r["speechOrder"])):
            body = " ".join(r["speech"].split())[:1500]
            f.write(f"\n## {r['date']} {r['nameOfMeeting']}{r['issue']} ")
            f.write(f"{r['speaker']}\nURL: {r['speechURL']}\n{body}\n")

先ほどの152発言(両院分)を束ねると24の見出しになり、最も多いのは自由民主党・無所属の会の66発言、次が内閣官房の審議官の28発言でした。「会派」と「政府答弁者」を別の見出しに分けておくと、質問側の論点と答弁側の説明を対比させやすくなります。

本文は1発言1,500字で切っています。長い趣旨説明の後半を落とす割り切りで、結論部分を取りこぼす可能性はあります。切り詰めたくない場合は、長い発言だけ別ファイルに回して個別に要約させます。

Claude Codeに要約と比較をさせる

Claude Codeは標準入力で受け取ったテキストを処理でき、-p を付けると非対話で動きます。公式の例は git log --oneline -20 | claude -p "summarize these recent commits" で、同じ形でファイルの中身を渡せます。

cat by_speaker.md | claude -p "$(cat prompt.txt)" > summary.md

prompt.txt に書く指示は、出力の構造と出典の扱いを固定するのが肝です。

入力は国会の内閣委員会での発言を、会派・答弁者ごとにまとめたものです。
次の形式で、入力に書かれていることだけを使って整理してください。
 
1. 見出しごとに、主張・質問の論点を3点以内で書く
2. 各論点の末尾に、根拠にした発言のURLを必ず付ける
3. 会派間で論点が分かれた点を表にする(列は論点・会派A・会派B)
4. 入力に無い事実、法案の評価、賛否の推奨は書かない
5. 発言が少なく論点を言えない見出しは「発言が少ない」と書く

4番目と5番目の制約が、国会審議の要約では効きます。発言が少ない見出しでも埋めようとして、一般論を足してしまう挙動を抑えられるからです。

出力を検証する仕組みを持たせる

Claude Codeの公式ベストプラクティスには「Claudeに自分の作業を検証する手段を与える」という節があります。要約でも同じで、確認の方法を最初から決めておくと崩れにくくなります。

出力された要約に付いたURLは、入力にあったURLの集合と突き合わせます。

import re
 
src = open("by_speaker.md", encoding="utf-8").read()
out = open("summary.md", encoding="utf-8").read()
pat = r"https://kokkai\.ndl\.go\.jp/txt/\S+?(?=[)\s」、。]|$)"
known, cited = set(re.findall(pat, src)), set(re.findall(pat, out))
print("入力に無いURL:", sorted(cited - known))

「入力に無いURL」が1件でも出れば、そこはClaudeが作った出典です。該当の論点ごと破棄します。逆に、全URLが入力と一致しても、中身が正しく要約されている保証にはなりません。URLの先の発言を、重要な論点だけでも自分の目で読んでください。

APIで組むなら引用機能を使う

Claude APIでパイプラインにする場合は、Citations機能が使えます。通常のテキストは文単位に自動分割され、文字位置で引用が返ります。議事録や文字起こしのように細かい単位を保ちたい文書には、custom contentを使います。

custom contentではブロックが分割されずそのまま渡されるため、1発言を1ブロックにしておけば「どの発言を根拠にしたか」がブロック番号で返ります。引用された本文(cited_text)は出力トークンに数えられません。法務文書での引用の使い方はClaudeで法務文書を要約するAPI実装にあります。

長くなる審議は段階に分ける

先ほどの152発言を1発言1,500字で切って束ねただけでも、約9万字になりました。会期をまたいで複数の法案を扱えば、1回の入力に収まらなくなります。

分け方は2段階が基本です。

手順

審議を段階に分けて要約する

  1. 1

    見出しごとに要約

    会派・答弁者ごとのブロックを個別に claude -p へ渡し、論点とURLを抽出します。

  2. 2

    要約同士を比較

    1段階目の出力だけを束ね、会派間の対立点と合意点を表にします。原文は渡さず、URLで辿れる状態を保ちます。

  3. 3

    URLを突き合わせる

    最終の表に出てくるURLが1段階目の出力に含まれているか、先ほどのスクリプトで確かめます。

APIで会話が長くなる場合の考え方はClaude APIのオンデマンドcompactionで扱っています。会議の発言を要約させるプロンプトの型はClaude議事録の実践プロンプトが参考になります。

手順書をCLAUDE.mdに残す

繰り返し使うなら、取得と検証の決まりをプロジェクトの CLAUDE.md に置きます。公式は、CLAUDE.mdは短く保ち、書くのは「消したらClaudeが間違える行」だけにするよう勧めています。

# 国会審議の要約
- 取得は fetch_speeches.py を使う。リクエスト間は5秒空ける
- speechOrder が0の「会議録情報」は要約に含めない
- 議員は speakerGroup、政府側は speakerPosition で束ねる
- 要約の各論点には speechURL を付け、verify_urls.py で突き合わせる
- 入力に無い事実、法案の賛否評価は書かない

利用条件と著作権で気をつけること

APIの利用に手続きは要りませんが、利用条件は国立国会図書館のウェブサイトのコンテンツ利用規約に従います。データベース自体と、同館の職員の発言の著作権は同館に帰属します。それ以外の発言の著作権は発言者個人にあります。

その利用には原則として許諾が必要です。ただし、保護期間が満了した発言者の場合や、私的使用のための複製、引用、報道、電子計算機による情報解析といった著作権法の権利制限規定が当てはまる場合は、許諾なしで使えます。許諾が要るかどうかの判断は、利用者が自分で行うことになっています。

つまり、手元で分析して要約を読む使い方と、要約や原文を転載して公開する使い方では、確認すべき範囲が変わります。公開する記事や社内資料に発言を引くときは、引用の要件を満たしているかを確かめてください。

つまずきやすい点

エラーコード19007が返る

検索語、会議名、発言者名などを1つも指定していないときの応答です。maximumRecords だけでは検索条件になりません。

maximumRecords でエラーになる

speech と meeting_list は1〜100、meeting は1〜10までです。101を指定すると、1〜100の値を指定するよう求めるエラーが返りました。

期待した発言が出ない

any を複数語にするとAND検索になり、絞り込みが強すぎる可能性があります。語を1つに減らして件数を見てください。nameOfMeeting は部分一致なので、「委員会」だけでは全委員会が対象になります。

政府側答弁がまとめから落ちる

会派で束ねると speakerGroup がnullの発言が一括りになります。肩書きで補う処理を入れます。

同じ内容を数回聞いて結果が変わる

要約は毎回同じ文面になるとは限りません。比較に使う数値や日付は、要約ではなく取得したデータから直接集計するのが安全です。

まとめ

国会会議録APIは、発言単位の出力に会派・肩書き・URLが付いて返るため、Claudeに渡す前の整理が主な仕事になります。束ね方を会派と政府答弁者に分け、出典URLを検証する工程を最後に置けば、法案審議の論点整理を再現できる形で回せます。

要約はあくまで読み始めの地図です。発言の評価や賛否の判断は、URLの先の原文を読んだうえで、読む人が行う部分として残してください。

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