見出し画像

上場企業のリストを取得するために、EDINETコードリストをPythonで自動取得する

久しぶりの投稿になります。最近はWEBアプリケーションを作る機会が少し減ってしまいましたが、プライベート面でいろんな物を作っては潰してを繰り返していました。

ここ最近はフィナンシャル(金融)系の勉強をしており、株価や企業の財務などの分析をPythonで自動的にやるようなものを作っていたりします。

今回は企業の財務分析を自動でやるための過程で作ったPythonのコードを紹介していきます。

今回やること

企業には財政状態や経営成績を表した損益計算書、貸借対照表、キャッシュフロー計算書という主に3つの財務諸表があります。企業の財務分析をするためにはこれら3つの財務諸表を入手しなくてはいけません。

日本にある全上場企業には財務諸表を公開する義務があります。全上場企業には証券コードという5桁の数字が割り振られており、それらのリストは金融庁が運営するEDINETというサイトで公開されています。

今回は金融庁のEDINETから法人リストを自動で取得してcsvに変換するPythonコードを作成します。

EDINETとは

EDINETとは金融庁の管轄にある電子情報開示システムです。主に企業やファンド、法人などが決算書を提出する際、株式の大量所有報告書などの何か大きな報告ごとがある度にEDINETに登録する義務があります。

EDINETでは開示文書をWEB上で誰でも取得できるようになっています。

上場企業であれば必ずここに全ての開示資料を提出する必要がありますが、全ての法人がそれをやる必要が無いため、非上場企業などの全ての法人がEDINETに資料があるわけではありません。

EDINETコードリスト

EDINETで取得できる開示情報の法人リストは以下のリンクから取得できます。

https://disclosure.edinet-fsa.go.jp/E01EW/BLMainController.jsp?uji.verb=W1E62071InitDisplay&uji.bean=ee.bean.W1E62071.EEW1E62071Bean&TID=W1E62071&PID=currentPage&SESSIONKEY=1624182893757&downloadFileName=&lgKbn=2&dflg=0&iflg=0

リンクを開くと一番下の方に行くと以下のように二つのファイルがダウンロードできるようになっています。今回はEDINETコードリストをダウンロードします。

スクリーンショット 2021-06-20 18.53.30

ダウンロードすると、Edinetcode_20210620.zipといったような日付をファイル名に足したzip形式のファイルがダウンロードされます。

EDINETコードリストのファイルを解凍する

ファイルをunzipコマンドで解凍すると、EdinetcodeDlInfo.csvというファイルが出てきます。

$ ls
Edinetcode_20210620.zip

$ unzip Edinetcode_20210620.zip
Archive:  Edinetcode_20210620.zip
 inflating: EdinetcodeDlInfo.csv
 
$ ls
EdinetcodeDlInfo.csv    Edinetcode_20210620.zip

EdinetcodeDlInfo.csvというファイルの問題点

ここまで普通にダウンロードしてファイルを解凍してcsvが取得できたわけですが、このcsvファイルは非常に残念な形式になっています。

まずは以下のfileコマンドで文字コードを調べてみると、Shift-JISであることが確認できます。

$ file EdinetcodeDlInfo.csv
EdinetcodeDlInfo.csv: Non-ISO extended-ASCII text, with very long lines, with CRLF, NEL line terminators

Windowsを前提とした文字コードであるため、MacやLinuxtで扱うためにもできればutf-8にしたい所です。

次にこれが一番ひどいと思いましたが、このEdinetcodeDlInfo.csvの中身を見てみると、1行目と2行目のカラム数が違ってずれています。

スクリーンショット 2021-06-20 19.16.00

これをpandasなどでそのまま読み込めば表記がおかしくなります。

なんというか全体的に見てセンスというか流石はお役所のクオリティだなと感心してしまいました。(ファイル名にも付いているのに、ダウンロード実行日いらないのでは...?)

自動でダウンロードするPythonコードを作成する

それでは今回の本題である、実行するとEDINETコードリストのCSVファイルを取得するPythonコードを作成していきます。

実行すると以下の二つの条件持ったファイルを出力させます。

・文字コードをutf-8に変換
・1行目のカラムを削除する

必要なライブラリをインストールする

EDINETからファイルをダウンロードするには、スクレイピング などで使われるrequestsなどが必要ですが、今回はseleniumを使います。

リンクをクリックすると実態としてはjsを実行しているため、それに最適なseleniumを使います。また詳細の説明は省きますが、webdriver_managerというライブラリも入れる必要があります。

$ pip install selenium webdriver_manager

実際にEDINETからダウンロードする

まずはEDINETからEDINETコードリストのファイルをダウンロードしてみます。

以下のコードはseleniumで実際にEDINETコードリストを取得している処理になります。EDINETのサイトで「EDINETコードリスト」をクリックしているのと同じ状態になります。

import time

from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager


def edinet_code_dl():
    # seleniumでchromeからzipファイルをダウンロード
    chromeOptions = webdriver.ChromeOptions()
    chromeOptions.add_experimental_option(
        "prefs",
        {"download.default_directory": "./"},
        # 保存先のディレクトリの指定
    )

    # ブラウザ非表示
    chromeOptions.add_argument("--headless")

    url = "https://disclosure.edinet-fsa.go.jp/E01EW/BLMainController.jsp"
    url += "?uji.bean=ee.bean.W1E62071.EEW1E62071Bean&uji.verb"
    url += "=W1E62071InitDisplay&TID=W1E62071&"
    url += "PID=W0EZ0001&SESSIONKEY=&lgKbn=2&dflg=0&iflg=0"

    driver = webdriver.Chrome(
        ChromeDriverManager().install(),
        options=chromeOptions,
    )
    driver.maximize_window()

    # EDINETのEDINETコードリストにアクセス
    driver.get(url)
    driver.execute_script(
        "EEW1E62071EdinetCodeListDownloadAction('lgKbn=2&dflg=0&iflg=0&dispKbn=1');"
    )
    time.sleep(5)
    driver.quit()

# EDINETコードリストをダウンロードする.
edinet_code_dl()
   

上記を実行すると以下のようにzipファイルがダウンロードできていると思います。

$ python edinet_code_dl_info.py


====== WebDriver manager ======
Current google-chrome version is 91.0.4472
Get LATEST driver version for 91.0.4472

$ ls
Edinetcode_20210620.zip

zipファイルを解凍するコードを作成する

次に上記でダウンロードしたEdinetcode_20210620.zipを解凍するPythonコードを作成していきます。

下記では同ディレクトリ上にある最新のzipファイルを解凍して、その後にzipファイルを削除する処理を入れています。

必要なライブラリとしてはPythonで標準で入っているzipfileというものを使用します。

import os
import glob
import zipfile

def unzip_edinet_code_dl_info():
    # ダウンロードしたzipファイルのパスを取得
    # ディレクトリのリストを取得する.
    # ワイルドカードを追加
    list_of_files = glob.glob("./" + r"/*")

    # 作成日時が最新のファイルパスを取得
    latest_file = max(list_of_files, key=os.path.getctime)

    # zipファイルを同じディレクトリに展開
    zip_f = zipfile.ZipFile(latest_file)
    zip_f.extractall("./")
    zip_f.close()

    # zipファイルを削除
    os.remove(latest_file)

    list_of_files = glob.glob("./" + r"/*")  # ワイルドカードを追加
    csv_filepath = max(list_of_files, key=os.path.getctime)

    return csv_filepath

関数で最後にcsv_filepathというのを返しています。関数から返ってくるのは./EdinetcodeDlInfo.csvという文字列のはずです。

$ ls
EdinetcodeDlInfo.csv​

実際にEdinetcodeDlInfo.csv​が生成されていて、zipファイルは削除されているはずです。

解凍して出てきたcsvファイルの文字コードをutf-8に変換する

上記で生成したEdinetcodeDlInfo.csvはまだShift-JISのままなので、こちらをUTF-8に変換します。

EdinetcodeDlInfo_utf8.csvというutf-8形式のファイルができるはずです。これでmacやlinuxでも読み込めるようにファイルとしては扱いやすくなります。

# EdinetcodeDlInfo.csvを取得
csv_filepath = unzip_edinet_code_dl_info()
print(csv_filepath)

cp932_file = open(csv_filepath, "r", encoding="cp932")
cp932_file_list = [row for row in cp932_file]

# 一番最初の行である不要なカラムを削除する
del cp932_file_list[0]

utf8_file_name = "EdinetcodeDlInfo_utf8.csv"
utf8_file = open(utf8_file_name, "w", encoding="utf-8")

for row in cp932_file_list:
   utf8_file.write(row)

cp932_file.close()
utf8_file.close()

実際にfileコマンドでutf-8であることが確認できます。

$ file EdinetcodeDlInfo_utf8.csv
EdinetcodeDlInfo_utf8.csv: UTF-8 Unicode text

最終的には元々のShift-JISのCSVファイル、UTF-8のCSVファイルの2つができるはずです。

$ ls
EdinetcodeDlInfo.csv    EdinetcodeDlInfo_utf8.csv

EdinetcodeDlInfo_utf8.csvの中身は以下のようになっているはずです。最初の頃の無駄な一行目が削除されていることがわかります。

EDINETコード,提出者種別,上場区分,連結の有無,資本金,決算日,提出者名,提出者名(英字),提出者名(ヨミ),所在地,提出者業種,証券コード,提出者法人番号
"E00004","内国法人・組合","上場","有","1491"," 5月31日","カネコ種苗株式会社","KANEKO SEEDS CO., LTD.","カネコシュビョウカブシキガイシャ","前橋市古市町一丁目50番地12","水産・農林業","13760","5070001000715"
"E00006","内国法人・組合","上場","有","13500"," 5月31日","株式会社 サカタのタネ","SAKATA SEED CORPORATION","カブシキガイシャ サカタノタネ","横浜市都筑区仲町台2-7-1","水産・農林業","13770","6020001008662"
"E00007","内国法人・組合","上場","有","119"," 3月31日","株式会社雪国まいたけ","YUKIGUNI MAITAKE CO.,LTD.","カブシキカイシャユキグニマイタケ","南魚沼市余川89番地","水産・農林業","13750","1010001185037"
"E00008","内国法人・組合","上場","有","5500"," 3月31日","ホクト株式会社","HOKUTO CORPORATION","ホクトカブシキガイシャ","長野市南堀138番地1","水産・農林業","13790","6100001003151"
"E00009","内国法人・組合","上場","有","452"," 6月30日","株式会社アクシーズ","AXYZ Co., Ltd","カブシキガイシャアクシーズ","鹿児島市草牟田二丁目1番8号","水産・農林業","13810","5340001000258"
"E00010","内国法人・組合","上場","有","421"," 6月30日","株式会社ホーブ","HOB Co.,Ltd.","カブシキガイシャホーブ","上川郡東神楽町14号北1番地","水産・農林業","13820","9450001002677"
"E00011","内国法人・組合","上場","有","32828","12月31日","住友林業株式会社","Sumitomo Forestry Co.,Ltd.","スミトモリンギョウカブシキガイシャ","千代田区大手町一丁目3番2号","建設業","19110","4010001090011"
"E00012","内国法人・組合","上場","有","5664"," 3月31日","株式会社 極洋","KYOKUYO CO., LTD.","カブシキガイシャ キョクヨウ","港区赤坂三丁目3番5号","水産・農林業","13010","1010401033225"
"E00014","内国法人・組合","上場","有","30685"," 3月31日","日本水産株式会社","Nippon Suisan Kaisha, Ltd.","ニッポンスイサンカブシキガイシャ","港区西新橋一丁目3番1号","水産・農林業","13320","1010001016860"

EDINETコードリストは以下の13の列を持っていることがわかります。

EDINETコード
提出者種別
上場区分
連結の有無
資本金
決算日
提出者名
提出者名(英字)
提出者名(ヨミ)
所在地
提出者業種
証券コード
提出者法人番号

コード全体

上記全体をまとめたコードは以下になります。

まとめ

今回はEDINETコードリストを取得するコードを作成しました。こちらをGitHub ActionsやCircleCIなどで毎日実行して、差分を抽出すれば、登録された法人や削除された法人などを把握することもできるはずです。

今は趣味で会計や金融系のことを勉強していることもあり、そのためにEDINET関連を簡易的にするためのサービスなどを作っています。

近日公開予定です。

この記事が気に入ったらサポートをしてみませんか?