投資するための財務分析step2「XBRLファイルをDBに取り込む」

◆はじめに
=========================================
ここでは、財務情報を取得するためのSTEPを紹介します。
今後は取得した財務情報を解析するまでに道筋を追って紹介していく予定です。
最終的には、公開企業の倒産確率を求めたり、独自ファクターを用いた株価予測モデルの構築などを考えています。
関連記事：

* [ロジスティック回帰分析のアルゴリズム導出](http://qiita.com/NaoyaOura/items/6ad5142b0306476d9293)

* [危ない企業がすぐわかるGC注記とは](http://qiita.com/NaoyaOura/items/d04e6392ab6db27ec464)

前step:

* [step1:財務情報XBRLを取得する](http://qiita.com/NaoyaOura/items/4f613525063d0c8d6653)

◆XBRL
=========================================
◇XBRLファイルとは
-----------------------------------------
[WikipediaよりXBRLファイルとは](https://ja.wikipedia.org/wiki/Extensible_Business_Reporting_Language)、eXtensible Business Reporting Language(拡張可能な事業報告言語)の略称です。財務諸表などのビジネスレポートを電子文書化することでそれらの作成の効率化や比較・分析などの二次利用を目的として、XMLの規格をベースに作られた言語を表します。

◇会計にも共通化が必要に。XBRLが社会的に必要になった背景
-----------------------------------------
XBRLファイルという形式で財務諸表を表しはじめた理由は、

* 日本の会計基準を[国際財務報告基準（IFRS）](https://ja.wikipedia.org/wiki/%E5%9B%BD%E9%9A%9B%E8%B2%A1%E5%8B%99%E5%A0%B1%E5%91%8A%E5%9F%BA%E6%BA%96)に共通化（会計用語ではコンバージェンスという）する過程

のうちの１つの取り組みになります
平たくいえば、「日本独自の会計基準にならず、国際統一していこうよ」という施策により始まっているものです

◇XBRLファイルの読み方は次章
-----------------------------------------
これは、次章で細かく細分化していきたいと思います
ひとまず、データを広いあげて何ができるかを本投稿では考えていきます

◆XBRLをDBロードできる形(CSV)へ変換する
===========================================

◇EDINETが提供しているCSV変換アプリ
------------------------------------------
以下、でedinetにてXBRLをCSVに変換するアプリケーションを提供している。
ただし今回は、それを利用するとつまらないのと、CUIの口があるかわからなかったため、pythonで実装しました
<https://disclosure.edinet-fsa.go.jp/download/ESE140131.pdf>

◇事前準備
-----------------------------------------
python にpython-xbrlというpackageをインストールする。
※私はここでやたらと詰まったので、本投稿の最下部にメモしておきます。

```py:事前準備
pip install python-xbrl
```

◇PythonでCSVへデータ変換
-----------------------------------------
以下の記事を参考にPythonでデータを取得するプログラムを作り直しました。

* [EDINETのXBRLファイルから情報抽出](http://qiita.com/shima_x/items/58634a838ab37c3607b5)

上記はPython2系で動くようなアプリですが、3系で動くように変更しています。
その他にも、IRデータベースが作成できるように一括で取得するような定義に変更しています。
主な変更点は以下になります

* 前章で取得したXBRLファイルの全データをCSVへparseするようにロジックを変更
* ラベル情報の取得などは別途マスタ化を行うものとして、XBRLのみをparseするように変更
* ラベル定義は外出しして、取得したいラベルのみ情報を取得できるように変換
* 結果をすべて１ファイルのCSV形式で出力(DBロードしやすくするため)

以下コードでは、前ステップで取得したXBRLファイルを一括でCSVファイルへ変換します。

```py:XBRLファイルをCSVファイルへ変換する
# coding: utf-8
from xbrl import XBRLParser
import os, re, csv
from collections import defaultdict

default_tag = ['file_nm','element_id','amount']
custom_tag = ['unit_ref','decimals','contextref']
encode_type = 'utf-8'

class XbrlParser(XBRLParser):
    def __init__(self, xbrl_filepath):
        self.xbrl_filepath = xbrl_filepath

    def parse_xbrl(self):
        # parse xbrl file
        with open(self.xbrl_filepath,'r',encoding='utf-8') as of:
            xbrl = XBRLParser.parse(of) # beautiful soup type object
        result_dicts = defaultdict(list)
        _idx = 0

        #print xbrl
        name_space = 'jp*'
        for node in xbrl.find_all(name=re.compile(name_space+':*')):
            if self.ignore_pattern(node):
                continue

            row_dict = defaultdict(list)
            #default tag
            row_dict['file_nm'] = self.xbrl_filepath.rsplit('\\' or '/', 1)[1]
            row_dict['element_id'] = node.name
            row_dict['amount'] = node.string

            #cutom tag
            for tag in custom_tag:
                row_dict[tag] = self.get_attrib_value(node,tag)

            result_dicts[_idx] = row_dict
            _idx += 1
        return result_dicts

    def ignore_pattern(self, node):
        if 'xsi:nil' in node.attrs:
            if node.attrs['xsi:nil']=='true':
                return True
        #結果が空の場合は対象外にする
        if not isinstance(node.string, str):
            return True
        # 改行コードが結果にある場合対象外にする
        if str(node.string).find(u'\n') > -1:
            return True
        #text文字列は解析に利用できないため、対象外
        if u'textblock' in str(node.name):
            return True
        return False

    def get_attrib_value(self, node, attrib):
        if attrib in node.attrs.keys():
            return node.attrs[attrib]
        else:
            return None

#ディレクトリ配下のファイルのうちis_xbrl_fileがTrueのもののみ取得する
def fild_all_files(directory):
    for root, dirs, files in os.walk(directory):
        for file in files:
            if not is_xbrl_file(root,file):
                continue
            yield os.path.join(root, file)

def is_xbrl_file(root_path,file_name):
    #xbrlファイルでなければ対象外
    if not file_name.endswith('.xbrl'):
        return False
    #AuditDocは対象外
    if u'AuditDoc' in str(root_path):
        return False
    return True

def dump_file(writer,info_dicts):
    _idx = 0
    while _idx < len(info_dicts):
        row_dict = info_dicts[_idx]
        writer.writerow(row_dict)
        _idx += 1

def main():
    base_path = os.getcwd()+'/xbrl_files'

    #writerオブジェクト生成
    resultCsvWriter = csv.DictWriter(
                            open('eggs.csv', 'w',encoding=encode_type)
                        ,   default_tag + custom_tag
                        ,   lineterminator="\n")
    resultCsvWriter.writeheader()

    #対象ファイルを抽出
    xbrl_files = fild_all_files(base_path)
    count = 0
    for xbrl_file in xbrl_files:
        count += 1
        print ('getting data...'+xbrl_file)
        xp = XbrlParser(xbrl_file)
        info_dicts = xp.parse_xbrl()
        dump_file(resultCsvWriter,info_dicts)

if __name__=='__main__':
    main()
```

◆次回予定：XBRLファイルの中身を解読する（＆タグのマスタ作成）
=========================================================
次回、更新またはソースをリファクタリングした際はストックした方に通知するように致します。


☆【参考】事前準備でつまった方へ
-----------------------------------------
Windows環境でインストール時に詰まったので、そのメモになります。
もし、以下のエラーがでるようであれば、追加で[Microsoft Visual C++のdownload](https://www.visualstudio.com/downloads/download-visual-studio-vs#d-2010-express)が必要


> Microsoft Visual C++ 10.0 is required(Unable to find vcvarsall.bat).

加えて、それでもなお以下のようなエラーがでるようであれば、

> lxml\includes\etree_defs.h(14) : fatal error C1083: include ファイルを開けません。'libxml/xmlversion.h': No such file or directory

```py:事前準備でエラーのとき
pip install lxml
```

私の場合は、それでも同じエラーでダメだったので、以下で実行しました
[※参考](http://stackoverflow.com/questions/20460890/lxml-install-on-windows-7-using-pip-and-python-2-7)

```py:事前準備のエラーが解消しないとき
set STATICBUILD=true && pip install lxml
```

上記を実施することで、なんとか私はpython-xbrlのインストールができました。