EDINETから証券コードCSVをダウンロードするコード(Linux)

問題

EDINETでは以下のページで証券コードのCSVが公開されています。

EDINETタクソノミ及びコードリストダウンロード
EDINETタクソノミ及びコードリストダウンロード指定画面

しかしながら、以前はGETリクエストでダウンロードできる構成だったのですが、2023年頃の仕様変更によりダウンロード方法が変わり自動化が難しい構成となりました。

どうやら、JavaScriptで生成した値を入れてPOSTリクエストを送信する必要があるようで、固定の値にはできません。ソースコードの解析ができたとしても実現するにはJavaScriptと同様の動作を行うコードを書く必要があり一朝一夕では済みません。
また、応答データもJSON形式でbase64でエンコードされたデータをJavaScriptで実行する方式となっており、正直嫌がらせにもほどがある構成となっています。

もし実装する場合、以下のような泣きそうな作業をしなければいけません。

  1. JavaScriptを解析し、リクエストURLの値の生成
  2. JavaScriptを解析し、送信するJSONのhshの値を生成
  3. JavaScriptを解析し、応答データのbase64を複合しダウンロード形式に変換

リクエスト形式:

POST https://disclosure2.edinet-fsa.go.jp/weee0010.aspx?c01d04b1610243d2a2af23e7952e8b18b04dae7dea0dea41b37cf7561b911b6d,gx-no-cache=1761746440871


{
	"MPage": false,
	"cmpCtx": "",
	"parms": [
		"WEEE0010",
		"EDINETタクソノミ及びコードリストダウンロード指定画面"
	],
	"hsh": [
		{
			"hsh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJneC1pc3N1ZXIiOiIiLCJneC1wZ20iOiJXRUVFMDAxMCIsImd4LXZhbCI6IldFRUUwMDEwIiwiZ3gtZXhwIjoiMTc2MzA2NjU2OS4xNjQxOSIsIm5iZiI6MTc2MTczODE2OSwiZXhwIjoxNzYzMDM0MTY5LCJpYXQiOjE3NjE3MzgxNjl9.YLbVuvR_EbReu6iQ4D5wJFJ_dPlOBHygJ4Kx9KEYj80",
			"row": ""
		},
		{
			"hsh": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJneC1pc3N1ZXIiOiIiLCJneC1wZ20iOiJXRUVFMDAxMCIsImd4LXZhbCI6IkVESU5FVOOCv-OCr-OCveODjuODn-WPiuOBs-OCs-ODvOODieODquOCueODiOODgOOCpuODs-ODreODvOODieaMh-WumueUu-mdoiIsImd4LWV4cCI6IjE3NjMwNjY1NjkuMTY0MTkiLCJuYmYiOjE3NjE3MzgxNjksImV4cCI6MTc2MzAzNDE2OSwiaWF0IjoxNzYxNzM4MTY5fQ.wwuPAm6qtWj4dCrgoQaa_y9EjdWj3a7NkMpaDFJL0BA",
			"row": ""
		}
	],
	"objClass": "weee0010",
	"pkgName": "GeneXus.Programs",
	"events": [
		"'DODOWNLOADEDINET'"
	],
	"grids": {}
}

レスポンス形式:

    "gxProps": [
        {
            "CmpContext": "",
            "IsMasterPage": "False",
            "TXTSCRIPT": {
                "Caption": "<script type=\"text/javascript\">function downloadBase64File() {const linkSource = \"data:;base64,UEsDBBQAAAAIAGWlXVv9j6Oa84EIAAsdIgAUAAAARWRpbmV0Y29kZURsSW5mby5jc3asvf13XMWZJ/77nrP/Qx/9........EIAAAAlgggAAAA=\";const downloadLink = document.createElement(\"a\");downloadLink.href = linkSource;downloadLink.download = \"Edinetcode_20251029.zip\";downloadLink.click();}downloadBase64File();</script>"
            }
        }
    ],
    "gxHiddens": {
        "GX_CMP_OBJS": {}
    },
    "gxValues": [],
    "gxMessages": {
        "MAIN": []
    },
    "gxComponents": {},
    "gxGrids": []
}

さすがにこれはやってられないと思い、selenium を使用してブラウザシミュレートでダウンロードする方法で対処を行うこととしました。

環境

OS: Rocky Linux

インストール

Seleniumを実行するには色々と必要になります。
以下のモジュールをダウンロード・インストールします。
少々古いバージョンになりますが、それほど複雑な作業を行うわけではないためデフォルトのリポジトリからインストールしても大丈夫です。

pip3 install selenium webdriver-manager --user
yum install -y chromedriver 
yum install -y chromium

ソースコード

ソースコードは以下のようになります。

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
import time
import os

def download_edinet_file():
    # ダウンロード先
    download_dir = os.path.join(os.getcwd(), "")
    os.makedirs(download_dir, exist_ok=True)

    options = webdriver.ChromeOptions()
    options.add_argument("--headless")
    options.add_argument("--no-sandbox")
    options.add_argument("--disable-dev-shm-usage")
    prefs = {
        "profile.default_content_settings.popups": 0,
        "download.default_directory": download_dir,
        "directory_upgrade": True
    }
    options.add_experimental_option("prefs", prefs)
    
    # driverの初期化
    driver = None 

    try:
        driver = webdriver.Chrome(executable_path="/usr/bin/chromedriver", options=options)

        # EDINETの「EDINETタクソノミ及びコードリストダウンロード指定画面」へ遷移
        driver.get("https://disclosure2.edinet-fsa.go.jp/weee0010.aspx")

        # 代わりに「リンクがクリックできるようになったこと」を待機する
        WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#GridContainerRow_0001 a"))
        )
        # selenium実行
        driver.execute_script("onDownloadEdinet()")

        # ファンドコードリストのダウンロード
        WebDriverWait(driver, 10).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#GridContainerRow_0002 a"))
        )
        driver.execute_script("onDownloadFund()")

        # ダウンロード完了するくらいまでsleepする。
        time.sleep(5)

        driver.close()

    finally:
        if driver is not None:
            driver.quit()

if __name__ == "__main__":
    download_edinet_file()

これでダウンロードができます。

参考

こちらのコードを大変参考にさせていただきました。なお、以下のページのコードはWindows用です。

リニューアル後のEDINETからEDINETコードリストを取得する - Qiita
EDINET、EDINETコードリストについて EDINET、EDINETコードリストについて、詳細は EDINET の操作ガイド等を参照してください。 本稿で扱う EDINETコードリストは上場企業の一覧などを簡単に取得できることから機械...

コメント

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