【Python】企業の決算情報をEDINET APIで取得する

プログラミング
http://disclosure.edinet-fsa.go.jp/ https://www.python.org/community/logos/
この記事は約20分で読めます。

株式投資をやっていると、当然企業の決算情報や適時開示情報を確認することがあると思いますが、めんどくさがりな私としてはそれらの情報を1つ1つチェックするのは大変なので、プログラムで自動チェックしたいと思うところです。

適時開示情報(XBRL)は、こちらの金融庁が提供している有価証券報告書などの開示書類を閲覧するサイト(EDINET)からダウンロードできるのですが、大量のデータをダウンロードしようと思うと大変でした。

ところが、よくよく調べてみると、なんとWeb APIを提供してくれていました。ついに望んでいたものに巡り会えたという感じです。ということで、EDINETが提供しているWeb APIを使って企業の適時開示情報を取得するプログラムを紹介したいと思います。

EDINET API

EDINETは、こちらのページで結構親切にAPIの使い方を説明していくれています。
基本的には以下のサイトに従いながらプログラムを書いていきたいと思います。

requests、jsonモジュールのインポート

モジュールをインストールします。
EDINETのページでは、requestsだけimportしておりますが、結果がjson形式で返ってくるので、jsonもインポートしておきます。

import requests
import json

提出書類一覧データおよびメタデータの取得

EDINET APIに記載の通り以下のコードでデータ取得できます。

# 書類一覧APIのエンドポイント
url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"
# 書類一覧APIのリクエストパラメータ
params = {
  "date" : '2019-04-25',
  "type" : 2
}

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

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

以下のような結果が得られます。
※Warningが出るかもしれませんが、気にしなくて大丈夫です。

{
    "metadata":
        {
            "title": "提出された書類を把握するためのAPI",
            "parameter":
                {
                    "date": "2019-04-25",
                    "type": "2"
                },
            "resultset":
                {
                    "count": 370
                },
            "processDateTime": "2019-10-22 00:01",
            "status": "200",
            "message": "OK"
        },
    "results": [
        {
            "seqNumber": 1,
            "docID": "S100FIZV",
            "edinetCode": "E11764",
            "secCode": null,
            "JCN": "1010401064261",
            "filerName": "T&Dアセットマネジメント株式会社",
            "fundCode": "G08875",
            "ordinanceCode": "030",
            "formCode": "07A000",
            "docTypeCode": "120",
            "periodStart": "2018-07-26",
            "periodEnd": "2019-01-25",
            "submitDateTime": "2019-04-25 09:00",
            "docDescription": "有価証券報告書(内国投資信託受益証券)-第13期(平成30年7月26日-平成31年1月25日)",
            "issuerEdinetCode": null,
            "subjectEdinetCode": null,
            "subsidiaryEdinetCode": null,
            "currentReportReason": null,
            "parentDocID": null,
            "opeDateTime": null,
            "withdrawalStatus": "0",
            "docInfoEditStatus": "0",
            "disclosureStatus": "0",
            "xbrlFlag": "1",
            "pdfFlag": "1",
            "attachDocFlag": "1",
            "englishDocFlag": "0"
        },
        {
            "seqNumber": 2,
            "docID": "S100FNKK",
            "edinetCode": "E12448",

--- 以下省略 ---

resultsデータの取得

実際のドキュメントのデータを取得するために、docID、docDescription、filerNameを使いたいので、上記のresをjsonに変換してpythonで扱えるようにします。

#APIの結果をjson形式に変換
res_text = json.loads(res.text)

#res_text内のresultsの内容を取得
results= res_text["results"]

#resultsの中身(docID, docDescription, filerName)を表示
for result in results:
    print(result['docID'], result['docDescription'],result['filerName'])

以下のような結果が得られます。

S100FIZV 有価証券報告書(内国投資信託受益証券)-第13期(平成30年7月26日-平成31年1月25日) T&Dアセットマネジメント株式会社
S100FNKK 臨時報告書(内国特定有価証券) 明治安田アセットマネジメント株式会社
S100EU0W 半期報告書(内国投資信託受益証券)-第9期(平成30年7月26日-平成31年7月25日) 三井住友トラスト・アセットマネジメント株式会社
S100FJ03 訂正有価証券届出書(内国投資信託受益証券) T&Dアセットマネジメント株式会社
S100F0BR 半期報告書(内国投資信託受益証券)-第19期(平成30年7月26日-平成31年7月25日) アセットマネジメントOne株式会社
S100F8D7 有価証券報告書(内国投資信託受益証券)-第11期(平成30年7月27日-平成31年1月28日) 新生インベストメント・マネジメント株式会社
S100FGIF 訂正有価証券届出書(内国投資信託受益証券) 野村アセットマネジメント株式会社
--- 以下省略 ---

決算データの取得

先程のresultsデータの中には様々な適時開示情報が含まれているのですが、決算短信の情報にしぼりたいと思います。

kessan = []
for result in results:
    if result['docDescription'] is not None:
        if '四半期' in result['docDescription']:
            print(result['docID'], result['docDescription'],result['filerName'])
            kessan.append(result)

以下の3社の四半期報告書がありました。

S100FOJX 四半期報告書-第22期第2四半期(平成31年1月1日-平成31年3月31日) 株式会社サイバーエージェント
S100FOK3 四半期報告書-第38期第1四半期(平成31年1月1日-平成31年3月31日) 株式会社ブロンコビリー
S100E3QC 四半期報告書-第19期第2四半期(平成30年5月1日-平成30年7月31日) 株式会社Mマート

zipファイルの取得

先程取得したresultsリストの0番目(サイバーエージェント)のXBRLデータを取得したいと思います。

#0番目のdocumentのdocID(S100FOJX)を取得
docid = kessan[0]['docID'] 
print(docid)

>> 'S100FOJX'

このdocidを使って、zipファイルを取得するコードを書きます。

# 書類取得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)

これで現在のフォルダに「S100FOJX.zip」というzipファイルができていると思います。

zipファイルの解凍

このzipファイルを手動で解凍しても良いのですが、それだとファイル数が増えたときに大変なので、解凍も自動化したいと思います。
zipファイルの解凍にはzipfileというモジュールをインポートします。

以下のコードで現在のフォルダに解凍されたフォルダが展開されます。

import zipfile
with zipfile.ZipFile(filename) as existing_zip:
    existing_zip.extractall(docid)

S100FOJXという名前のフォルダが出来上がり、以下のようなフォルダ構成になっているかと思います。

S100FOJX/
└── XBRL
    ├── AuditDoc
    │   ├── jpaud-qrr-cc-001_E05072-000_2019-03-31_01_2019-04-25.xbrl
    │   ├── jpaud-qrr-cc-001_E05072-000_2019-03-31_01_2019-04-25.xsd
    │   ├── jpaud-qrr-cc-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
    │   ├── jpaud-qrr-cc-001_E05072-000_2019-03-31_01_2019-04-25_pre.xml
    │   └── manifest_AuditDoc.xml
    └── PublicDoc
        ├── 0000000_header_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0101010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0102010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0103010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104000_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104020_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104035_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104050_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104100_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0104110_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── 0201010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25.xbrl
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25.xsd
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_cal.xml
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_def.xml
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_lab-en.xml
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_lab.xml
        ├── jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_pre.xml
        └── manifest_PublicDoc.xml

htmファイルの取得

先程のフォルダの中の「0101010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm」というファイルに売上高、経常利益などが記載されていますので、そのhtmファイルをpythonで扱えるようにしたいと思います。

フォルダ内のファイルを取得するのには、globというモジュールをインポートします。

import glob

filepath = docid + '/XBRL/PublicDoc/'

files = glob.glob(filepath+'*.htm') #htmファイルの取得
files = sorted(files) #ファイルを並び替えているだけ
target_file = files[1]
print(target_file)

>> S100FOJX/XBRL/PublicDoc/0101010_honbun_jpcrp040300-q2r-001_E05072-000_2019-03-31_01_2019-04-25_ixbrl.htm

以下のコードでhtmlファイルとして読み込むことができます。

with open(target_file , encoding='utf-8') as f:
    html = f.read()

BeautifulSoupでhtml内のデータを取得

上記のコードでhtmlファイルとして読み込むことができたので、最後にBeautifuSoupでデータを取得したいと思います。

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'html.parser')

tag_p = soup.find_all('p') #pタグの要素を取得

#pタグのテキストを表示
for p in tag_p:
    print(p.text)

以下のような結果が得られていると思います。

回次
第21期
第2四半期
連結累計期間
第22期
第2四半期
連結累計期間
第21期
会計期間
自  2017年10月1日
至  2018年3月31日
自  2018年10月1日
至  2019年3月31日
自  2017年10月1日
至  2018年9月30日
売上高
(百万円)
207,495
228,184
419,512
経常利益
(百万円)
18,574
13,729
28,565
--- 以下省略 ---

あとはスクレイピングと同じ要領ですね。

ここからはスクレピングのテクニックなので、私の他の投稿を見ていただくか、以下の書籍で勉強してもらえればと思います。

まとめコード

以上で、無事決算データをプログラムで取得できるようになりました。
以下にまとめコードを書いておきます。

import requests
import json
import zipfile
import glob
from bs4 import BeautifulSoup


# 書類一覧APIのエンドポイント
url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"
# 書類一覧APIのリクエストパラメータ
params = {
  "date" : '2019-04-25',
  "type" : 2
}

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

# resultデータ取得
res_text = json.loads(res.text)
results= res_text["results"]

# 決算データに絞る
kessan = []
for result in results:
    if result['docDescription'] is not None:
        if '四半期' in result['docDescription']:
            kessan.append(result)


# zipファイル取得
docid = kessan[0]['docID']
url = 'https://disclosure.edinet-fsa.go.jp/api/v1/documents/' + docid
params = {
  "type" : 1
}
res = requests.get(url, params = params, verify=False)

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

# zipファイル解凍
with zipfile.ZipFile(filename) as existing_zip:
    existing_zip.extractall(docid)

# 対象htmの取得
filepath = docid + '/XBRL/PublicDoc/'
files = glob.glob(filepath+'*.htm')
files = sorted(files)
target_file = files[1]

with open(target_file , encoding='utf-8') as f:
    html = f.read()

# htmデータの取得
soup = BeautifulSoup(html, 'html.parser')

tag_p = soup.find_all('p')
for p in tag_p:
    print(p.text)

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