【Python】XBRL から『勘定科目の金額や文章』を取得するコード例【Arelle】

XBRL 読み込みライブラリの Arelle アレル を使用して、『勘定科目の金額や文章(ファクト、fact)』を取得する Python コード例です。

Arelle を使用したら、簡単なコードでデータを取得することができました。

勘定科目の金額に加えて、『日付』や『日本語ラベル』などの情報も、一緒に取得することができました。

自分が Arelle を使った時に『気づいた点』と『Python コード例』を紹介します。

Arelle のインストール方法は、『Arelle のインストール方法』に書きました。

Arelle の『終了日』と『時点(期末日)』が『翌日の日付』になっていた

Arelle のもどから日付を取得したところ、以下の日付が『翌日の日付』になっていました。

  • fact.context.endDatetime:終了日
  • fact.context.instantDatetime:時点(期末日)

XBRL ファイルには 2020-05-31 と書いてあったのに、Arelle で見ると 2020-06-01 になっていたりして気づきました。

Arelle の解釈ではなくて、『XBRL 報告書インスタンスのファイル』に書かれている通りの日付を取得するときは、以下の属性を使うとできました。

  • fact.propertyView 属性
  • fact.context.propertyView 属性

もう1つ、気づいた点がありました。

『instant 時点(期末日)』を表している日付なのに、Arelle は『終了日』にも『instant 時点(期末日)』の日付を設定していました。

これらの件については、『ModelInstanceObject.py』⇒『class ModelContext(ModelObject):』にも、その様にしている旨の説明がありました。

@property
def endDatetime(self):
    """(datetime) -- endDate or instant attribute,
        with adjustment to end-of-day midnight as needed"""

@property
def instantDatetime(self):
    """(datetime) -- instant attribute,
        with adjustment to end-of-day midnight as needed"""

これらを見るに、Arelle は必要に応じて『endDate 終了日』と『instant 時点(期末日)』を、それぞれ『その日の終わりのミッドナイト (24 時)』に調整しているようでした。

つまり、『翌日の 0 時』に調整する、ということだと思います。

『endDatetime』については、『endDate or instant attribute』になる旨も書いてありますね。

公式サイトの資料にも、同じような説明がありました。

arelle®DocumentationArchitecture, Overview で公開されていた『Enabling Comparability and Data Mining with the Arelle® Open Source Unified Model』という PDFです。

ModelInstanceObject.py

(中略)

endDatetimeDatetime value of end or instant, with adjustment to next day midnight as needed
instantDatetimeDatetime value of instant, with adjustment to next day midnight as needed

日付調整の意図については、ちょっと分かりませんでした。

(追記)XBRL の仕様書を見たら、『ISO 8601 syntax』のために行っている処理(定義)である旨が書かれていました。

A date, with no time part, in the endDate or instant element is defined to be equivalent to specifying a dateTime of the same date plus P1D and with a time part of T00:00:00. This represents midnight at the end of the day. The reason for defining it thus, i.e. as midnight at the start of the next day, is that [XML Schema Datatypes] mandates this representation by prohibiting the value of 24 in the “hours” part of a time specification, which is ISO 8601 syntax.

Extensible Business Reporting Language (XBRL) 2.1 – The <period> element (2020年11月6日 閲覧)

自分の Python コード例では、Arelle が調整した日付を取得しました。

ですが、データ分析の内容によっては、『fact.propertyView 属性』や『fact.context.propertyView 属性』の中の日付を使用したほうが良いかもしれません。

コード例

Arelle を使用して、XBRL からデータを取得する Python コード例です。

『勘定科目や文章(ファクト、fact)』のデータを取得して、リスト入れてみました。

"""
main_facts.py
Arelle を使用して XBRL から『fact』のリストを取得する
Python コード例です。
"""

import sys
sys.path.append(r'F:\project\kabu\Arelle')
from Arelle.arelle import Cntlr

def main():
    """メイン関数"""
    # (準備 1/4) XBRL の zip を決めます。
    # (例) カネコ種苗株式会社 1376 / E00004
    #      有価証券報告書-第73期(令和1年6月1日-令和2年5月31日)
    #      開示日: 2020/8/28 12:55
    #      書類管理番号: S100JKNH
    xbrl_zip = r'F:\project\kabu\download\S100JKNH.zip'

    # (準備 2/4) zip の中の『報告書インスタンス』のパスをくっつけます。
    xbrl_file = xbrl_zip + r'\S100JKNH\XBRL\PublicDoc\jpcrp030000-asr-001_E00004-000_2020-05-31_01_2020-08-28.xbrl'

    # (準備 3/4) Arelle のコントローラーを取得します。
    # 'logToPrint' とは、Arelle のログを標準出力(stdout)に出す、という意味でした。
    # (出典) Cntlr.py にある class LogToPrintHandler(logging.Handler) の docstring。
    ctrl = Cntlr.Cntlr(logFileName='logToPrint')

    try:
        # (準備 4/4) XBRL ファイルを読み込みます。
        model_xbrl = ctrl.modelManager.load(xbrl_file)
        try:
            # ヘッダを決めます。
            head = [
                '名前空間',
                '日本語', '英語',
                '接頭辞', 'タグ', 'ファクトID',
                '値', '単位', '貸借',
                '開始日', '終了日', '時点(期末日)',
                'コンテキストID', 'シナリオ',
                ]

            # fact を入れるリストを作ります。
            fact_datas = [head]

            # すべての fact からデータを取得していきます。
            for fact in model_xbrl.facts:
                # (ファクト fact の例) <jppfs_cor:NetSales
                #   contextRef="CurrentYearDuration"
                #   unitRef="JPY"
                #   decimals="-3">58179890000</jppfs_cor:NetSales>

                # (1/7) 日本語ラベルを取得します。
                # (例) '売上高'
                label_ja = fact.concept.label(preferredLabel=None, lang='ja', linkroleHint=None)

                # (2/7) 英語ラベルを取得します。
                # (例) 'Net sales'
                label_en = fact.concept.label(preferredLabel=None, lang='en', linkroleHint=None)

                # (3/7) タグの値を取得します。(勘定科目の金額や文章など)
                # (例) Decimal('58179890000')
                x_value = fact.xValue

                # (参考) タグの素(す)の値は、.text から取得できました。
                # tag_value = fact.text

                # # (デバッグ) Excel や LibreOffice Calc などで見るために、
                # # 長い文字列を 100 文字で切り捨てて、改行も削除するコード。
                # if isinstance(x_value, str):
                #     x_value = x_value[:100].replace('\n', ' ')

                # (4/7) 単位を取得します。
                if fact.unit is None:
                    unit = None
                else:
                    # .unit の.value とは、複雑な分数形式の単位などを、
                    # Arelle が人の見やすい形式に整えた文字列でした。
                    # (例) 'JPY / shares'
                    unit = fact.unit.value

                # (5/7) 開始日、終了日、時点(期末日) の日付を取得します。
                if fact.context.startDatetime:
                    # 開始日
                    # (例) datetime.datetime(2019, 6, 1, 0, 0)
                    start_date = fact.context.startDatetime
                else:
                    start_date = None

                if fact.context.endDatetime:
                    # 終了日
                    # (例) datetime.datetime(2020, 6, 1, 0, 0)
                    # ※ (注意)
                    # ・1日分だけ加算された日付になっていました。
                    # ・また、開始日が無い時でも『instance 時点 (期末日) 』の
                    #   日付が設定されました。
                    #
                    # XBRL ファイルに書かれているのと同じ日付の
                    # 『終了日』を取得するときは、
                    # 『fact.propertyView 属性』や
                    # 『fact.context.propertyView 属性』の中から
                    # 取得することができました。
                    end_date = fact.context.endDatetime
                else:
                    end_date = None

                if fact.context.instantDatetime:
                    # 時点 (期末日)
                    # (例) datetime.datetime(2020, 8, 29, 0, 0)
                    # ※ (注意)
                    # ・1日分だけ加算された日付になっていました。
                    # 
                    # XBRL ファイルに書かれているのと同じ日付の
                    # 『時点 (期末日)』を取得するときは、
                    # 『fact.propertyView 属性』や
                    # 『fact.context.propertyView 属性』の中から
                    # 取得することができました。
                    instant_date = fact.context.instantDatetime
                else:
                    instant_date = None

                # (6/7) シナリオ (scenario) を取得します。
                scenario_datas = []
                for (dimension, dim_value) in fact.context.scenDimValues.items():
                    # fact.context.scenDimValues の型は、普通の dict 型でした。
                    # dimension は ModelConcept 型でした。
                    # dim_value は ModelDimensionValue 型でした。
                    # dim_value.member は ModelConcept 型でした。
                    scenario_datas.append([
                        dimension.label(preferredLabel=None, lang='ja', linkroleHint=None),
                        dimension.id,
                        dim_value.member.label(preferredLabel=None, lang='ja', linkroleHint=None),
                        dim_value.member.id,
                        ])
                if len(scenario_datas) == 0:
                    scenario_datas = None

                # (7/7) リストに追加します。
                fact_datas.append([
                    fact.namespaceURI, # (例) 'http://disclosure.edinet-fsa.go.jp/taxonomy/jppfs/2019-11-01/jppfs_cor'
                    label_ja, # (例) '売上高'
                    label_en, # (例) 'Net sales'
                    fact.prefix, # (例) 'jppfs_cor'
                    fact.localName, # (例) 'NetSales'
                    fact.id, # (例) 'IdFact1707927900' (id は footnoteLink を参照するときに使いました)
                    x_value, # (例) Decimal('58179890000') (値は Decimal, int, None, str 型など色々でした)
                    unit, # (例) 'JPY'
                    fact.concept.balance, # (例) 'credit'
                    start_date, # (例) datetime.datetime(2019, 6, 1, 0, 0)
                    end_date, # (例) datetime.datetime(2020, 6, 1, 0, 0) (1日加算された日付になっていました)
                    instant_date, # (例) datetime.datetime(2020, 8, 29, 0, 0) (1日加算された日付になっていました)
                    fact.contextID, # (例) 'CurrentYearDuration'
                    scenario_datas, # (例) "[[
                                    #   '連結個別',
                                    #   'jppfs_cor_ConsolidatedOrNonConsolidatedAxis',
                                    #   '非連結又は個別',
                                    #   'jppfs_cor_NonConsolidatedMember',
                                    #  ],
                                    #  [
                                    #   '事業セグメント',
                                    #   'jpcrp_cor_OperatingSegmentsAxis',
                                    #   '種苗事業',
                                    #   'jpcrp030000-asr_E00004-000_SeedsAndSeedlingsReportableSegmentsMember',
                                    #  ]]"
                ])
        finally:
            # modelXbrl を閉じます。
            # (出典) ModelManager.py
            ctrl.modelManager.close()
    finally:
        # Arelle のコントローラーを閉じます。
        # (出典) Cntlr.py
        ctrl.close()

    # あとは、作ったリストを csv や SQLite DB などに出力したり、
    # pandas.DataFrame などに変換したりして、分析していきます。

    # 以上です。
    return


if __name__ == '__main__':
    main()

実行結果

XBRL から取得した『勘定科目や文章(ファクト、fact)』のリストです。

Visual Studio Code のウォッチ式のスクリーンショットを撮りました。

『売上高』の取得例です。

『1株当たり純資産額』の取得例です。

『研究開発費』の取得例です。

シナリオに事業セグメントを区別するための情報入っています。

『利益剰余金』の取得例です。

シナリオに『非連結(個別)』を表す情報が入っています。

Arelle を使用したことで、短い Python コードだけで、データを取得できるようになりました。

リンクベースの内容も取得するコード例を書きました。

XBRL から『勘定科目』と『リンクベース』の内容を取得するコード例【Arelle】

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