Python
スクレイピング
pandas
Python3

株式投資自動化にトライ -Webサイト『株探』をスクレイピングして有望銘柄を抽出する


前回まで

株式投資の自動化を題材にして、実現までのステップと必要となりそうな知識を前回記事でザッと整理した。

とはいっても実際のところはやってみないとわからないことも多いし、ありとあらゆるところでハマりそうな予感しかしないので、細かいことはあまり考えずにとりあえず手を動かして進めていこうと思う。


環境

※以降の内容は、Anacondaをインストールしている前提で記載

※コーディング時はJupyter Notebookを使用(Jupyterでないと出来ないという要素は特にないはずなので、使いやすい開発環境があればそちらでも問題ないと思われる)


有望銘柄をスクレイピングで抽出する


スクレイピング対象

会社四季報オンライン を利用して引っこ抜けたら良いなと思っていたのだけれど、

当該サービスは有料(どうやら初月は無料で利用できる模様)なうえに認証処理等もあって面倒そう。

もっと手軽に銘柄情報を引っこ抜ける方法はないかなと思っていたら、世の中便利なもので、様々な視点で銘柄を検索するためのサイトが多数存在するみたい。

今回は株探 を利用することにした。

無課金かつ会員登録なしでも利用できるデータがたくさんありそうなのが採用理由。


『株探』の中からスクレイピング対象のページを選定する

とはいってもトレード知識のない私は何がなんだかさっぱりわからないので、

「有望」の一語に惹かれ、「【第1四半期】時点 中間期上振れ 有望銘柄」から銘柄を引っこ抜いてみることにした(単純)。

image.png

【第1四半期】時点 中間期上振れ 有望銘柄

赤枠で囲った一覧の情報を抽出することが今回のゴール。

また、ページ送りもあるので、全ページ分抽出する必要がある。

image.png


早速スクレイピングしてみる

スクレイピングということで、色々調べてみたところ、

Seleniumを使ってjavascriptの操作をしてみたり、BeautifulSoupを使ってhtmlの解析をしてみたり色々やるのだろう…と予想して実際に色々とトライしてみたが、

実はPandasだけで今回の目的を実現できてしまうことがわかった。

めちゃくちゃ調べたのに…悲しい…

てわけで、早速ソースコード。


ソースコード(2018/09/04 修正)


KabutanScraping.py

import pandas as pd

import numpy as np
from IPython.core.display import display
pd.set_option("display.max_rows", 10)

baseUrl = 'https://kabutan.jp/tansaku/?mode=1_funda_06&market=0&stc=&stm=0&page='
pageNum = 1
dfAllBrands = pd.DataFrame()
while True:
url = baseUrl + str(pageNum)
# 7つ目に作られるDataFrameが銘柄情報
# 1行目(index=0)にヘッダが重複して取得されるため2行目から使用
dfBrandsInPage = pd.read_html(url, header=0)[6].iloc[1:,:]
if len(dfBrandsInPage) == 0:
display('break')
break
dfAllBrands = dfAllBrands.append(dfBrandsInPage)
pageNum += 1

# ヘッダ部とデータ部のズレを引き起こしている不要な列を除外してDataFrameを再構成
header = dfAllBrands.columns.values
header = np.r_[header[0:3],header[4:5],header[6:12]]
data = [np.r_[row[0:3],row[5:6],row[7:]] for row in dfAllBrands.values]
dfAllBrands = pd.DataFrame(data, columns=header)
display(dfAllBrands)


おおまかなポイントだけ記載することにする。


1.URLの規則性を利用する

今回対象としたページの構成は、URLのpage=の部分にページ番号が入るだけだったので、シンプルなループ処理でも十分と判断。

件数分を表示しきって表示銘柄がなくなるとヘッダだけの空の表ができるだけのようだったので、ループの終了タイミングも特定できた。

(page=10 にしてページを開いてみた結果)

image.png

この時点で、今回はSeleniumなしでもいけると判断。

(調査の過程で触ってみたりもしたが、怠惰な筆者は楽なやり方に流れた)


2.表データ取得時はpandas.read_htmlを使う

はじめはBeautifulSoupを使ってhtmlの要素を特定して…

って感じで色々調べていたのだが、他所事でpandasのリファレンスを見ていた時にpandas.read_htmlメソッドの存在に気がついた。

どうやらtableタグの中身をDataFrameにぶち込んでくれるらしい。

pandasちゃん超有能、俺はお前についていく。

リファレンス(pandas.read_html)

この時点で、BeautifulSoupも不要と判断。

(調査の過程で触ってみたりもしたが、怠惰なh)

あれ?てかスクレイピングしてる感が全然なくね?


3.表の構成によってはpandas.read_htmlで期待した結果を得られないかも

実は今回ターゲットにした表については、単純にこのメソッドを使うだけではダメだった。

というのも、表には画像が埋め込まれたセルや、データ部は2列でもヘッダ部が結合されて1列の箇所があったため、

そのままやったらDataFrameの列の位置がズレた。

この列のせいで期待したDataFrameの結果を得られず。

image.png

実際のDataFrameの出力結果。

「株価」列からずれてしまっている。

image.png

これを誤魔化すために、折角出力したDataFrameをバラし、ヘッダ部とデータ部を作りなおして最終形にもっていっている。

ここについてはもっと良い方法がある気がするのだが…

最終的な実行結果はこちら。

image.png

今回はすべての銘柄を引っこ抜いたが、DataFrameを使っているので、そこから自分の好みの条件でフィルターをかけたりして銘柄を絞ってみても面白いと思う。

スクレイピングっぽいことを全くやっていない上になんかダサいコードになってしまった感が否めないが、現状ではコレが一番シンプルそうだったので、とりあえずこれで。