EDINETコードと証券番号をマッピングしたい

#1 この記事はなに？

ある企業の有価証券報告書をダウンロードしたいとします。
その企業が提出した有価証券報告書のEDINETコードが分かれば、EDINET APIからXBRL形式で書かれた有価証券報告書を入手できます。XBRL形式の有価証証券報告書はブラウザで閲覧することができます。XBRLファイルが入手できれば、例えば数百社の自己資本比率をスクレイピング技術を使い自動取得するといったことも可能です。しかしながら、証券番号とEDINETをマッピングした情報がネット上に公開されてないので、それらをマッピングするコードを作りました。

ちなみにXBRLが何かは[こちらにわかりやすく解説されています。](https://qiita.com/XBRLJapan/items/cd6af5bff5f6ae11d774)


#2 EDINET CODEと証券番号のマッピング方法



<b>処理の流れ</b>
<img width="875" alt="99.JPG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150223/550c67b0-d906-0f6e-1f7b-981160b5414b.jpeg">



###2-1 「証券番号」と「会社名」のマッピング表を取得する。

[こちらのサイト(日本取引所グループ)](https://www.jpx.co.jp/markets/statistics-equities/misc/01.html)から東証に上場している企業の証券番号一覧表をcsvファイル形式でダウンロードします。この作業は手動で行ってください。

###2-2 「EDINET CODE」と「会社名」のマッピング表を取得する。

EDINETコードは有価証券報告書に紐づけされています。つまり、同じ会社であっても年度の違う有価証券報告書には違うEDINETコードが割り当てられています。また<b>EDINET APIは、ある日にちに提出された有価証券報告書が取得できる仕様</b>になっています。よって本日から過去1年前までさかのぼり1日ごとに提出された「EDINET CODE」と「会社名」を取得できれば、全上場企業の「EDINET CODE」と「会社名」のマッピング表を作れます。

###2-3  「証券番号」と「EDINET CODE」と「会社名」のマッピング表を取得する。


<b>「証券番号」と「会社名」のマッピング表 </b> と <b>EDINET」と「会社名」のマッピング表</b>より「会社名」をキーにして前述２つのマッピング表をマージして「証券番号」と「会社名」と「EDINET CODE」のマッピング表を生成します。




#3 コードの掲載

下記に上記で説明した「証券番号」と「EDINET CODE」と「会社名」のマッピングを行うpythonコードを掲載します。

<b>コードを実行する前に下記定数の条件設定を行ってください</b>
・START_DATE 有価証券報告書を提出した企業のデータを収集する日時開始日を設定する
・END_DATE　 #有価証券報告書を提出した企業のデータを収集する日時終了日を設定する
・FPATH='「証券番号」と「企業名」のマッピング表csvファイルのpathをここに記入する。' 
・SPATH='「EDINET CODE」と「企業名」のマッピング表csvファイルを格納するpathをここに記入する。'
・OPATH='成果物(「証券番号」と「企業名」と「EDINET CODE」のマッピング表)csvファイルを格納するpathをここに記入する。'



```python:test.py


# -*- coding: utf-8 -*-
import requests
import datetime
import time
import pandas as pd
import os.path
import math
import numpy as np

#クラスの定義
class YUHO_GET():

    #コンストラクタ・・ここでは変数の読み込みを行う。
    def __init__(self,start_date, end_date,spath,fpath,sel):
        
        
        self.start_date=start_date
        self.end_date=end_date
        self.spath=spath
        self.fpath=fpath
        self.sel=sel
        
    
        
    #日付ごとに有価証券報告書の会社名、時期、EDIETコードを取得する。 
    def mainproc(self):

        day_list = self.make_day_list() #日付開始と終了を指定すると、その間の日付を生成する関数

        securities_report_doc_list = self.make_doc_id_list(day_list) #日付ごとに有価証券報告書の会社名、時期、EDIETコードを取得する。
        number_of_lists = len(securities_report_doc_list)
        print("number_of_lists：", len(securities_report_doc_list))
        print("get_list：", securities_report_doc_list)
       
        
    #日付開始と終了を指定すると、その間の日付を生成する関数
    def make_day_list(self):
        print("start_date：", self.start_date)
        print("end_day：", self.end_date)

        period = self.end_date - self.start_date
        period = int(period.days)
        day_list = []
        for d in range(period):
            day = self.start_date + datetime.timedelta(days=d)
            day_list.append(day)

        day_list.append(self.end_date)

        return day_list

    #日付ごとに有価証券報告書の会社名、EDIETコードを取得する。
    def make_doc_id_list(self,day_list):
        securities_yuho_list = []
        securities_4hanki_list = []
        com_edi=[]
        for index, day in enumerate(day_list):
            url = "https://disclosure.edinet-fsa.go.jp/api/v1/documents.json"
            params = {"date": day, "type": 2}

            proxies = {
                "http_proxy": "http://username:password@proxy.example.com:8080",
                "https_proxy": "https://username:password@proxy.example.com:8080"
            }
            #EDINET APIにアクセスし、指定した日付にて提出された書類の種類を取得している。
            res = requests.get(url, params=params, proxies=proxies)
            json_data = res.json()
            print(day)

            for num in range(len(json_data["results"])):
                #EDINET APIから返却された書類の種類の情報を取得している。
                ordinance_code = json_data["results"][num]["ordinanceCode"]
                form_code = json_data["results"][num]["formCode"]

                 #有価証券報告書であれば、「ordinance_code == "010" and form_code == "030000"」は有価証券報告書を指している。
                if ordinance_code == "010" and form_code == "030000":
                    print('★★★★★★★★★★★★ 有価証券報告書★★★★★★★★★★★★★★★')                    
                    #会社名をcomnameに格納する
                    comname=json_data["results"][num]["filerName"]
                    #comnameから"株式会社"を削除する。前株と後株に対応している。
                    comname=comname.split('株式会社')[0] if comname.split('株式会社')[0] != '' else comname.split('株式会社')[-1]
                    #comnameに空白がある場合は削除する
                    comname=comname.split('　')[-1] if comname.split('　')[0]=='' else comname
                    
                    com_edi={ '会社名':comname,
                              '時期':json_data["results"][num]["docDescription"],           
                              'EDINET':json_data["results"][num]["docID"],
                             '提出日':day
                         }
                    

                    securities_yuho_list.append(com_edi)
                    
                                        
            securities_report=securities_yuho_list if self.sel==0 else securities_4hanki_list
            securities_report=pd.DataFrame(securities_report,columns=['会社名','時期','EDINET','提出日'])
            securities_report.to_csv(self.spath)
            
            
                    
        return securities_report                


        
        
    #EDINETと証券番号をマッピングする関数    
    def edinet_syoken_mapping(self):
        df_all_syokennum = pd.read_csv(self.fpath) #東証に上場しているすべての銘柄の証券番号を取得する。
        df_all_editnum = pd.read_csv(self.spath) #会社名,EDINETコードを読み込む       
        df_edi_syo=df_all_editnum.loc[:,['会社名','EDINET']]
        df_edi_syo=pd.DataFrame(df_edi_syo,columns=['会社名','EDINET','コード'])                                                     
        df_syoken=df_all_syokennum.loc[:,['コード','会社名']]
              
  
        for i in range(len(df_edi_syo)): 
            #(3)「会社名」,「証券番号」表と「会社名」「EDINETコード」表から「会社名」「証券番号」「EDINETコード」のマッピング表を得る。
            code=self.get_syouken_num(df_syoken,df_edi_syo.iloc[i]['会社名'])            
            df_edi_syo['コード'][i]=code

        #証券番号に".0"が付与されるので".0"を削除する。
        
        df_edi_syo.set_index("コード",inplace=True)     
        df_edi_syo.to_csv(OPATH)
        df_edi_syo = pd.read_csv(OPATH, index_col=0)
        df_edi_syo.reset_index("コード",inplace=True)        
        df_edi_syo['コード'] = df_edi_syo.apply(lambda x:self.bunri(x),axis=1)
        df_edi_syo.set_index("コード",inplace=True)
        
        #df_edi_syoをcsvファイルに書き出す。
        #print(df_edi_syo)
        df_edi_syo.to_csv(OPATH)
        
    
    #整数部と小数部を分離する関数
    def bunri(self,x):
        return x.コード.split(".")[0]
        
        
    #(3)会社名から証券番号を取得する。
    def get_syouken_num(self,df,company_name):
        flag=0
       
        try:
            df1=df[df.会社名==str(company_name)]
            meigara_num=df1.iloc[0][0].astype(str)
            
            return  meigara_num
        #会社名と証券番号がマッピングできなかったときは、NONEを返す。
        except Exception as e:
            flag='NONE'
            return flag
        
        
##################   MAIN ##################            
            
START_DATE= datetime.date(2019,8,7) #有価証券報告書を提出した企業のデータを収集する日時開始日を設定してください。
END_DATE= datetime.date(2020,8,6)   #有価証券報告書を提出した企業のデータを収集する日時終了日を設定してください。

SEL=0 # SEL=0:有価証券報告書の取得を行う。


FPATH='「証券番号」と「企業名」のマッピング表csvファイルのpathをここに記入する。' 
SPATH='「EDINET CODE」と「企業名」のマッピング表csvファイルを格納するpathをここに記入する。'
OPATH='成果物(「証券番号」と「企業名」と「EDINET CODE」のマッピング表)csvファイルを格納するpathをここに記入する。'

def main():

    yuho=YUHO_GET(START_DATE,END_DATE,SPATH,FPATH,SEL) #(1)インスタンスを生成する。パラメータをセットする。
    yuho.mainproc() #(2)有価証券報告書を提出した企業名とEDINETを抽出する 
    yuho.edinet_syoken_mapping() #(3)証券番号とEDINET番号のマッピングを行う。
    
 
if __name__ == "__main__":
    main()

```