株の銘柄を選定する際、ランキングやその他の指標を継続的に監視したいことがあると思います。毎日の作業なので出来れば自動化したいところですが、自分にオリジナルなチェック基準がある場合、既存のサイトでのフィルタは物足りないことがあります。
私もいい方法がないかとネットで検索していたところ、pythonでスクレイピングすることでカスタマイズ性が上がりそうなので実装してみました。
Contents
各種インポート
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# インポートモジュール import requests from datetime import datetime, timedelta from bs4 import BeautifulSoup import numpy as np import pandas as pd import os from tqdm.notebook import tqdm # 常にすべてのカラムを表示する pd.set_option('display.max_columns',None) pd.set_option('display.max_rows',250) # プロキシがある環境の場合 #os.environ["HTTP_PROXY"] = "http://xxx:8080" #os.environ["HTTPS_PROXY"] = "https://xxx:8080" |
私の環境は、今後得られたデータを使って機械学習を行うことを想定してGoogle Colabolatoryを使用しています。
Google ColabolatoryはGoogleアカウントさえ持っていれば気軽にPythonをいじれるので超簡単。ノートブックしかない私の環境でもサクサク動きます。
Google様には頭が上がりません。
とりあえず環境設定はこんな感じ。自PC環境でプロキシ設定がある場合はコメントアウト部分をいじればいけると思います。
株ドラゴンのサイト構造
株ドラゴン https://www.kabudragon.com/ こちらのサイトから情報を使用させていただきます。
スクレイピングはあまりURLへのアクセス頻度が高いと相手サイトのサーバー負荷が高くなるので、迷惑にならないようアクセス頻度に気を付けてコーディングしましょう。
ただ、数十日分のスクレイピングをするくらいなら現状は問題なさそうです。
さて、株ドラゴンのサイト構造は以下のようになっています。
1 2 |
# 東証1部(t1)の値上がり率ランキング200件(age200)、鉱業(業種02)、チャート型指定は陽線(candle=yousen)、2019年の8月10日を指定 https://www.kabudragon.com/ranking/2019/08/10/1000/t1/02/age200.html?candle=yousen |
のちに出てくるURL指定の際には、自身が取得したいランキングを上記のURLをカスタマイズして取得してください。
取得する日付の区間指定とデータ整備のための関数
1 2 3 4 5 6 7 8 9 |
# 日付の指定 st_date = '2020/07/01' end_date = '2020/07/31' st_date = datetime.strptime(st_date, '%Y/%m/%d') end_date = datetime.strptime(end_date, '%Y/%m/%d') # 期間の日数計算 term = end_date - st_date # データのint 変換用関数 to_int = lambda x: int(x.replace(',','')) |
ランキングを利用して分析する際は、日次ごとの変化を見たいはずなのでスクレイピング開始と終了の日付を指定する変数を作ります。
また、後で順番通りに取得できるよう、日付文字列を演算可能なdatetime型に変換しておきます。
それと、上記のto_intはとっても重要です。スクレイピングすると、株ドラゴンの表内の価格に関するデータはことごとくカンマ区切りの文字列で取得されるため、数値演算ができません!私はここで少し泣きました。まぁ変換は簡単で、後でDataFrame[‘列名’].map(to_int)としてやって、変換したい列を全部数値に置き換えます。
スクレイピング本体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# スクレイピング結果をdfに格納 with tqdm(total = term.days +1 ) as pbar: while st_date <= end_date: date = datetime.strftime(st_date, '%Y/%m/%d' ) url = 'https://www.kabudragon.com/ranking/{}/dekidaka.html'.format(date) st_date = st_date + timedelta(days = 1) soup = BeautifulSoup(requests.get(url).text, "lxml") if len(soup.body.find_all('tr')) > 20: start_line = [i for i in range(14,20) if soup.body.find_all('tr')[i].text.splitlines()[1] == '順位'] items = [v.text.splitlines() for i, v in enumerate(soup.body.find_all('tr')) if i > start_line[0]] cols = ['','順位','コード', '名称', '市場','日付','終値','前日比(円)','前日比(%)','出来高','高値','安値'] df = pd.DataFrame(np.array(items[0]).reshape(1,-1),columns=cols) for i in range(1,50): df_add = pd.DataFrame(np.array(items[i]).reshape(1,-1),columns=cols) df = pd.concat([df, df_add],axis = 0) else : print('休場') pbar.update(1) |
今回は出来高ランキングを使ってみます。
2行目のtqdmは、取得する日付が多くなった時にプログラムの実行に時間がかかるとき進捗度合いをシークバーで表示する文です。自PCの際はただのtqdmをimportすることでもっと簡単に書けると思います。最下段のpbar.update(1)を忘れずに。
コーディングの大部分は他サイト様の情報を参考にしました。閲覧するランキングによってcolsの要素数が変化するので気を付けてください。
補足ですが、URLで平日を指定した場合、サイト情報は取得されないのでhtmlタグのtrを条件にサーチしてあげれば休日を飛ばしてDataFrameに突っ込めます。へぇ~。
さらに追記で、ランキング200件を選択した場合、14行目の範囲は50→200にしてください。
データの整形
1 2 3 4 5 6 7 8 9 10 11 |
dekidaka = df.drop('',axis=1) dekidaka['出来高'] = dekidaka['出来高'].map(to_int) dekidaka['順位'] = dekidaka['順位'].map(to_int) dekidaka = dekidaka.drop(['市場','前日比(円)','前日比(%)','高値','安値'],axis=1) # display(dekidaka) # 当日のdf(出来高が9桁以上) dekidaka_9 = dekidaka[dekidaka['出来高']>100000000] # 当日(出来高が9桁以上)の銘柄コードリスト today_list = dekidaka_9['コード'].sort_values().unique() |
取得した直後のDataFrameは、分析に要らない要素があるので適当にdropします。今回は順位,銘柄,終値,出来高が分かればいいことにしてその他は落としました。
取得したdekidakaの見た目はこんな感じ

取得したデータで条件をつけて抜き出したい場合も、DataFrame型なら不等号などですぐに検索できます。
また、dfに同じ要素がある場合にその要素をユニークに数えることもできます。
ということで、以下のように書いて1ヵ月分の中から、出来高が9桁以上になった銘柄をすべて取り出してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# 日付の指定まで省略 dekidaka_9_col = ['順位','コード', '名称','日付','終値','出来高'] dekidaka_9 = pd.DataFrame(columns=dekidaka_9_col) # スクレイピング結果をdfに格納 with tqdm(total = term.days +1 ) as pbar: while st_date <= end_date: date = datetime.strftime(st_date, '%Y/%m/%d' ) url = 'https://www.kabudragon.com/ranking/{}/dekidaka.html'.format(date) st_date = st_date + timedelta(days = 1) soup = BeautifulSoup(requests.get(url).text, "lxml") if len(soup.body.find_all('tr')) > 20: start_line = [i for i in range(14,20) if soup.body.find_all('tr')[i].text.splitlines()[1] == '順位'] items = [v.text.splitlines() for i, v in enumerate(soup.body.find_all('tr')) if i > start_line[0]] cols = ['','順位','コード', '名称', '市場','日付','終値','前日比(円)','前日比(%)','出来高','高値','安値'] df = pd.DataFrame(np.array(items[0]).reshape(1,-1),columns=cols) for i in range(1,50): df_add = pd.DataFrame(np.array(items[i]).reshape(1,-1),columns=cols) df = pd.concat([df, df_add],axis = 0) dekidaka = df.drop('',axis=1) dekidaka['出来高'] = dekidaka['出来高'].map(to_int) dekidaka['順位'] = dekidaka['順位'].map(to_int) dekidaka = dekidaka.drop(['市場','前日比(円)','前日比(%)','高値','安値'],axis=1) # 当日のdf(出来高が9桁以上) dekidaka_9 = dekidaka_9.append(dekidaka[dekidaka['出来高']>100000000]) pbar.update(1) display(dekidaka_9) code_list = dekidaka_9['コード'].sort_values().unique() display(code_list) |
結果

2020年の7月中に出来高が9桁到達したのは上記の2銘柄でした。
このようにカスタマイズ性が格段にあがるのでpythonを触ってみて楽しいなと思いました。いい売買ロジックを持っている方がいれば組んでみることをおススメします。
コメント