見出し画像

python EDINET APIを使って有価証券報告書他 資料を取得する

ここを参考にして作った

忘れっぽいので参考にしたサイトの解説メモを追加しておく

いくつか作ってみてから再度別のサイトのサンプルを見直すと、
理解できなかったところがみえてくるから面白い。
本を再読すると違った感じ方がするようなものか

では、ここからメモ

EDINETからデータ取得する場合、二つのAPIがある
書類一覧API:書類の一覧を取得するAPI
書類取得API:書類の内容を取得するAPI

〇requestsモジュールのインストール

PythonからWeb APIを呼び出すには、requestsモジュールをインポートする。そのため、初めに一度だけrequestsモジュールをインストールする必要がある。

Pythonのrequestsモジュールをインストールするには、次のコマンドを実行する。

!pip install requests

〇メタデータを取得する

メタデータとは、日付ごとの提出書類一覧に関する基礎情報のことである。メタデータには、件数や更新日時などが含まれる。

EDINETからメタデータを取得するには、書類一覧APIを使う。

・EDINET書類一覧API

エンドポイント: https://disclosure.edinet-fsa.go.jp/api/バージョン/documents.json
HTTPメソッド: GET
応答形式: JSON
暗号化: TLS (Transport Layer Security)
クロスドメイン通信: 許可しない

EDINET書類一覧APIのリクエストパラメータ(2つ)は、次のとおり。

date ファイル日付 必須:Yes
 日付(YYYY-MM-DD形式)
 出力対象とする提出書類一覧のファイル日付を指定します。
type 取得情報 必須:No
 1:メタデータのみを取得(指定が無い場合のデフォルト値
 2:提出書類一覧及びメタデータを取得

import requests

# 書類一覧APIのエンドポイント
url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"

# 書類一覧APIのリクエストパラメータ
params = {
  "date" : "2023-06-12"
}

# 書類一覧APIの呼び出し
res = requests.get(url, params=params, verify=False)

# レスポンス(JSON)の表示
print(res.text)

params でdateのみ指定しているため
types は省略されているためデフォルトの 1 が渡される

実行結果は

{
  "metadata": {
    "title": "提出された書類を把握するためのAPI",
    "parameter": {
      "date": "2023-06-12",
      "type": "1"
    },
    "resultset": {
      "count": 203
    },
    "processDateTime": "2023-06-25 00:02",
    "status": "200",
    "message": "OK"
  }
}

203件のデータあり

同じ書類一覧APIを使って
提出書類一覧及びメタデータを取得

type 2 :提出書類一覧及びメタデータを取得

import requests

# 書類一覧APIのエンドポイント
url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"

# 書類一覧APIのリクエストパラメータ
params = {
  "date" : "2023-06-12",
  "type" : 2
}

# 書類一覧APIの呼び出し
res = requests.get(url, params=params, verify=False)

# レスポンス(JSON)の表示
print(res.text)

実行結果(1行目のワーニングはとりあえずスルー)

/usr/local/lib/python3.10/dist-packages/urllib3/connectionpool.py:1056: InsecureRequestWarning: Unverified HTTPS request is being made to host 'disclosure.edinet-fsa.go.jp'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  warnings.warn(
{
  "metadata": {
    "title": "提出された書類を把握するためのAPI",
    "parameter": {
      "date": "2023-06-12",
      "type": "2"
    },
    "resultset": {
      "count": 203
    },
    "processDateTime": "2023-06-25 00:02",
    "status": "200",
    "message": "OK"
  },
  "results": [
    {
      "seqNumber": 1,
      "docID": "S100QWV4",
      "edinetCode": "E04931",
      "secCode": "97930",
      "JCN": "6180001006700",
      "filerName": "株式会社ダイセキ",
      "fundCode": null,
      "ordinanceCode": "010",
      "formCode": "170000",
      "docTypeCode": "220",
      "periodStart": null,
      "periodEnd": null,
      "submitDateTime": "2023-06-12 09:00",
      "docDescription": "自己株券買付状況報告書(法24条の6第1項に基づくもの)",
      "issuerEdinetCode": null,
      "subjectEdinetCode": null,
      "subsidiaryEdinetCode": null,
      "currentReportReason": null,
      "parentDocID": null,
      "opeDateTime": null,
      "withdrawalStatus": "0",
      "docInfoEditStatus": "0",
      "disclosureStatus": "0",
      "xbrlFlag": "1",
      "pdfFlag": "1",
      "attachDocFlag": "0",
      "englishDocFlag": "0",
      "csvFlag": "1",
      "legalStatus": "1"
    },
    {
      "seqNumber": 2,
      "docID": "S100QN6G",
      "edinetCode": "E09666",
      "secCode": null,
      "JCN": "9010001062807",
      "filerName": "アムンディ・ジャパン株式会社",
      "fundCode": "G13968",
      "ordinanceCode": "030",
      "formCode": "10A000",
      "docTypeCode": "160",
      "periodStart": "2022-09-13",
      "periodEnd": "2023-09-12",
      "submitDateTime": "2023-06-12 09:00",
      "docDescription": "半期報告書(内国投資信託受益証券)-第3期(2022/09/13-2023/09/12)",
      "issuerEdinetCode": null,
      "subjectEdinetCode": null,
      "subsidiaryEdinetCode": null,
      "currentReportReason": null,
      "parentDocID": null,
      "opeDateTime": null,
      "withdrawalStatus": "0",
      "docInfoEditStatus": "0",
      "disclosureStatus": "0",
      "xbrlFlag": "1",
      "pdfFlag": "1",
      "attachDocFlag": "0",
      "englishDocFlag": "0",
      "csvFlag": "1",
      "legalStatus": "1"
    },
・
・
続く(略

EDINET書類一覧APIの出力データ内容(レスポンスデータ)
項目名 項目ID 型 説明
連番 seqNumber number ファイル日付ごとの連番
書類管理番号 docID string 書類管理番号
提出者EDINETコード edinetCode string 提出者のEDINETコード
提出者証券コード secCode string 提出者の証券コード

〇書類(PDF、XBRL)を取得する

書類取得APIを使う

エンドポイント: https://disclosure.edinet-fsa.go.jp/api/バージョン/documents/書類管理番号
HTTPメソッド: GET
応答形式: ZIP、PDF、JSON
暗号化: TLS (Transport Layer Security)
クロスドメイン通信: 許可しない

書類取得APIのパラメータは以下の通り

type (必須項目)
1: 提出本文書及び監査報告書
2: PDF
3 : 代替書面・添付文書
4: 英文ファイル

以下、ZIP、PDF それぞれの取得プログラム

・ZIPファイル

import requests

# 書類管理番号
docid = "S100FIZV"

# 書類取得APIのエンドポイント
url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents/" + docid

# 書類取得APIのリクエストパラメータ
params = {
  "type" : 1
}

# 出力ファイル名
filename = docid + ".zip"

# 書類取得APIの呼び出し
res = requests.get(url, params=params, verify=False)

# ファイルへ出力
if res.status_code == 200:
  with open(filename, 'wb') as f:
    for chunk in res.iter_content(chunk_size=1024):
      f.write(chunk)

・PDFファイルを取得

import requests

# 書類管理番号
docid = "S100FIZV"

# 書類取得APIのエンドポイント
url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents/" + docid

# 書類取得APIのリクエストパラメータ
params = {
  "type" : 2
}

# 出力ファイル名
filename = docid + ".pdf"

# 書類取得APIの呼び出し
res = requests.get(url, params=params, verify=False)

# ファイルへ出力
if res.status_code == 200:
  with open(filename, 'wb') as f:
    for chunk in res.iter_content(chunk_size=1024):
      f.write(chunk)

param type=2 → PDFファイル

で、これだと S100QXDB.pdf というような docid.pdf になってしまい、中身がわからない
証券コードと企業名をファイル名にするように変更したのがこちらのプログラム

import time
import requests
import zipfile
import os
from pathlib import Path
import urllib3
from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings(InsecureRequestWarning)
from datetime import datetime, timedelta #v2


#drive のマウントアイコンをクリックしてマウントする

#001
def get_submission_docs(date):
    """提出された書類を把握するためのAPI"""
    url = 'https://disclosure.edinet-fsa.go.jp/api/v1/documents.json'
    params = {
        "date": date,
        "type": 2,  #提出書類一覧およびメタデータを取得
    }

    return requests.get(url, params=params, verify=False)

#002
def generate_doc_information(results):
    """filerName(会社名)とdocID(書類管理番号)とsecCode(証券コード)をyieldして返す"""
    for result in results:
       if result['docTypeCode'] != '120' or result['secCode'] is None :
            continue
       yield result['filerName'], result['docID'],result['secCode']


#003
def get_doc_binary_response(doc_id):
    url = f'https://disclosure.edinet-fsa.go.jp/api/v1/documents/{doc_id}'
    params = {
        "type": 2 #PDFを取得する
#        "type": 1 #XBRLを取得する
    }

    return requests.get(url, params=params, verify=False)

#004
def download_doc(date, filerName, secCode, binary_response):
    # 保存用のreportフォルダを作る
    #base_dir = Path('__file__').resolve().parent
    #drive のマウントアイコンをクリックしてマウントしてから
    base_dir = "/content/drive/MyDrive/Colab Notebooks"
    save_dir_name = 'yuho_data2023'
    if not os.path.exists(Path(base_dir, save_dir_name)):
        os.makedirs(Path(base_dir, save_dir_name))


    # 保存フォルダ名
    folder_path = f'{base_dir}/{save_dir_name}/{secCode}_{filerName}_{date}'

    filename = folder_path + '.pdf'
    with open(filename, 'wb') as f:
        for chunk in binary_response.iter_content(chunk_size=1024):
            f.write(chunk)


#005 実行ジョブ
def job():

# 開始日と終了日を設定します。
    start_date = datetime(2023, 6, 21)
    end_date = datetime(2023, 6, 24)

# 指定期間の日付を列挙します。
    for n in range(int ((end_date - start_date).days)+1):
        date = (start_date + timedelta(n)).strftime('%Y-%m-%d')  # datetimeオブジェクトを文字列に変換
        print(date)

        res = get_submission_docs(date)   #001
        print(res.json())
#        results = res.json()['results']
        results = res.json().get('results', []) # get methodを使って、resultsキーがない場合は空のリストを返すように修正
        for filerName, doc_id, secCode in generate_doc_information(results):    #002
            binary = get_doc_binary_response(doc_id)  #003
            download_doc(date, filerName, secCode, binary)  #004
            time.sleep(.5)


if __name__ == '__main__':
    job()

secCode:証券コード
filerName:会社名
をパラメータで渡して、ファイル名を生成している。

以上

何かの参考になれば幸いです。


この記事が気に入ったらサポートをしてみませんか?