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

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

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

金融庁の 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

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

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