ストックドッグ

KatoTakahiro。金融系の会社で働くSEが株やPython、その他諸々について書いています。サービスも運営してます→http://fmbrain.work

XBRLをAPI経由で取得する方法 ~Pythonで実装してみる~


EDINETのAPIの仕様が公開され、XBRL解析する勢はワクワクしています...(たしか公開は2019年3月)


と言いつつ、現状でもAPIは提供されており、そこからXBRLの取得自体は可能です。(提供元は違います)


そもそもXBRLって何って方は、こちらの記事参照。


www.stockdog.work


提供されているのは、有限会社プレシスという会社が有報キャッチャーというAPIです。

(引用)
有報キャッチャーは、EDINETやTDnetで開示されたIR情報をご提供するサービスです。
XBRLデータを活用し、会社属性情報などを整理・閲覧することができます。

ufocatch.com



APIの使い方はどシンプルなので、記事にするほどでもないのですが、XBRLのフォルダ構成が絡むと少しややこしくなるので備忘含めたメモ的な記事にしておきました。

とりあえず、有報キャッチャーなるAPIを経由したXBRLの取得をPythonで実装してみました記事です。

APIのエンドポイント

http://resource.ufocatch.com/atom/edinet/query/

エンドポイントの末にクエリワード(銘柄コードやEDINETコード)を指定して、リクエストを送ると、EDINETに提出されているドキュメントのURL一覧が返ってきます。


あくまでもレスポンスは、ドキュメントのURL一覧であり、まだXBRLは取得できません。

APIを使ってみる

例えば、「三菱UFJ 日本成長株オープン」という投資信託のドキュメント一覧を取得したければ...

# 三菱UFJ 日本成長株オープンのEDINETコードはG01051
GET http://resource.ufocatch.com/atom/edinet/query/G01051

EDINETコードは、EDINETサイトからCSV形式で取得可能です。


ok google 「EDINETコードを検索して」

と言えばひっかかる気がします。(EDINETはURL長いので貼りたくありませんでした...)


上のリクエストを送ると、レスポンスはこんな感じ。

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>有報キャッチャー - EDINET情報配信サービス</title>
  <link href="http://resource.ufocatch.com/" />
  <updated>2018-09-22T10:04:03Z</updated>
  <id>http://resource.ufocatch.com/atom/edinet/query/G01051</id>
  <entry>
    <title>【G01051】三菱UFJ投信株式会社 有価証券報告書(内国投資信託受益証券)-第19期(平成29年4月21日-平成30年4月20日)</title>
    <link rel="alternate" type="text/html" href="http://resource.ufocatch.com/pdfv/ED2018071900080" />
    <id>ED2018071900080</id>
    <docid>S100DKHL</docid>
    <updated>2018-07-19T09:19:00+09:00</updated>
    <link rel="related" type="application/zip" href="http://resource.ufocatch.com/data/edinet/ED2018071900080" />
    <link rel="related" href="http://resource.ufocatch.com/xbrl/edinet/ED2018071900080/S100DKHL/XBRL/AuditDoc/jpaud-aar-cn-001_E11518-000_2018-04-20_01_2018-07-19.xbrl" type="text/xml" />
    <link rel="related" href="http://resource.ufocatch.com/xbrl/edinet/ED2018071900080/S100DKHL/XBRL/AuditDoc/jpaud-aar-cn-001_E11518-000_2018-04-20_01_2018-07-19.xsd" type="text/xml" />
    ...


長いので省略しますが...

提出されているドキュメントの一覧が返ってきます。

厳密には提出されているファイルのパスの一覧が返ってくる


提出されているドキュメントの一覧が返ってくるというのは誤りで、キレイな一覧では返ってこないです。

理想は...

$ GET http://resource.ufocatch.com/atom/edinet/query/G01051
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2018-03-23に提出された有報.xbrl
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2017-03-23に提出された有報.xbrl
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2016-03-23に提出された有報.xbrl
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2015-03-23に提出された有報.xbrl

みたいな、ドキュメントの一覧なのですが、そうはいきません。

キレイな一覧で返ってこない理由は...

例えば、有報(きっと他のドキュメントも)。

これらは1つの有報というドキュメントを複数ファイルで構成されているからです。

$ GET http://resource.ufocatch.com/atom/edinet/query/G01051
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2018-03-23に提出された有報.xbrl
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2018-03-23に提出された有報の画像.image
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2018-03-23に提出された有報の一部.htm

http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2017-03-23に提出された有報.xbrl
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2017-03-23に提出された有報の画像.image
http://resource.ufocatch.com/xbrl/edinet/ED2018032300059/2017-03-23に提出された有報の一部.htm

...

イメージで言うと、上記のようなレスポンスになります。


XBRLをダウンロードしたことがあって、中身を見たことがある人はわかると思います。

ダウンロードするとXBRLのファイルだけではなくて、他にもhtmやimageなど色々とあるんですね。


f:id:doz13189:20180922195607p:plain


この中でほしいのは、拡張子が.xbrlのファイルだけです。

他はノイズです。


そのため、返ってきたレスポンスの中から.xbrlのパスのみを取得して、その取得したパスを見に行くことでXBRLが取得できます。

Pythonで実装

import requests
from bs4 import BeautifulSoup
import re
import time

# エンドポイントにリクエスト
response = requests.get("http://resource.ufocatch.com/atom/edinet/query/G01003")
response.encoding = response.apparent_encoding

# レスポンスをBS4でHTMLを解析
soup = BeautifulSoup(response.text, "lxml")
links = soup.find_all("link")

# 返ってきた一覧のうち、.xbrlかどうかを正規表現で判別
pattern = ".*PublicDoc.*\.xbrl"

for lin in links:
	result = re.search(pattern , lin.get("href"))

	# .xbrlであれば、xbrlを取得
	if result != None:
		print(lin.get("href"))
		response = requests.get(lin.get("href"))
		response.encoding = response.apparent_encoding
		print(response.text)

	else:
		pass

	time.sleep(2.0)


少し正規表現の部分を補足すると...

pattern = ".*PublicDoc.*\.xbrl"

拡張子を.xbrlで指定しています。

また、Publicと指定しているのは、EDINET上に公開されている方の情報を取得するためです。

Publicと同じ階層にAuditがあるのですが、こちらは独立監査人用のものなようです(たぶん)。

まとめ

とりあえず、特にエラーがなければ上記のコードでXBRLが取得できたはずです。

素でAPI叩くのもいいですが、edinet-xbrlというライブラリもあるので、APIの構造が理解できれば以降はライブラリを使ったほうがいいですね。


github.com



以上、終わり!