cojimaru BLOG

エンジニア支援のために技術情報を発信するブログ

Webスクレイピングで急落銘柄通知ツールを作成してみた

f:id:cojimaru-chan:20210420010122p:plain

どうも、こじまるです。
以前Twitterの仲良しさんと投資ツールについてやり取りしていた時に、下記のようなツールを使ってみたいという話がありました。



f:id:cojimaru-chan:20210419234111p:plain:w500


そのため、当月・翌月が権利確定月の銘柄で、急落銘柄を通知するツールを作ってみようと思いました。

この記事をみてわかること

Webスクレイピングで急落銘柄通知ツールの作成

要件定義

システムの要件定義
  • 要件1. 当月・翌月が権利確定日の銘柄で、急落銘柄を通知できること
  • 要件2. スマートフォン/パソコンから簡単に情報取得できること

処理の流れ

今回使用するプログラムは、権利確定日の情報を取得する事前処理と定期的に急落銘柄を判定し通知するメイン処理に分離しました。

事前処理
権利確定日の情報は、頻繁に変更されるものではありません。そのため、スクレイピング先のサーバの負荷を考慮し、一ヶ月に一度あるいは一度だけ実行されればいいと思います。

f:id:cojimaru-chan:20210419235910p:plain

事前処理の流れ
  • ①権利確定月などの銘柄情報の取得
  • ②銘柄情報を保存


メイン処理(定期実行)
メイン処理に関しては、当月・翌月が権利確定日の銘柄で、急落銘柄を通知する必要があります。急落銘柄は、前日終値と現在の株価から割合を求めます。タイムリーにその情報を得るためにも定期的な実行が必要になります。

f:id:cojimaru-chan:20210420000004p:plain
メイン処理の流れ
  • スクリプトの定期実行
  • ②銘柄情報を取得
  • ③急落銘柄を通知

事前処理

①権利確定日の銘柄情報を取得

権利確定日の銘柄情報取得のために、https://kabuoji3.com/を使用しました。https://kabuoji3.com/robots.txtを確認しましたが、Allow:/と記載されていますので、問題なく使用できそうです。

User-Agent: *
Allow:/
Sitemap:http://kabuoji3.com/sitemap/sitemap-index.xml



今回使用するURLは、https://kabuoji3.com/stockholder/{銘柄コード}/になります。こちらのURLにブラウザでアクセスすると、権利確定月が表示されています。
f:id:cojimaru-chan:20210420000407p:plain


こちらの権利確定月の表示をXPATHで参照するようにし、取得しました。

url = "https://kabuoji3.com/stockholder/{}/".format(stock_code)
headers = {"User-Agent": "Chrome"}

html = requests.get(url, headers=headers)
html.raise_for_status()
dom_tree = lxml.html.fromstring(html.content)

# 権利確定月
vesting_date = dom_tree.xpath('//*[@id="base_box"]/div/div[3]/dl[2]/dd/text()')
if not len(vesting_date):
  continue
stock_vesting_date = vesting_date[0]


②銘柄情報の保存

権利確定月の情報は日々更新されるわけではないので、下記のようにExcelデータとして保存し、それをメイン処理で読み取む形で利用します。
f:id:cojimaru-chan:20210420000759p:plain

メイン処理

スクリプトの定期実行

タスクスケジューラやcronなどを使って、スクリプトの定期実行が可能です。こちらの設定方法などは下記記事を参考にしてください。

cojimaru-chan.hatenablog.com

cojimaru-chan.hatenablog.com

②銘柄情報を取得

事前処理で取得した権利確定月の情報を利用して、当月・翌月が権利確定月の銘柄のみに対してのみ、スクレイピング処理を行います。

当月・翌月が権利確定月の銘柄の判定
取得した権利確定月の情報には月を指す文字以外の余計な文字も含まれています。正規表現を使って、必要となる月を示す文字列のみを取得しています。

# 当月・翌月の文字列を取得
dt_now = datetime.now()
tmp = dt_now + relativedelta(months=1)
dt_month = str(dt_now.month)
dt_next_month = str(tmp.month)

...

stock_vesting_date = str(row[2]) # 権利確定月
if stock_vesting_date == "随時": # 随時は対象外に
  continue
else:
  month_list = re.findall("\d+月",stock_vesting_date)
  vesting_month_list = [s.replace("月","") for s in month_list]
  
  # 当月・翌月が権利確定月の銘柄のみ後段の処理を実行
  if dt_month in vesting_month_list or dt_next_month in vesting_month_list:
    pass
  else:
    continue



急落銘柄の判定
現在の株価、前日終値は以前の記事と同様に、みん株のサイトからウェブスクレイピングを利用して取得します。詳細に関しては、下記の記事を見てください。

cojimaru-chan.hatenablog.com

取得した株価と前日終値を利用し、急落率を計算します。ユーザが定義した急落率を超えた場合に、リストに情報を保持するように実装しました。

# 現在値
tmp = chart_dom_tree.xpath('//*[@id="layout"]/div[2]/div[3]/div[2]/div/div[1]/div/div/div[1]/div[2]/div/div[2]/div/text()')
current_price = float(re.sub(r'\D','',tmp[0]))

# 前日終値
stock_previous_closing_place = parse_dom_tree(chart_dom_tree,'//*[@id="contents"]/div[3]/div[1]/div/div/div[2]/div/div[1]//tr[1]/td[1]','円','')            
price_drop_rate = (1 - current_price / stock_previous_closing_place) * 100
if price_drop_rate >= TARGET_DROP_RATE:
  output_list.append([stock_code,stock_name,current_price,stock_previous_closing_place,price_drop_rate])


③急落銘柄を通知

Slackへの通知には、Incoming Webhooksを利用して実行しています。詳細はこちらでは割愛しますので、必要であれば、下記記事を参考にしてください。
参考
https://developers.wonderpla.net/entry/2020/06/18/110005

コード

今回使用したコードを下記にアップロードしました。興味がありましたら、事前処理はdataCollection.py、メイン処理はcreateStockMap.pyを確認してください。
github.com

実行結果

急落率 : 5%の条件で実行してみました。急落率が5%以上の銘柄が取得できています。
f:id:cojimaru-chan:20210420004649p:plain

他のサイトで急落率を確認しましたが、一致していますね。
f:id:cojimaru-chan:20210420005040p:plain

まとめ

Webスクレイピングを行って、当月・翌月が権利確定月の銘柄で、急落銘柄を通知するツールを作成しました。Webスクレイピング記事を他にも書いており、ナレッジがあったので、案外簡単に作成することができました。もし、興味がありましたら、利用してみてください。(※定期的なスクレイピングは高頻度に実行すると、サービス提供者への負荷になりますのでご注意ください。)

今後は有効性を検証するため、急落率 : 3%~5%、平日の9時~15時で一時間刻みの条件でスクリプトを実行し、有効性を検証してみようと思います。