【第4章】EDINETから5年分のXBRL有価証券報告書を自動取得し、JSONファイルに保存する方法

EDINETから5年分のXBRL有価証券報告書を自動取得し、JSONファイルに保存する方法を示したタイトル画像【第4章】 投資

これまでのシリーズでは、EDINET APIを利用してXBRLファイルを取得し、そのファイルを辞書化してJSON形式で保存する方法について解説してきました。今回は、その延長線上で、過去5年間の有価証券報告書を自動で取得し、XBRLデータを解析して辞書形式に変換し、JSONファイルとして保存するコードを解説します。

この記事は以下のシリーズに続く内容です。

  1. 第1章:EDINET APIからXBRLファイルを取得する基本的な方法
  2. 第2章:XBRLファイルを辞書化し、JSONファイルとして保存する方法
  3. 第3章:過去5年間の有価証券報告書をEDINET APIから取得するためのPythonコードの解説

今回は、これらの記事で紹介した知識を組み合わせて、より高度なデータ処理を行う方法を紹介します。

プロジェクトの目的

今回のプロジェクトでは、特定の企業に関する過去5年間の有価証券報告書をEDINET APIから自動で取得し、それらのXBRLファイルを解析してJSON形式に変換し、保存することを目指してきました。この方法は、長期間の財務データを効率的に収集し、投資分析や経済的な洞察を得るための重要なステップになります。

最終的なソリューションコード

完成形のコード全体は以下のようになります。

import requests
import zipfile
import os
import io
from dotenv import load_dotenv
from datetime import datetime, timedelta
from lxml import etree
import json
# 環境変数の読み込み
load_dotenv()
# APIキーを環境変数から取得
api_key = os.getenv("API_KEY")
# xbrl_filesフォルダが存在しない場合は作成
os.makedirs("./xbrl_files", exist_ok=True)
# XBRLファイルをダウンロードする関数
def download_xbrl_file(doc_id):
    download_url = f"https://api.edinet-fsa.go.jp/api/v2/documents/{doc_id}"
    params = {"type": 1, "Subscription-Key": api_key}
    download_response = requests.get(download_url, params=params)
    if download_response.status_code == 200:
        zip_file_path = f"./xbrl_files/{doc_id}.zip"
        with open(zip_file_path, "wb") as f:
            f.write(download_response.content)
        print(f"XBRLファイルを保存しました: {zip_file_path}")
        return zip_file_path
    else:
        print(f"XBRLファイルのダウンロードに失敗しました: {doc_id}")
        return None
# XBRLファイルをZIPから抽出する関数
def extract_xbrl(zip_file_path):
    with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
        xbrl_files = [f for f in zip_ref.namelist() if f.endswith('.xbrl')]
        if xbrl_files:
            return zip_ref.read(xbrl_files[0])  # 最初のXBRLファイルを返す
    return None
# XBRLファイル内のタグに対応する数値と属性を取得する関数
def get_values_and_attributes_from_xbrl(root):
    tag_to_value_and_attrs = {}
    for element in root.iter():
        ns_prefix = element.prefix
        ns_tag = etree.QName(element).localname
        full_tag = f"{ns_prefix}:{ns_tag}" if ns_prefix else ns_tag
        value = element.text.strip() if element.text else None
        attributes = {attr: val for attr, val in element.attrib.items()} if element.attrib else None
        tag_to_value_and_attrs[full_tag] = {
            "value": value,
            "attributes": attributes
        }
    return tag_to_value_and_attrs
# 辞書をJSON形式に変換して保存
def save_to_json(data, year, doc_id):
    # jsonファイルをxbrl_filesフォルダに保存
    file_name = f"./xbrl_files/xbrl_data_{year}_{doc_id}.json"
    with open(file_name, 'w', encoding='utf-8') as json_file:
        json.dump(data, json_file, ensure_ascii=False, indent=4)
    print(f"JSONファイルを保存しました: {file_name}")
# 過去5年間の有価証券報告書を取得する関数
def get_reports_for_past_5_years(edinet_code):
    current_year = datetime.now().year
    for year in range(current_year - 5, current_year + 1):
        print(f"年: {year} のデータを取得しています。")
        period_start = datetime(year, 1, 1)
        period_end = datetime(year, 12, 31)
        current_date = period_start
        while current_date <= period_end:
            url = "https://disclosure.edinet-fsa.go.jp/api/v2/documents.json"
            params = {'date': current_date.strftime('%Y-%m-%d'), 'type': 2, "Subscription-Key": api_key}
            response = requests.get(url, params=params)
            if response.status_code == 200:
                data = response.json()
                for doc in data.get('results', []):
                    if doc['edinetCode'] == edinet_code and doc['docTypeCode'] == '120':
                        doc_id = doc['docID']
                        print(f"ドキュメントID: {doc_id}, 提出日: {doc['submitDateTime']}")
                        # XBRLファイルをダウンロード
                        zip_file_path = download_xbrl_file(doc_id)
                        if zip_file_path:
                            # ZIPからXBRLファイルを抽出
                            xbrl_content = extract_xbrl(zip_file_path)
                            if xbrl_content:
                                # XBRLファイルのルート要素を解析
                                root = etree.fromstring(xbrl_content)
                                # タグと値、属性を取得
                                tag_to_value_and_attrs = get_values_and_attributes_from_xbrl(root)
                                # JSONファイルに保存(ファイル名に決算年度とdocIDを組み合わせる)
                                save_to_json(tag_to_value_and_attrs, year, doc_id)
            else:
                print(f"{current_date.strftime('%Y-%m-%d')} のデータ取得に失敗しました。")
            current_date += timedelta(days=1)
# EDINETコードを指定して過去5年間の有価証券報告書を取得
edinet_code = "E02529"
get_reports_for_past_5_years(edinet_code)

XBRLデータをJSONファイルに保存するためのステップ

それでは、今回のコードの各ステップを見ていきましょう。

1.必要なモジュールとAPIキーの読み込み

前回の記事同様、APIキーを.envファイルから読み込みます。これにより、EDINET APIへのアクセスが可能となります。

from dotenv import load_dotenv
import io
import os
import requests
from lxml import etree
import zipfile
from datetime import datetime, timedelta
import json

load_dotenv()
api_key = os.getenv("API_KEY")

2.XBRLファイルのダウンロード

特定の企業の書類管理番号(docID)に基づき、XBRLファイルをダウンロードします。第1章でも触れたように、EDINET APIを使用してZIP形式のXBRLファイルを取得し、それをxbrl_filesフォルダに保存します。

def download_xbrl_file(doc_id):
    download_url = f"https://api.edinet-fsa.go.jp/api/v2/documents/{doc_id}"
    params = {"type": 1, "Subscription-Key": api_key}
    download_response = requests.get(download_url, params=params)
    
    if download_response.status_code == 200:
        zip_file_path = f"./xbrl_files/{doc_id}.zip"
        with open(zip_file_path, "wb") as f:
            f.write(download_response.content)
        print(f"XBRLファイルを保存しました: {zip_file_path}")
        return zip_file_path
    else:
        print(f"XBRLファイルのダウンロードに失敗しました: {doc_id}")
        return None

3.ZIPファイルからXBRLファイルを抽出

ダウンロードしたZIPファイルからXBRLファイルを抽出します。この部分は第2章でも触れた内容ですが、ZIPファイル内のXBRLファイルを探し、それを抽出してメモリ上で処理します。

def extract_xbrl(zip_file_path):
    with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
        xbrl_files = [f for f in zip_ref.namelist() if f.endswith('.xbrl')]
        if xbrl_files:
            return zip_ref.read(xbrl_files[0])
    return None

4.XBRLファイルの解析と辞書化

ここでは、XBRLデータを解析し、各要素の名前空間プレフィックスと要素名のペアをキーとして、値と属性を辞書に格納します。この手法は、第2章で説明した「XBRLファイルを辞書形式に変換」で使用しました。

def get_values_and_attributes_from_xbrl(root):
    tag_to_value_and_attrs = {}
    for element in root.iter():
        ns_prefix = element.prefix
        ns_tag = etree.QName(element).localname
        full_tag = f"{ns_prefix}:{ns_tag}" if ns_prefix else ns_tag
        value = element.text.strip() if element.text else None
        attributes = {attr: val for attr, val in element.attrib.items()} if element.attrib else None
        tag_to_value_and_attrs[full_tag] = {
            "value": value,
            "attributes": attributes
        }
    return tag_to_value_and_attrs

5.JSONファイルとして保存

辞書化したXBRLデータをJSON形式で保存します。ファイル名には有価証券報告書を提出した年とdocIDを含め、データ管理をしやすくしています。

def save_to_json(data, year, doc_id):
    file_name = f"./xbrl_files/xbrl_data_{year}_{doc_id}.json"
    with open(file_name, 'w', encoding='utf-8') as json_file:
        json.dump(data, json_file, ensure_ascii=False, indent=4)
    print(f"JSONファイルを保存しました: {file_name}")

6.過去5年間の有価証券報告書を取得

このコードの核となる部分です。特定のEDINETコードに基づいて、過去5年間の有価証券報告書(docTypeCodeが120)を取得します。日付ごとに検索し、報告書が見つかった場合にXBRLファイルをダウンロードし、解析、JSON形式で保存します。

def get_reports_for_past_5_years(edinet_code):
    current_year = datetime.now().year
    for year in range(current_year - 5, current_year + 1):
        print(f"年: {year} のデータを取得しています。")
        period_start = datetime(year, 1, 1)
        period_end = datetime(year, 12, 31)
        current_date = period_start
        
        while current_date <= period_end:
            url = "https://disclosure.edinet-fsa.go.jp/api/v2/documents.json"
            params = {'date': current_date.strftime('%Y-%m-%d'), 'type': 2, "Subscription-Key": api_key}
            response = requests.get(url, params=params)
            
            if response.status_code == 200:
                data = response.json()
                for doc in data.get('results', []):
                    if doc['edinetCode'] == edinet_code and doc['docTypeCode'] == '120':
                        doc_id = doc['docID']
                        print(f"ドキュメントID: {doc_id}, 提出日: {doc['submitDateTime']}")
                        
                        zip_file_path = download_xbrl_file(doc_id)
                        
                        if zip_file_path:
                            xbrl_content = extract_xbrl(zip_file_path)
                            if xbrl_content:
                                root = etree.fromstring(xbrl_content)
                                tag_to_value_and_attrs = get_values_and_attributes_from_xbrl(root)
                                save_to_json(tag_to_value_and_attrs, year, doc_id)
            else:
                print(f"{current_date.strftime('%Y-%m-%d')} のデータ取得に失敗しました。")
            
            current_date += timedelta(days=1)

まとめ

この記事では、EDINET APIから過去5年間の有価証券報告書を取得し、その報告書に含まれるXBRLデータを辞書化し、JSON形式で保存する方法について解説しました。これまでのブログ記事で学んできた内容を基に、より長期間のデータ取得と管理を実現しました。

次回の記事では、取得したXBRLデータの具体的な分析方法や、フィルタリング、可視化について取り組んでいきたいと思います。

過去のデータを効率的に取得して分析するための第一歩として、このコードを活用して、投資分析や経済データの活用に役立ててください!

タイトルとURLをコピーしました