EDINETから10年分のXBRLデータをスクレイピング

■2023年4月現在で使えるコードです■
環境:windows10
jupiter notebook python3にて動作確認

このコードは、EDINETのWebページから10年分の短信を取得するものです。 requests ライブラリを用いてWebページにアクセスし、
年ごとにループを回してデータを取得しています。
取得したデータはZipファイルとして取得され、 zipfile ライブラリを使用して展開されます。

10年分のデータはPC性能や環境にもよりますが約60分程度かかります。
※通信ビジー時にもリトライするコードですが50回を上限として設定しています

・cnでEDINETコードを指定して約10年分を遡って書類を取得します。
 ※EDINETコードは証券コードと同じではありません

・〇部分は指定してください

import requests
import json
import datetime
import os
import time
os.chdir("C:\\〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇")   
#指定後の絶対パスの出力
print(os.getcwd())
dt = datetime.date.today()
#検索する会社のEDINETコードを入れる
cn = "〇〇〇〇〇〇"
kessan = []

for i in range(0,3000):
    d = dt - datetime.timedelta(i) 
    # 書類一覧APIのエンドポイント
    url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"
    
    # 書類一覧APIのリクエストパラメータ
    params = {
    "date" : d,
    "type" : 2,
    "count": 1,
    "start": st
    }
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    # APIを呼び出す関数
    def call_api(url, params,max_retry=50):
        retry_count=0
        while retry_count < max_retry:
            response = requests.get(url, params=params)
            if response.status_code == 200:
                response.raise_for_status()
                return response.json()
            else:
                retry_count += 1
                time.sleep(1)
        raise Exception(f"Failed to get a response after {max_retry} attempts")

    # 書類情報の総件数を取得する
    # params['count'] = '1'
    result = call_api(url, params)
    total_count = result['metadata']['resultset']['count']
    print(d)
    print(total_count)

    # 書類情報を取得する
    # params.pop('count')
    params['length'] = '200'
    results = []
    #書類の数が200を超えているかどうかの条件分岐
    if total_count < 200:
        # 200件未満の場合は1回のAPI呼び出しで結果を取得する
        res = requests.get(url, params=params, verify=True,timeout=30)
        try:
            res_text = json.loads(res.text)
        except json.JSONDecodeError:
            data = None
        results= res_text["results"]
    else:
        # 200件以上の場合は複数回のAPI呼び出しで結果を取得する
        st = 0
        for start in range(0, total_count, 200):
            res = requests.get(url, params=params, verify=True, timeout=30)
            try:
                res_text = json.loads(res.text)
            except json.JSONDecodeError:
                data = None
            results= res_text["results"]
            st = st + 200
    #DL書類の検索
    for result in results:
            filename = ""
            if result["edinetCode"] is not None:
                if cn in result["edinetCode"]:
                    if '四半期' in result["docDescription"] or "有価証券報告書" in result["docDescription"]:
                        kessan.append(result)  
        
                        docid =result["docID"] 
                #日付の/がエラーの原因となっているので取り除く対応を行った 23/2/26
                        result["docDescription"] = result["docDescription"].replace("/", "")                    
                #指定のZIPファイルを保存
                        url = "https://disclosure2.edinet-fsa.go.jp/api/v1/documents/" + docid
                # 書類取得APIのリクエストパラメータ
                        params = {
                        "date" : d,
                        "type" : 1
                        }
                # 出力ファイル名 resultの結果を追うようにIDは変数として取り込む
                        filename = result["secCode"]+"_"+result["filerName"]+"_"+result["docDescription"]+"_"+result["docID"]
                        filename = f"{filename}_{d.strftime('%Y%m%d')}"+".zip"
                        print(filename)              
                        
                    # 書類一覧APIの呼び出し
                        res = requests.get(url, params=params, verify=True)         
                        if res.status_code == 200:
            #wbはバイナリ書き込みモード
                            with open(filename, 'wb') as f:
                                for chunk in res.iter_content(chunk_size=1024):
                                    f.write(chunk)   
print(len(kessan))

APIの仕様書等は下記を参考ください。

・APIは2種類存在し
 書類一覧API:日付のみ指定可能
 書類DLAPI:上記APIで取得した書類IDを指定してダウンロード

・200件が上限設定されているとのことなので 念のため200件ずつ検 
 索をかけています。
 200件を超える恐れがない場合は条件分岐と200件ごとの検索分を削 
 除することで各段に完了までの時間が短縮されます。

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