【Python】スクレイピングで株価データを取得する

プログラミング
この記事は約17分で読めます。

私の経験上、株でしっかりと稼ぐためには、取引する銘柄の値動きを毎日しっかりとチェックしておく必要があると思います。

毎日注目している銘柄の月足、週足、日足それぞれの移動平均線、一目均衡表、出来高、RCIなどをポチポチとクリックしていくとそれだけで1〜2時間経ってしまいます。これは面倒だということでなんとか、自動化させたいのですが、自分が着目している銘柄かつ指標に絞って一覧で結果が見れるようなサイトはありません。ということで、自分で作ることにしました。

スポンサーリンク

株価データ提供サイト

まずは自分が着目している個別銘柄の株価データを取得することを考えます。私は主にsbi証券を使っており、個別銘柄のデータをハイパーSBIなどを使ってダウンロードすることはできるのですが、その作業が面倒なので、株価データを提供しているサイトからスクレイピングすることにしました。

ありがたいことにこちらのサイトで株価データを提供してくださっているので、こちらを利用させていただきたいと思います。

robots.txtの確認

サイトによっては、スクレイピングが禁止されているものがあります。
スクレイピングをしてよいかどうかを確認するためには、各サイトのrobots.txtを見ることで確認できます。

robots.txtの見方をご存じない方はこちらのサイトで詳細がわかるので確認してください。

念の為、https://kabuoji3.com/robots.txtにアクセスし、robots.txtを確認したところ、rootからスクレイピングを許可してくれているので、ありがたくスクレイピングさせていただきます。(2019年7月14日時点)

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

必要なモジュールのインストール

pythonにはスクレイピングを簡単に行えるBeautifulSoupという便利なモジュールがあります。今回はこのBeautifulSoupというモジュールを利用したいと思います。
ただし、BeautifulSoup以外にも必要なモジュールがいくつかありますので、以下のモジュールがインストールされていない方は、pip installでインストールしてください。versionは最新のもので良いので特に指定しなくて良いです。
pipがよくわからない方はこちらをご参照ください。
Pythonの始め方④ pipとは?Pythonを便利に利用するためのpipの理解

  • bs4(BeautifulSoupのこと)
  • pandas
  • requests

PythonのBeautifulSoupを使って株価データをスクレイピング

モジュールのインポート

モジュールをインポートします。datetimeというモジュールをインポートしていますが、これはpythonの標準モジュールなので、pip installしなくてもpythonをインストールした時点ですでに存在しているはずです。

from bs4 import BeautifulSoup
import pandas as pd
import requests
from datetime import datetime

ページのhtmlを取得

取得したい銘柄の株価データは、https://kabuoji3.com/stock/以下に”/銘柄コード/年”という形式で存在しているようです。

y = 2019 #2019年
stock_number = 6577 #好きな銘柄コード、今回はベスト・ワンドットコム
url = 'https://kabuoji3.com/stock/{}/{}/'.format(stock_number,y)
soup = BeautifulSoup(requests.get(url).content,'html.parser')

上記のようにBeautifulSoupでページのHTMLソースを取得すると以下のようなHTMLが得られます。

<!DOCTYPE HTML>

<html class="no-js" lang="ja">
<head>
<meta charset="utf-8"/>
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="requiresActiveX=true">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<![endif]--><title>6577 (株)ベストワンドットコム 2019年度の株価データ・株価データ、CSVダウンロード | 株式投資メモ・株価データベース</title>
<meta content="6577 (株)ベストワンドットコム 2019年度の株価推移を時系列で確認できます。株価データのCSVダウンロードも可能です。株式投資、システムトレードや株価分析に有益な情報を多数配信!" name="description">
<meta content="6577,(株)ベストワンドットコム,マザーズ,サービス業,2019年,株式投資,株価,株価推移,時系列データ,CSVデータ,CSVダウンロード" name="keywords"/>
<meta content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"/>
<meta content="#fff" name="msapplication-TileColor"/>
<meta content="images/mstile-144x144.png" name="msapplication-TileImage"/>
<meta content="telephone=no" name="format-detection"/>
<link href="https://kabuoji3.com/images/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon"/>
<link href="https://kabuoji3.com/images/favicon.ico" rel="icon" type="image/vnd.microsoft.icon"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-57x57.png" rel="apple-touch-icon" sizes="57x57"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-60x60.png" rel="apple-touch-icon" sizes="60x60"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-72x72.png" rel="apple-touch-icon" sizes="72x72"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-76x76.png" rel="apple-touch-icon" sizes="76x76"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-114x114.png" rel="apple-touch-icon" sizes="114x114"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-120x120.png" rel="apple-touch-icon" sizes="120x120"/>
<link href="https://kabuoji3.com/images/apple-touch-icon-144x144.png" rel="apple-touch-icon" sizes="144x144"/>
...

株価データをデータフレーム化

ページのHTMLの構成を頑張って調べていきます。
調べると割と整ったテーブルになっており、trタグの中のthタグにテーブルのヘッドがあり、trタグの中のtdタグにデータが入っている構成でした。

tag_tr = soup.find_all('tr')
head = [h.text for h in tag_tr[0].find_all('th')] #テーブルのヘッドの取得

#テーブルの各データの取得
data = []
for i in range(1,len(tag_tr)):
    data.append([d.text for d in tag_tr[i].find_all('td')])
    df = pd.DataFrame(data, columns = head)

テキストデータを数値、タイムスタンプに変換

上で作成したdfを表示すると以下のようになっており、無事データフレーム化できたように思うのですが、見た目にはわからないのですが、実はすべてテキストデータなので、このままだとグラフを書いたりする時に扱いづらいままです。

したがって、数字をfloatに、日付をタイムスタンプに変換します。

col = ['始値','高値','安値','終値','出来高','終値調整']
for c in col:
    df[c] = df[c].astype(float)
df['日付'] = [datetime.strptime(i,'%Y-%m-%d') for i in df['日付']]

dfを再度表示すると以下のように数字の後ろに小数点が現れていると思います。(今回はわかりやすいようにfloatにしましたが、実際はintでも問題ありません)
見た目ではわかりませんが、日付もタイムスタンプに変換されているはずです。

複数年のデータの取得

このサイトでは株価データが年ごとに別ページにわかれているので、ページをfor文で繰り返して取得する必要があります。あと、最終的にはすべての年を1つのデータフレームにしたいので、結合したほうが良いと思います。ということで以下のようなコードになります。

#複数年のデータフレームの作成
dfs = []
year = [2018,2019]
for y in year:
    url = 'https://kabuoji3.com/stock/{}/{}/'.format(stock_number,y)
    soup = BeautifulSoup(requests.get(url).content,'html.parser')
    tag_tr = soup.find_all('tr')
    head = [h.text for h in tag_tr[0].find_all('th')]
    data = []
    for i in range(1,len(tag_tr)):
        data.append([d.text for d in tag_tr[i].find_all('td')])
    df = pd.DataFrame(data, columns = head)

    col = ['始値','高値','安値','終値','出来高','終値調整']
    for c in col:
        df[c] = df[c].astype(float)
    df['日付'] = [datetime.strptime(i,'%Y-%m-%d') for i in df['日付']]
    dfs.append(df)
 
#複数年のデータフレームの結合
data = pd.concat(dfs,axis=0)
data = data.reset_index(drop=True)

取得した株価の銘柄リストを作成する

自分が取得したい株価の銘柄リストを作成します。私が取得したい銘柄は10倍株検索をした以下の銘柄になります。
10倍株検索に関してはこちらを参照ください。
「いま仕込んでおくべき10倍株教えます!」に従って銘柄検索してみた

銘柄(コード) 銘柄名
2424ブラス
2820やまみ 
2970グッドライフC
3134Hamee
3172ティーライフ
3180ビューティガレージ
3189ANAP
3276日本管理
3457ハウスドゥ 
3474G-FAC
3480ジェイ・エス・ビー
3496アズーム
3566ユニネク
3674オークファン 
3695GMOリサーチ
3696セレス
3965CAP
3985テモナ
3986ビーブレイク
3992ニーズウェル
3997トレードワークス
6036KeePer技研
6038イード
6044三機サービス
6048デザインワン
6061ユニバ園芸
6087アビスト
6171土木管理総合試験所
6175ネットマーケティング
6199セラク
6558クックビズ
6577ベストワンドット
7042アクセスグループ
7813プラッツ
9270SOU

このテーブルをcsvにして以下のコードで読み込みます。

code_list = pd.read_csv('code list.csv')
code_list.head(10)

表示すると以下のようなcode listが得られているはずです。

まとめコード

最後に上記のコードを関数化し、複数の銘柄コードを取得するコードにしておきます。
古い年月まで含めるとデータがないですよと怒られることがあるので、try文を使ってエラー回避しています。
最後にcsvで保存しておきます。

from bs4 import BeautifulSoup
import pandas as pd
import requests
from datetime import datetime

def get_dfs(stock_number):
    dfs = []
    year = [2017,2018,2019] #2017〜2019年までの株価データを取得
    for y in year:
        try:
            print(y)
            url = 'https://kabuoji3.com/stock/{}/{}/'.format(stock_number,y)
            soup = BeautifulSoup(requests.get(url).content,'html.parser')
            tag_tr = soup.find_all('tr')
            head = [h.text for h in tag_tr[0].find_all('th')]
            data = []
            for i in range(1,len(tag_tr)):
                data.append([d.text for d in tag_tr[i].find_all('td')])
            df = pd.DataFrame(data, columns = head)

            col = ['始値','高値','安値','終値','出来高','終値調整']
            for c in col:
                df[c] = df[c].astype(float)
            df['日付'] = [datetime.strptime(i,'%Y-%m-%d') for i in df['日付']]
            dfs.append(df)
        except IndexError:
            print('No data')
    return dfs

def concatenate(dfs):
    data = pd.concat(dfs,axis=0)
    data = data.reset_index(drop=True)
    col = ['始値','高値','安値','終値','出来高','終値調整']
    for c in col:
        data[c] = data[c].astype(float)
    return data

#複数のデータフレームをcsvで保存
for i in range(len(df)):
    k = df.loc[i,'code']
    v = df.loc[i,'name']
    print(k,v)
    dfs = get_dfs(k)
    data = concatenate(dfs) 
    data.to_csv('{}-{}.csv'.format(k,v))

おすすめ書籍

スクレイピングに関してはこちらの書籍がおすすめです。

コメント

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