Claude Media
EDINET APIで有価証券報告書をClaudeに読ませる — 書類一覧からCSV抽出まで

EDINET APIで有価証券報告書をClaudeに読ませる — 書類一覧からCSV抽出まで

EDINET API v2で有価証券報告書を探し、XBRLをCSVで取得してClaude Codeに読ませる手順。APIキー、書類一覧、書類取得、UTF-16LEのCSV、CLAUDE.mdの書き方まで。

有価証券報告書をClaudeに読ませるなら、PDFを貼るより、EDINET APIでXBRLをCSVに変換した形で取るほうが速く正確です。数値は要素IDと期間つきの表になっているので、Claudeは本文を探し回らずに必要な行だけを読めます。

ここでは金融庁のEDINET API仕様書(Version 2)に沿って、書類一覧API、書類取得API、CSVの読み込み、Claude Codeへの渡し方を順に組み立てます。Claudeに渡すAPIキーの扱いはClaude APIキーの取得方法とは別物で、EDINET側で発行するキーです。

手順

全体の流れ

  1. 1

    書類一覧APIで探す

    提出日を指定し、その日の提出書類の一覧を取る。

  2. 2

    対象書類を絞る

    書類種別コードと提出者のEDINETコードで、有価証券報告書の書類管理番号を決める。

  3. 3

    書類取得APIでCSVを落とす

    type=5 でXBRLをCSVに変換したZIPを受け取る。

  4. 4

    必要な項目だけ抜く

    要素IDとコンテキストIDで絞り、小さなファイルにする。

  5. 5

    Claude Codeに読ませる

    抜き出したファイルだけを渡し、根拠の要素IDを添えて答えさせる。

EDINET APIで取れるもの

EDINET APIは2種類あります。提出書類の一覧を返す書類一覧APIと、書類そのものを返す書類取得APIです。一覧には「メタデータのみ」と「提出書類一覧とメタデータ」の2通りがあり、使い方の基本は次の順序です。

  1. メタデータを取り、件数が前回から増えたかを見る
  2. 増えていれば提出書類一覧を取る
  3. 一覧から必要な書類の書類管理番号を読み取る
  4. 書類取得APIで書類を取る

取得できるのは閲覧期間にある書類です。有価証券報告書は縦覧期間5年に延長期間5年が付き、合計10年分が対象になります。四半期報告書は縦覧3年、延長期間7年で、やはり10年です。

延長期間中の書類には注意が要ります。法定縦覧期間を過ぎたあとは行政サービスとして閲覧できる状態なので、提出会社が訂正を出していないことがあります。古い年度の数字を比較に使うときは、訂正の有無を別に確かめます。

APIキーを用意して、Claude Codeから隠す

APIの認証にはEDINET側で発行するAPIキーを使います。アカウントを作成し、APIキー発行画面で発行する流れです。発行したキーは初回のものを継続して使えます。

実行環境の条件も2つあります。

  • 通信はTLS 1.2以上
  • クロスドメイン通信は許可されず、ブラウザ上のJavaScriptからは呼べない

したがってPythonやNodeのサーバー側スクリプトから叩く形になります。Claude Codeに作らせるのもこの形です。

キーは環境変数に置き、コードやCLAUDE.mdには書きません。Claude Codeが .env を読めないようにするには、プロジェクトの .claude/settings.json に拒否ルールを入れます。

{
  "permissions": {
    "deny": ["Read(./.env)"]
  }
}

Read(./.env) はカレントディレクトリの .env の読み取りに一致するルールです。denyは常にallowより先に評価されるので、別の許可ルールでこの拒否を覆すことはできません。

export EDINET_API_KEY="発行したキー"

.env に書く運用にするなら、読み込みはシェル側かスクリプト側で行い、Claudeの会話には出しません。

書類一覧APIで有価証券報告書を探す

エンドポイントは https://api.edinet-fsa.go.jp/api/v2/documents.json です。必須のパラメータは date(YYYY-MM-DD形式)と Subscription-Key で、type=2 を付けると提出書類一覧がメタデータつきで返ります。type を省略すると既定の 1 になり、メタデータだけが返ります。

date は「ファイル日付」で、当日以前かつ、直近の財務局営業日の24時時点で10年を経過していない日付を指定します。土日祝日も指定できます。

つまずきやすいのは、日付が「提出日」とは限らないことです。磁気ディスク提出や紙面提出で提出日が書類提出操作より過去になる場合、その書類は提出操作を行った日のファイル日付の一覧に載ります。提出日で引いても出てきません。

有価証券報告書だけに絞る

一覧の results 配列から、次の項目で絞ります。

項目内容絞り込みでの使い方
docTypeCode内容書類種別コード絞り込みでの使い方120 が有価証券報告書、130 が訂正報告書(有価証券報告書の訂正)
edinetCode内容提出者のEDINETコード(6桁)絞り込みでの使い方企業の特定
periodStart / periodEnd内容期間絞り込みでの使い方有価証券報告書では事業年度
docID内容書類管理番号(8桁)絞り込みでの使い方書類取得APIに渡す
xbrlFlag / csvFlag内容XBRL・CSVの有無絞り込みでの使い方1 なら取得できる
withdrawalStatus内容取下区分絞り込みでの使い方0 以外は取下書か取り下げられた書類

企業の特定は、証券コードの secCode より edinetCode のほうが扱いやすいでしょう。EDINETコードに紐づく提出者の情報は、EDINET閲覧サイトの「EDINETコードリスト」からダウンロードできます。このCSVはカンマ区切りで、文字コードはシフトJISです。

有価証券報告書の訂正は、別の書類として一覧に出ます。最新の確定値が欲しいときは、同じ事業年度の 130 が出ていないかも見ます。

同じ日に何度も取るなら連番を使う

当日の一覧を同じ日に複数回取る場合は、seqNumber(ファイル日付ごとの連番)を使います。連番は一度付与されたら変わりません。前回取得した最後の連番より大きいものだけを処理すれば、取りこぼしも二重処理も防げます。

書類取得APIでCSVを落とす

書類取得APIのエンドポイントは https://api.edinet-fsa.go.jp/api/v2/documents/{書類管理番号} です。type で何を取るかを決めます。

type取得物形式
1取得物提出本文書と監査報告書(XBRLを含む)形式ZIP
2取得物PDF形式PDF
3取得物代替書面・添付文書形式ZIP
4取得物英文ファイル形式ZIP
5取得物CSV形式ZIP

Claudeに読ませる用途なら type=5 が第一候補です。XBRLをCSVに変換したもので、ZIPの中の XBRL_TO_CSV フォルダに提出本文書と監査報告書のCSVが入っています。type=1 のXBRLが取れるのは xbrlFlag が 1 の書類、type=5 のCSVは csvFlag が 1 の書類です。

PDFを経由する方法もあります。Claudeは1ページあたりテキスト分で1,500〜3,000トークン程度を使うので、有価証券報告書のように長い書類を丸ごと渡すとコストがかさみます。数値を取りたいだけなら、CSVを絞って渡すほうがトークンを節約できます。PDFの上限や扱いはClaudeのPDF要約のコツにまとめています。

エラーはHTTPステータスで判定できない

書類取得APIには癖があります。パラメータの誤りなどでエラーになっても、HTTPステータスは 200 で返ります。成功かどうかは、レスポンスヘッダの Content-Type で見ます。

  • ZIPが取れたとき: application/octet-stream
  • PDFが取れたとき: application/pdf
  • 失敗したとき: application/json; charset=utf-8

失敗時の本文はJSONで、401(キーが無効)や 404(リソースなし)、429(大量リクエスト)などの状態が入ります。429 を受けたら間隔を空けて再試行します。

ダウンロードと抽出のスクリプト

次のスクリプトは、指定日の一覧から指定企業の有価証券報告書を探し、CSVのZIPを取得して、経営指標等の行だけをJSON Linesに書き出します。仕様書の項目名に沿って書いた例で、実行する前に自分のAPIキーで1日分を試してください。

import csv, io, json, os, sys, zipfile
import requests
 
BASE = "https://api.edinet-fsa.go.jp/api/v2"
KEY = os.environ["EDINET_API_KEY"]
 
 
def find_reports(date, edinet_code):
    r = requests.get(
        f"{BASE}/documents.json",
        params={"date": date, "type": 2, "Subscription-Key": KEY},
        timeout=30,
    )
    body = r.json()
    if body.get("StatusCode") or body["metadata"]["status"] != "200":
        raise RuntimeError(body)
    return [
        d for d in body["results"]
        if d["docTypeCode"] == "120"
        and d["edinetCode"] == edinet_code
        and d["csvFlag"] == "1"
        and d["withdrawalStatus"] == "0"
    ]
 
 
def fetch_csv_zip(doc_id):
    r = requests.get(
        f"{BASE}/documents/{doc_id}",
        params={"type": 5, "Subscription-Key": KEY},
        timeout=120,
    )
    if "octet-stream" not in r.headers.get("Content-Type", ""):
        raise RuntimeError(r.text[:300])
    return r.content
 
 
def rows_from_zip(content):
    with zipfile.ZipFile(io.BytesIO(content)) as z:
        for name in z.namelist():
            if "XBRL_TO_CSV" in name and name.endswith(".csv"):
                text = z.read(name).decode("utf-16-le").lstrip(chr(0xFEFF))
                yield from csv.DictReader(io.StringIO(text), delimiter="\t")
 
 
if __name__ == "__main__":
    date, edinet_code, out = sys.argv[1:4]
    for doc in find_reports(date, edinet_code):
        rows = rows_from_zip(fetch_csv_zip(doc["docID"]))
        with open(out, "w", encoding="utf-8") as f:
            for row in rows:
                if "SummaryOfBusinessResults" in row["要素ID"]:
                    f.write(json.dumps(row, ensure_ascii=False) + "\n")
python fetch_edinet.py 2026-06-25 E00000 data/edinet/summary.jsonl

E00000 はダミーです。実際のEDINETコードに置き換えます。

CSVの形式で押さえる点

変換されたCSVは、拡張子こそ csv ですが、区切りはカンマではなくタブです。文字コードはUTF-16LEで、改行はCRLF、各項目はダブルクォーテーションで囲まれます。上のスクリプトが decode("utf-16-le") と delimiter="\t" を使っているのはこのためです。UTF-8として開くと文字化けします。

1行目の見出しは次の9項目です。

  1. 要素ID
  2. 項目名
  3. コンテキストID
  4. 相対年度
  5. 連結・個別
  6. 期間・時点
  7. ユニットID
  8. 単位
  9. 値

スクリプトの絞り込み条件 SummaryOfBusinessResults は、売上高の要素 jpcrp_cor:NetSalesSummaryOfBusinessResults の接尾辞から置いた仮定です。経営指標等の要素が同じ接尾辞で揃うかは、最初に要素IDの重複なし一覧を出して確かめます。Claude Codeに「このCSVの要素IDを種類ごとに数えて」と頼めば足ります。

コンテキストIDは、CurrentYearDuration(当期の期間)、CurrentYearInstant(当期末の時点)、Prior1Year系(前期)のような名前で期間を表します。連結財務諸表のコンテキストにはメンバー要素が付かず、個別財務諸表には NonConsolidatedMember が付く仕様です。個別の数値が欲しいなら、コンテキストIDの末尾でも絞ります。ただし個別財務諸表の数値でも、連結・個別の区別を持たない箇所では NonConsolidatedMember が付きません。末尾だけで機械的に落とさず、連結・個別 列と合わせて見ます。

Claude Codeに読ませる

絞ったJSON Linesを渡して質問します。全文のCSVではなく、抜き出したファイルだけを読ませるのがコツです。

CLAUDE.mdには、次のような取り決めを置いておきます。

## EDINET
- APIキーは環境変数 EDINET_API_KEY から読む。値を出力・保存しない
- 取得物は data/edinet/ に置く。ZIPや全文CSVは直接読まず、
  抽出スクリプトの出力(JSON Lines)だけを読む
- 数値を答えるときは、要素ID・コンテキストID・単位を併記する
- 該当する行が無いときは推測で埋めず、「該当行なし」と答える

「単位を併記する」は効きます。CSVの 単位 列には通貨単位が入っていて、円と百万円の取り違えを防げます。

質問の例は次のとおりです。

data/edinet/summary.jsonl は、ある企業の有価証券報告書から抜いた
経営指標等の行です。売上高(NetSales...)の当期と前期を取り出して、
前期比を計算してください。要素ID、コンテキストID、単位を表にし、
個別と連結が混ざっていないか先に確認してください。

返ってきた数字は、必ず原本と1件突き合わせます。書類取得APIで type=2 のPDFを同じ書類管理番号で取り、該当ページと照合すれば足ります。計算はClaudeの暗算に任せず、スクリプトに書かせて実行させるほうが再現できます。

複数年を並べたいときは、書類一覧APIを日付ごとに繰り返すことになります。1日1リクエストの設計なので、期間で探すなら日付のループを回し、間に待ち時間を挟みます。

つまずいたときの切り分け

症状ごとの原因を並べます。

症状原因と対処
401 が返る原因と対処APIキーの誤り、またはパラメータに未指定。キーを再確認する
429 が返る原因と対処短時間にリクエストが集中した。間隔を空けて再試行する
一覧に目的の書類が無い原因と対処ファイル日付が提出日とずれている可能性。前後の日付も引く
CSVが文字化けする原因と対処UTF-16LE・タブ区切り。文字コードと区切りを指定して読む
ZIPのはずが中身がJSON原因と対処失敗レスポンス。Content-Type を先に判定する
訂正前の数字を拾った原因と対処同じ事業年度の訂正(130)が出ていないか確認する

APIは予告なく停止や性能低下が起きることがあり、仕様の変更も事前の通知なしに行われます。ブラウザ上のページをスクレイピングで取得する行為は利用規約で禁止され、機械的に取得するにはAPIを使うことが求められます。

取得した内容を公開するときの出典表記

EDINETのコンテンツはPDL1.0(公共データ利用規約)に沿って利用できます。利用するときは出典を記載します。編集・加工して使う場合は、出典とは別に、加工したことと加工した主体も書きます。国が作成した未加工の情報であるかのような態様での公表はできません。

Claudeに要約させた数値を社内資料や記事に載せるなら、この表記を忘れないことです。EDINETタクソノミは、この利用規約の適用外とされています。

まとめ

EDINET APIは、一覧で探して、書類管理番号で取る二段構えです。有価証券報告書をClaudeに読ませる経路としては、PDFよりCSV(type=5)のほうが数値を行単位で扱えます。CSVはUTF-16LEのタブ区切りで、エラーはHTTPステータスでなく Content-Type で判定します。全文を渡さず、要素IDで絞った小さなファイルだけを読ませ、数値は原本と1件照合する。この3点を守れば、Claude Codeでの財務データの取り込みは安定します。

契約書のように提出元がAPIを持たない長文は、別の組み立てになります。Claudeで法務文書を要約するAPI実装を参照してください。

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