東証上場銘柄の自動更新プログラムを作成①【Python】

東証のプライム/スタンダード/グロース市場に株式を上場している企業の一覧について、常に最新状態の一覧リストが欲しいと思ったことはないでしょうか。

以前から手動で銘柄リストを更新しており、いいかげん自動化したいと思っていましたが、私のような零細個人投資家が簡単に付き合えるようなサービスが思い当たらず、、

なので、今回は東証の公式サイトから情報を取得して、東証上場企業の最新銘柄を自動取得および更新するプログラムを作成してみました。

プログラム全体の概要

今回作成するプログラムは、以下の機能を組み合わせた内容になります。

  • Webページから上場銘柄の更新情報を取得
  • スケジューラによる定期実行

本記事では、最初の『Webページから上場銘柄の更新情報を取得』を行うプログラムを作成してみます。

情報の取得先

まず一番初めに、現時点で上場している企業の一覧のリストを準備しておく必要があります。

少し面倒ですが、上場企業リスト一覧を掲載している株マップのようなサイトを参照し、銘柄コード、企業名、市場区分などをコピーして、事前にCSVで保存しておきます。

次に、Webページから更新データを取得するプログラムを作っていきます。

更新データを取得するページは、東京証券取引所の公式ページに挙げられている新規上場銘柄市場区分変更銘柄上場廃止銘柄のページとします。

注意

プログラムを用いてWebサーバーへアクセスするスクレイピング行為は、相手方のWebサーバーへ負担を掛ける恐れがあります。スクレイピングする際は、相手方のサーバーへ負荷が掛からないように(例:アクセス間隔を制御する等)配慮が必要です。

プログラムを作成

まず、Beautiful Soup ライブラリを使用して HTMLデータを取得する関数 以下で作成します。(User-Agent は、Webページへアクセス時に相手方のサーバーへ渡すブラウザの情報です。確認サイトなどで自分の環境を確認して記入します。)

import requests
from bs4 import BeautifulSoup

# リンクからデータを取得する関数
def get_data(url):

    # User-Agent設定
    user_agent = '確認した User-Agent を入力'
    header = {
        'User-Agent': user_agent
    }

    r = requests.get(url, headers=header)  # User-Agentsを設定
    soup = BeautifulSoup(r.content, "html.parser")

    return soup

if __name__ == '__main__':
    url = input('URLを入力: ')
    soup = get_data(url)
    print(soup)

新規上場銘柄の情報を取得

次に、上記で定義した関数を用いて、Beautiful Soup ライブラリを用いて新規上場銘柄のリストをスクレイピングします。

# 新規上場銘柄のデータ元リンク
jpx_newlist_url = 'https://www.jpx.co.jp/listing/stocks/new/index.html'

# データを取得
soup = get_data(jpx_newlist_url)

スクレイピング結果から、銘柄リストが掲載されているテーブル部分を抽出。

# テーブル部分のみ抽出
items = soup.findAll("div", {"class": "component-normal-table"})

テーブル部分を見てみると、"a-center" のタグに上場日/コード/市場区分のテキストが、"a-left" のタグに銘柄名のテキストが含まれている事が分かるため、それぞれをリスト形式で一括で取得します。

# Dataframeに格納する上場日、コード、市場区分を取得
code_data = []
for item in items:
    code_list = item.findAll("td", {"class": "a-center"})
    for code in code_list:
        code = code.getText().strip()
        code_data.append(code)

# Dataframeに格納する銘柄名を取得
name_data = []
for item in items:
    name_list = item.findAll("td", {"class": "a-left"})
    for name in name_list:
        name = name.getText().strip().replace(' ',' ')
        name_data.append(name)

続いて、上場日/コード/市場区分の情報が含まれる code_data と、銘柄名の情報が含まれる name_data から必要な情報を抽出していきます。

# Dataframe格納用に整理(日付)
i_pre = []
date_pre = []

for i in code_data:
    i = i[:10]
    i_pre.append(i)

date_pre = [x for x in i_pre if len(x) > 9]
# Dataframe格納用に整理(コード)
i_pre = []
code_pre = []

for i in code_data:
    i = i[:4]
    i_pre.append(i)

i_pre2 = [x for x in i_pre if len(x) < 5 and len(x) > 0]
i_pre3 = [x for x in i_pre2 if '-' not in x]

for i in i_pre3[1::3]:
    code_pre.append(int(i))
# Dataframe格納用に整理(市場区分)
i_pre = []
mrkt_pre = []

for i in code_data:
    i = i[:6]
    i_pre.append(i)

i_pre2 = [x for x in i_pre if len(x) < 7 and len(x) > 0]
i_pre3 = [x for x in i_pre2 if '-' not in x]

for i in i_pre3[2::3]:
    mrkt_pre.append(i)
# Dataframe格納用に整理(銘柄名)
name_pre = []

for i in name_data:
    name_pre.append(i.replace('\n代表者インタビュー','').replace('(株)','').replace(' *',''))

割と力業でスマートではありませんが、上場日/コード/市場区分/銘柄名の情報を抽出する事ができました。

# 各データをDataframeへ格納していく
newlist_df = pd.DataFrame()
newlist_df['更新日'] = date_pre
newlist_df['銘柄名'] = name_pre
newlist_df['コード'] = code_pre
newlist_df['市場区分'] = mrkt_pre

以上で、新規上場銘柄のリストをWebページから抽出し、DataFrame へ格納する事ができました。

市場区分変更銘柄上場廃止銘柄の情報を取得

やることは、先に説明した新規上場銘柄の取得方法と基本的に同じなので省略します。

上記までを通して、取得したデータを以下それぞれの DataFrame へ保存している状態にしておきます。

  • base_df : 東証プライム/スタンダード/グロース銘柄の現時点のデータ。
      【内容:コード、更新日、銘柄名、市場区分】
  • jpx_newlist_df : 新規上場銘柄のデータ。
      【内容:コード、更新日、銘柄名、市場区分】
  • jpx_transfer_df : 市場区分変更銘柄のデータ。
      【内容:コード、変更日、銘柄名、市場区分、市場区分(前)】
  • jpx_delist_df : 上場廃止銘柄のデータ。
      【内容:コード、上場廃止日、銘柄名、市場区分、上場廃止理由】

取得したデータを結合

次のステップとして、今までに取得したデータを現状データ(base_df)に統合していきます。

まずは新規上場銘柄のデータを concat で結合し、既に現状データに含まれており重複するものがあれば、現状データの方を残すように処理します。

# 新規上場を基準データに反映
merge_df = pd.concat([base_df, jpx_newlist_df], axis=0)
merge_df.drop_duplicates(subset='コード', keep='first', inplace=True)
merge_df2 = merge_df.reset_index(drop=True).copy()

次の作業のために、コードの列を DataFrame の index として指定しておきます。

# コードをindexに設定
merge_df3 = merge_df2.set_index('コード', drop=True).copy()

続いて、市場区分変更のデータを反映します。

市場区分変更データと現状データを突き合わせて、該当した銘柄を置き換える処理をします。

# 市場変更を基準データに反映
for tr_cd in jpx_transfers_df['コード']:
    if tr_cd in merge_df3.index:
        merge_df3.loc[merge_df3.index==tr_cd, '市場区分'] = jpx_transfers_df.loc[jpx_transfers_df['コード']==tr_cd, '市場区分'].values
        merge_df3.loc[merge_df3.index==tr_cd, '更新日'] = jpx_transfers_df.loc[jpx_transfers_df['コード']==tr_cd, '変更日'].values
    else:
        pass

最後に、上場廃止銘柄データを反映します。

こちらはシンプルに、上場廃止銘柄データに含まれるものを現状データから drop する処理を行います。

# 上場廃止を基準データに反映
for de_cd in jpx_delist_df['コード']:
    if de_cd in merge_df3.index:
        merge_df3.drop(index=merge_df3.index[merge_df3.index==de_cd], inplace=True)
    else:
        pass

以上、これで merge_df3 の DataFrame に全ての変更を反映したデータを格納している状態になり、Python で扱いやすい形式の最新の東証上場銘柄のリストを作成する事ができました。

あとはこれを csv に吐き出すなりデータベースに格納するなりしておけば、便利に活用する事ができますね。


珈琲1杯でもおごるつもりでご支援して頂けたら大変喜びます😊

スポンサーリンク