EDINET XBRLを読み込むPythonライブラリ

EDINET決算分析システム
(2020年11月6日 追記)Python で XBRL のデータを取得するなら、まず『Arelle(アレル)』という Python ライブラリを使ってみるのが良いと思います。
【Python】Arelle のインストール方法【XBRL 読み込みライブラリ】

以下は、自分が XBRL を読み込むために作成した Python ライブラリです。

(2022年3月31日 追記)このライブラリよりも、まずは↑上記の Arelleアレル の使用をおすすめします。


金融庁の EDINET で公開されている XBRL を読み込むために作りました。

上場企業の有価証券報告書、四半期報告書に対応しています。また、2013年以前の【旧】EDINET XBRL 形式にも対応しています。

このライブラリは、各勘定科目のタグ名・金額・日付・連結区分といった情報を、XBRL ファイルから一括で取得します。

要は、XBRLデータの中身をスクレイピングするライブラリです。

たとえば、以下のようなデータが取得できます。

XBRL 読み込み例XBRL読み込み例

コンテキストなどの定義をたどって、表形式に組み立てるのが主な機能です。

このデータから時系列分析をした時の記事はこちら

XBRLを一気に読み込み、データベースで時系列にする。

version から第N期(第N四半期のこと)までがファイル名からの情報で、名前空間接頭辞から値までが、個々の勘定科目とコンテキストから読み取った情報です。

このライブラリに XBRL のファイルパスを渡すと、上の画像のようなデータフレームが返ってきますので、ある企業の XBRL を全て連結して、売上・利益の時系列グラフを描く、といったことに使えます。

データフレームとは、pandas.DataFrame のことです。
これは、CSVやエクセル形式で保存することができます。それぞれ『.to_csv()メソッド』と『.to_excel()メソッド』を使うと保存できます。(エクセル形式で保存するには、別途 XlsxWriter, openpyxl, xlwt といったライブラリが必要になる場合があります。)
データフレームの『.to_json()メソッド』を使えば、XBRLをjson(ジェイソン)形式に変換することができます。もし、『インデックスが重複してはならない』という以下のエラーが出た場合は、『.reset_index(drop=True)メソッド』でインデックスを付け直すと保存できます。
ValueError: DataFrame index must be unique for orient='columns'.

(米国のEDGAR XBRL用のライブラリも作りました)

もっと詳細なXBRLパーサーの作り方の記事も書きました。

以下、XBRL解析ライブラリの説明です。

Pythonライブラリのダウンロード

有価証券報告書の XBRL を読み込む Python ライブラリ です。
(xbrl reader for edinet)

xbrl_reader_for_edinet_20180702-00.zip (zip形式 11.1KB)

※ このライブラリは、当サイトの管理人が作成したものです。

EDINET や金融庁は無関係です。

ライセンス (NYSL Version 0.9982)

このライセンスは、上記ライブラリの中の各Pythonファイルに対して適用します。

これらのPythonファイルの中でインポートしているその他のライブラリに関しては、それぞれのライセンスに従ってご利用ください。

NYSL Version 0.9982

A. 本ソフトウェアは Everyone’sWare です。このソフトを手にした一人一人が、
ご自分の作ったものを扱うのと同じように、自由に利用することが出来ます。

A-1. フリーウェアです。作者からは使用料等を要求しません。
A-2. 有料無料や媒体の如何を問わず、自由に転載・再配布できます。
A-3. いかなる種類の 改変・他プログラムでの利用 を行っても構いません。
A-4. 変更したものや部分的に使用したものは、あなたのものになります。
公開する場合は、あなたの名前の下で行って下さい。

B. このソフトを利用することによって生じた損害等について、作者は
責任を負わないものとします。各自の責任においてご利用下さい。

C. 著作者人格権は シラベルノート はるかわ に帰属します。著作権は放棄します。

D. 以上の3項は、ソース・実行バイナリの双方に適用されます。

動作環境と必要なライブラリ

カッコ内は動作確認で使用したバージョンです。

極端に古くなければ、ほかのバージョンでも動くと思います。

  • Python (3.5.2) 64bit版 または Python (3.4.3) 32bit版
  • lxml (3.6.4)
  • python-dateutil (2.6.1)
  • pandas (0.22.0)

インストール手順

ダウンロードした zip の中身を、あなたが開発している Python ファイルと同じフォルダに展開します

または、別のフォルダに展開して、そのフォルダへのパスを sys.path のリストに追加します

"""あなたが開発しているPythonファイル.py"""
import sys
sys.path.append(r'ライブラリを展開したフォルダへのパス')

これで、あなたの Python ファイルからインポートできるようになりました。

アンインストール手順

インストール手順で展開した Python ファイルを削除してください。

これで、アンインストールは完了です。

あと、ライブラリを使用した場合は、「__pycache__」というフォルダに「.pyc」というキャッシュファイルが作られていると思います。展開した Python ファイルの名前が入ったキャッシュファイルは不要ですので、これも削除してください。

「.pyc」の説明は、以下の Python マニュアルをご覧ください。

(Python) モジュール (module) "コンパイル" された Python ファイル

XBRLファイルを読み込む

複数の Python ファイルに分かれていますが、実際にインポートして使うのは「エックス・ビー・アール・エル・プロック(xbrl_proc.py)」にある、以下の関数です。それぞれ、解凍済みの「.xbrl」を読み込む用と、圧縮された「.zip」から読み込む用です。

read_xbrl(xbrl=xbrlファイルパス)
戻り値:pandas.DataFrame

read_xbrl_from_zip(xbrl=zipファイルパス)
戻り値:pandas.DataFrame のリスト

※ zipの中には、「jpfrとifrs」、「jpcrpとifrs」といった組み合わせで複数のXBRLファイルが入っている場合があります。そのため、zip版では戻り値を常にリストに入れて返すようにしています。ですので、戻り値をfor文にかけるなどして、個々のデータフレームを取り出してください

なお、監査報告書の XBRL(jpaud)はスキップしています。財務諸表が載っている XBRL だけを読み込んでいます。

使用例

ファイルに応じて、以下のように使い分けます。どちらか必要なほうを使ってください。

xbrl から読み込む

XBRL 用の関数にファイルパスを渡すと、データフレームが返ります。

# xbrl から読み込む
from xbrl_proc import read_xbrl

xbrl_file = r"*****\jpcrp030000-asr-001_E00000-000_2017-03-31_01_2017-06-29.xbrl"
df = read_xbrl(xbrl_file)

zip から読み込む

zip 用の関数にファイルパスを渡すと、データフレームのリストが返ります。

# zip から読み込む (データフレームのリストが返る)
from xbrl_proc import read_xbrl_from_zip

zip_file = r"*****\SXXXXXXX.zip"
df_list = read_xbrl_from_zip(zip_file)

for df in df_list:
    (データ処理など)

Pythonコードの解説

このライブラリの Python コードの解説は「XBRLまとめ」の記事に載っています。ライブラリの構造を知りたい時にご覧ください。

読み込みエラーなどについて

このライブラリには、assert文やraise文といった、デバッグ用のコードが残っています。もし、これらに反応して読み込めないファイルがあったときは、反応しているコードをコメントアウトするなどしてみてください。それでとりあえず読み込める場合もあるかもしれません。

全上場企業のXBRLを大量に読み込んでいくと、何かしらの読み込みエラーに遭遇すると思います。原因ですが、ダウンロードに失敗してXBRL(zip)が壊れていた、ファイル名が仕様書に無いパターンであった、XBRLファイルの構文に誤りがあった、などです。

これらに遭遇するたび修正して、出来るだけ止まらず読み込めるようにしてきました。今のところ、私の環境では実用的に動いていますが、ほかの環境でも動くかはわかりません。ライブラリは、ほぼ制限のないライセンスにしましたので、必要に応じて手を加えてみてください。

【旧】EDINET XBRL形式の ifrs に関してですが、個々の勘定科目の連結区分が空欄になる場合があります。「.xbrl」のファイルだけでは判定できない仕様のようだったので、そのようにしています。

読み込みを高速化したいとき

2014年以降の新しいEDINET XBRLでは、有報の本文まで載っています。このデータの読み込みをスキップすることで、読み込みが非常に速くなります。特に文章の多い本決算の有報では、所要時間を3分の1くらいにまで短縮できました

高速化の方法ですが、「xbrl_jpcor.py」の「Parserクラス」にある「get_xbrl_datas()メソッド」に、本文などをスキップするコードがあります。そこのコメントアウトを外すことで、データの大きい本文などをスキップするようになります。

    def get_xbrl_datas(self, namespace):
        """データ取得"""
        datas = OrderedDict()
        for element in self.root.findall('.//{%s}*' % namespace):
            # # 本文のテキストブロックは不要なのでスキップ
            # if self.ns_crp:
            #     if self.ns_crp in element.tag:
            #         if 'CoverPage' in element.tag:
            #             # print('skipped %s %s' % (
            #             #     element.tag.split('}')[1], element.text[:20]))
            #             continue
            #         elif 'TextBlock' in element.tag:
            #             # print('skipped %s %s' % (
            #             #     element.tag.split('}')[1], element.text[:20]))
            #             continue

            # # 提出者別タクソノミのテキストブロックは不要なのでスキップ
            # if self.ns_self:
            #     if self.ns_self in element.tag:
            #         if 'CoverPage' in element.tag:
            #             # print('skipped %s %s' % (
            #             #     element.tag.split('}')[1], element.text[:20]))
            #             continue
            #         elif 'TextBlock' in element.tag:
            #             # print('skipped %s %s' % (
            #             #     element.tag.split('}')[1], element.text[:20]))
            #             continue

            # tag名、contextRef、idのタプルをキーにして辞書を作成
            key = (element.tag, element.get('contextRef'), element.get('id'))
            data = OrderedDict()

            # 属性の内容を追加
            data.update(element.attrib)

            # テキストも追加
            data.update({'text': element.text})

            if key in datas:
                if data == datas[key]:
                    # キーも値も同じなのでスキップ
                    continue
                else:
                    print('キー重複 %s' % str(key))

            # リストに追加
            datas.update({key: data})
        return datas

プログラミングの参考になれば幸いです

スポンサーリンク
シェアする(押すとSNS投稿用の『編集ページ』に移動します)
フォローする(RSSフィードに移動します)
スポンサーリンク
シラベルノート
タイトルとURLをコピーしました