見出し画像

【保存版】Pythonでe-Govの法令を引っこ抜いてNotebookLMに食わせたら、最強のリサーチアシスタントが爆誕した話

こんにちは。最近 NotebookLM にハマっているんですが、これ、ただPDFを読み込ませるだけじゃもったいないことに気づきました。

特に「条文」のような構造化されたデータと相性が抜群なんです。

でも、e-Gov(イーガブ)のサイトを見ながらコピペするのは苦行ですよね? そこで今回は、Pythonを使ってe-Gov法令検索APIから必要な条文を自動取得し、整形してNotebookLMに突っ込む方法をシェアします。

これができると、「特定の法律に特化した、嘘をつかないAIアドバイザー」が一瞬で作れるようになります。私は税理士ですが、ガチで弁護士、司法書士、行政書士のプロの方でも活用していただけると思います!


なぜやるのか?(メリット)


高精度な回答: 一般的なChatGPTなどは法律の条数を間違えたりしますが、NotebookLMはソース(条文)に基づいて回答するため、ハルシネーション(嘘)が激減します。

  1. 最新情報の反映: 施行日を指定してデータを取得すれば、改正民法などにも対応可能。

  2. 複数法令の横断検索: 「民法」と「借地借家法」を両方入れて、「このケースではどっちが優先される?」といった質問ができます。


使うもの

  • Python: データ取得と整形用

  • e-Gov 法令API: 国が提供している無料の神API

  • NotebookLM: GoogleのRAG(検索拡張生成)ツール


手順1:e-Gov 法令APIを理解する

実はe-Govには、公式のAPIがあります。登録不要で叩ける素晴らしい仕様です。 ただ、戻り値が XML形式 なので、人間が読むには辛い。そこでPythonの出番です。

参考:e-Gov法令API仕様書


手順2:Pythonで条文を引っこ抜く

今回は例として**「著作権法」**を取得し、NotebookLMが読みやすい Markdown形式 に整形するスクリプトを書きました。

JSONでも良いのですが、NotebookLMはMarkdownのヘッダー構造(# や ##)を文脈として理解するのが得意なので、Markdown推奨です。

サンプルコード(テスト済み※不備があったのでアップデートしました)

Python

import requests
import xml.etree.ElementTree as ET

# 取得したい法令名
LAW_NAME = "著作権法" 

def fetch_law_data(law_name):
    # 1. 法令リストからLawIdを検索
    print(f"[{law_name}] を検索中...")
    list_url = "https://elaws.e-gov.go.jp/api/1/lawlists/1"
    response = requests.get(list_url)
    root = ET.fromstring(response.content)
    
    law_id = None
    for law in root.findall(".//LawNameListInfo"):
        if law.find("LawName").text == law_name:
            law_id = law.find("LawId").text
            break
            
    if not law_id:
        print(f"Error: {law_name} が見つかりませんでした。")
        return None

    # 2. 条文データを取得
    print(f"条文データをダウンロード中... (ID: {law_id})")
    detail_url = f"https://elaws.e-gov.go.jp/api/1/lawdata/{law_id}"
    law_response = requests.get(detail_url)
    return law_response.content

def parse_to_markdown(xml_content):
    print("Markdownに変換中...")
    root = ET.fromstring(xml_content)
    markdown_text = f"# {LAW_NAME}\n\n"
    
    # 条文(Article)の取得
    articles = root.findall(".//Article")
    
    for article in articles:
        # 条数
        article_caption = article.find("ArticleCaption")
        caption_text = article_caption.text if article_caption is not None else ""
        
        # 見出し
        article_title = article.find("ArticleTitle")
        title_text = article_title.text if article_title is not None else ""
        
        markdown_text += f"## {title_text} {caption_text}\n"
        
        # 項(Paragraph)の取得
        paragraphs = article.findall(".//Paragraph")
        for p in paragraphs:
            p_num = p.find("ParagraphNum")
            p_sent = p.find(".//Sentence") # 項の本文
            
            num_text = p_num.text if p_num is not None else ""
            sent_text = p_sent.text if p_sent is not None and p_sent.text else ""
            
            markdown_text += f"- **{num_text}**: {sent_text}\n"
            
            # --- 【修正点】号(Item)の取得 ---
            items = p.findall("Item")
            for item in items:
                i_title = item.find("ItemTitle") # 号名(例:一)
                i_sent = item.find(".//Sentence") # 号の本文
                
                it_text = i_title.text if i_title is not None else ""
                is_text = i_sent.text if i_sent is not None else ""
                
                # インデントを下げてリスト表示
                markdown_text += f"    - **{it_text}**: {is_text}\n"

                # さらにその下(イロハ等:Subitem1)がある場合
                subitems1 = item.findall("Subitem1")
                for sub1 in subitems1:
                    s1_title = sub1.find("Subitem1Title")
                    s1_sent = sub1.find(".//Sentence")
                    
                    s1_t_text = s1_title.text if s1_title is not None else ""
                    s1_s_text = s1_sent.text if s1_sent is not None else ""
                    
                    markdown_text += f"        - **{s1_t_text}**: {s1_s_text}\n"

        markdown_text += "\n"
        
    return markdown_text

# 実行
xml_data = fetch_law_data(LAW_NAME)
if xml_data:
    md_output = parse_to_markdown(xml_data)
    
    filename = f"{LAW_NAME}_full.md"
    with open(filename, "w", encoding="utf-8") as f:
        f.write(md_output)
    print(f"完了!ファイルを保存しました: {filename}")

これだけで、手元に 著作権法.md というきれいなファイルが生成されます。


手順3:NotebookLMに投入

  1. NotebookLM (https://notebooklm.google.com/) を開く。

  2. 「新しいノートブック」を作成。

  3. 「ソースを追加」から、先ほど作成したMarkdownファイルをアップロード。

これだけです。処理は数秒で終わります。


手順4:最強のアシスタントを試す

さあ、質問してみましょう。

質問例:

「引用」の要件について、条文に基づいてリストアップしてください。

NotebookLMの回答(実物):

「引用」の要件について、著作権法の条文に基づいてリストアップします。
著作権法第32条第1項には、著作物の引用に関する主要な規定が置かれています。

著作権法に基づく「引用」の要件
1. 公表された著作物であること
◦ 引用して利用できる著作物は、公表された著作物に限られます。
条文上、引用の要件として具体的に明記されているのは上記の点のみですが、著作権法には引用の際に順守すべき出所の明示に関する規定が別に存在します。
引用に伴う出所の明示義務
著作権法第48条第1項第1号により、第三十二条の規定により著作物を複製または利用する場合には、著作物の出所を明示しなければなりません。
1. 出所明示の方法と程度
◦ 著作物の出所を、その複製又は利用の態様に応じ合理的と認められる方法及び程度により、明示しなければならないとされています。
2. 著作者名の明示
◦ 出所の明示に当たっては、これに伴い著作者名が明らかになる場合及び当該著作物が無名のものである場合を除き、当該著作物につき表示されている著作者名を示さなければならないとされています。
補足
「引用」の規定は、著作者人格権に影響を及ぼすものと解釈してはならないとされています(著作権法第50条)。これは、引用が認められる場合であっても、著作者の同一性保持権(第20条)などの人格権を侵害しないよう配慮する必要があることを示唆しています。

NotebookLMから出力したリアルな回答

ソース番号のチップをクリックすると、該当する条文箇所(Markdownの該当行)へジャンプします。これがめちゃくちゃ便利。PDFだとレイアウト崩れで読みづらい箇所も、Markdownなら完璧に構造化されています。



応用編:JSONで構造化して使う場合


もし、アプリに組み込むなどでもっと厳密に扱いたい場合は、JSON形式で保存するのも手です。

Python

# JSONとして保存するイメージ
law_dict = {
    "law_name": "著作権法",
    "articles": [
        {"id": "1", "title": "目的", "text": "この法律は..."},
        {"id": "2", "title": "定義", "text": "この法律において..."},
    ]
}

こうしておけば、特定の条文だけをフィルタリングしてNotebookLMに渡したり、「第〇条に関連する判例」を別のAPIから取ってきて結合したりといった拡張が可能になります。



まとめ


「e-Gov API × Python × NotebookLM」 は、現時点で個人的に最強のリーガルテック活用法の一つです。

  • 無料

  • 正確(一次情報ベース)

  • 高速

特に、業務で頻繁に参照する法律を全部Markdown化してノートブックに入れておくと、検索時間が劇的に短縮されます。

この記事が沢山読まれるようでしたら、より実践的な応用編も書きたいと考えてます。

ぜひ、週末のPythonプロジェクトとして試してみてください!

🎅最後まで読んでくれた人のために、今回作成したmdデータをサンプルとして置いておきますね。🎄✨

ではでは


いいなと思ったら応援しよう!