最新のEDINETタクソノミをBeautifulSoupで処理して、標準科目ラベルのマスタを作成する

XBRLJapanのメンバーKです。

昨年「[Beautiful SoupでEDINETのXBRLから財務諸表のデータベースを構築する][2]」という記事を投稿しました。その記事では、データベースを構築するにあたり、各財務諸表科目の日本語ラベルを別ファイルに保存したマスタ（以下、「標準科目ラベルマスタ」とします。）から読み込んでいました。

この標準科目ラベルマスタの元データは金融庁で公表しているEDINETタクソノミです。そして、このEDINETタクソノミは、法令や会計基準の改正等に対応するため、毎年公表されています。

今回の記事は、標準科目ラベルマスタを各自で更新いただけるよう、EDINETタクソノミから標準科目ラベルマスタを作成する手順を紹介します。

# 対象読者

昨年 [こちらの記事][1] で、Webスクレイピングで有名なBeautifulSoupを使用して、有価証券報告書等のXBRLデータからデータフレームを作成する方法を記載しました。

今回の記事は、上記記事で利用した標準科目ラベルマスタの更新に関する記事ですので、上記記事の内容を前提にしていることをご留意ください。

（上記記事のうち、2021-07-18 22:39のコメント欄に記載しました [Github][2] のコードを前提にしています。）



# 手順

1. 金融庁HPから最新EDINETタクソノミをダウンロード・解凍
1. EDINETタクソノミから科目ラベルを取得しデータフレームに変換
1. 既存標準科目ラベルマスタに結合

### 1. 金融庁HPから最新EDINETタクソノミをダウンロード・解凍

EDINETタクソノミは金融庁HPからダウンロードできます。

2022年版EDINETタクソノミの公表について
>https://www.fsa.go.jp/search/20211109.html

毎年公表されるので、Google検索などで「〇〇年　EDIENTタクソノミ」と検索するとヒットします。

例年11月上旬に、翌年3月31日以後に終了する有価証券報告書のタクソノミが公開されるようです。

ページ中ほどに、`EDINETタクソノミ本体`というリンクがありますので、そちらからダウンロードしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500494/7548f53e-8a56-82b5-6149-27f7644603b7.png)
ダウンロードした後は、zipファイルを解凍してください。


### 2. EDINETタクソノミから科目ラベルを取得しデータフレームに変換

以下の関数を使って、EDINETタクソノミの標準科目ラベルを定義した`.xml`ファイルから標準科目ラベルマスタ用のデータフレームを作成します。

```python
import re
import pandas as pd
from bs4 import BeautifulSoup

def get_global_label(arg_path):
    '''
    金融庁が公開しているEDINETタクソノミから、XBRLタグ名と日本語ラベルの対応関係を示す、日本語ラベルマスタを作成する関数
    引数(arg_path)：*_lab.xmlのファイルパス
    '''
    # labファイルの読み込み
    with open(arg_path, encoding='utf-8') as f:
        soup = BeautifulSoup(f.read(), 'lxml')

    # link:locタグのみ抽出
    link_loc = soup.find_all('link:loc')

    # link:locタグの取得結果をdictにし、dictを格納するカラのリストを作成
    list_locator = []

    # link:locタグの情報をループ処理で取得
    for each_loc in link_loc:
        dict_locator = {}
        shema = each_loc.get('xlink:href').split(sep='#')[0]
        dict_locator['xmlns_jpcrp_ymd'] = re.findall(r'\d{4}-\d{2}-\d{2}', shema)[0]
        dict_locator['xlink_href'] = each_loc.get('xlink:href')
        dict_locator['shema'] = shema
        dict_locator['label_for_join'] = each_loc.get('xlink:href').split(sep='#')[1]
        dict_locator['loc_label'] = each_loc.get('xlink:label')
        list_locator.append(dict_locator)

    # link:locタグの取得結果をDFに    
    df_locator = pd.DataFrame(list_locator)

    # link:labelArcタグのみ抽出
    link_arc = soup.find_all('link:labelarc')

    # link:labelArcタグの取得結果をdictにし、dictを格納するカラのリストを作成
    list_arc = []

    # link:labelArcタグの情報をループ処理で取得
    for each_arc in link_arc:
        dict_arc = {}
        dict_arc['arc_role'] = each_arc.get('xlink:arcrole')
        dict_arc['loc_label'] = each_arc.get('xlink:from')
        dict_arc['xlink_label'] = each_arc.get('xlink:to')
        list_arc.append(dict_arc)

    # link:labelArcタグの取得結果をDFに    
    df_arc = pd.DataFrame(list_arc)

    # link:labelタグのみ抽出
    link_label = soup.find_all('link:label')

    # link:labelタグの取得結果をdictにし、dictを格納するカラのリストを作成
    list_label = []

    # link:labelタグの情報をループ処理で取得
    for each_label in link_label:
        dict_label = {}
        dict_label['xlink_label'] = each_label.get('xlink:label')
        dict_label['xlink_role'] = each_label.get('xlink:role')
        dict_label['xml_lang'] = each_label.get('xml:lang')
        dict_label['label_text'] = each_label.text
        list_label.append(dict_label)

    # link:labelタグの取得結果をDFに    
    df_label = pd.DataFrame(list_label)

    # locとarcの結合
    df_merged = pd.merge(df_locator, df_arc, on='loc_label', how='inner')
    # loc, arcとlabelの結合
    df_merged = pd.merge(df_merged, df_label, on='xlink_label', how='inner')

    return df_merged

```

上記関数の引数である`arg_path`には、解凍したEDINETタクソノミのzipファイル内の`*_lab.xml`ファイルのパスを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500494/5f131bb7-4268-4dcc-032d-bd9ef3609eea.png)

実際には、`glob()`を使ってファイルパスを検索するといいでしょう。

```python
import glob

########## タクソノミファイルのファイルパスを指定 ##########
path_taxonomy = 'タクソノミのzipファイルを解凍したファイルパスを指定してください。パスの最後に/を忘れないでください'

# 各labファイルのパスを格納するリストの定義
list_path_taxonomy = []

# 各labファイルの検索
list_path_taxonomy.extend(glob.glob(path_taxonomy + '**/jpcrp/**/label/**_lab.xml', recursive=True)) # 日本基準用タクソノミ
list_path_taxonomy.extend(glob.glob(path_taxonomy + '**/jppfs/**/label/**_lab.xml', recursive=True)) # IFRS用タクソノミ
list_path_taxonomy.extend(glob.glob(path_taxonomy + '**/jpigp/**/label/**_lab.xml', recursive=True)) # 米国基準用タクソノミ

```

### 3. 既存標準科目ラベルマスタに結合

各有価証券報告書のXBRL内には、いつの年度のEDINETタクソノミを使用するか指定があります。

そのため、最新のタクソノミを標準科目ラベルマスタに登録すればよいわけではなく、過去の標準科目ラベルマスタに最新のタクソノミを追加する必要があります。

これを実現するために、`taxonomy_global_label.tsv`の末尾にDFを追記するとよいでしょう。

```python
########## taxonomy_global_label.tsvが保存されているパスを指定 ##########
path_global_label = 'taxonomy_global_label.tsvが保存されているファイルパスを指定してください'

# 既存ファイル（taxonomy_global_label.tsv）の末尾に最新マスタを追記
df_global_label.to_csv(path_global_label, sep ='\t', encoding='UTF-8', mode='a', header=False, index=False)

```

# まとめ

全体の処理をまとめたコードを [Github][2] にUploadしました。

ファイル名は、`90_update_global_label.py`です。

よろしければ、そちらもご覧ください。

※ 同 Github のリポジトリ内にある`taxonomy_global_label.tsv`には、2022年版EDINETタクソノミは反映済みです。


# 問合せ先
本記事に関する問い合わせは、以下のメールアドレスまでお願いします。
e-mail：xbrl-tech-qa@xbrl.or.jp
（もちろん、qiita上でのコメントも歓迎します）

本メールアドレスは、qiitaの記事を執筆しているXBRLJapanの開発委員会の問合せ窓口になります。
そのため、組織に関する一般的な問合せなどは内容によって回答できかねますが、XBRLに関する技術的な質問、意見、要望、助言等はお気軽にご連絡ください。
なお、委員会メンバが有志で対応しているため、回答に時間がかかることもありますが、ご了承ください。

[1]:https://qiita.com/XBRLJapan/items/d23bc251c53d81d49852
[2]:https://github.com/sat128/xbrl_bs4/tree/feature01