karasuex54’s blog

プログラミングよりイリヤの方が好き

競馬のお勉強 その1

初めましての人は初めまして、からすさんと申します。
競馬で取得したデータから上位を予想できることがゴールにし、いくつかのステップを目標に記録をつけていければと思っています。
データを取ろうとしているサイト名は「netkeiba.com」さんから
www.netkeiba.com
無料だからです。
今回は、「過去1年分の競馬馬データを取得する」ことを目標に進めていきます。
なぜ、過去1年分だけなのか?全部取ってくればいいじゃないかって見ている方の一部の人は思いますが、データ量が多くなれば時間がかかるのと、予想する馬は次に開催されるレースでそれに影響(が大きいと思われる)のは2年前、3年前じゃなくて過去1年間のデータであると考えたからです。
過去一年分の競馬馬データはどう絞り込むのか?僕はレースの開催日から絞り込むことを考えてみました。
日付ごとに調べる2018年1月6日では
2018年01月06日のレース情報 | 競馬データベース - netkeiba.com
f:id:karasuex54:20190311182329p:plain
と開催されたレースが各地毎に出てきます。このサイトから各レース先へのリンクが取得できれば
3歳未勝利|2018年01月06日 | 競馬データベース - netkeiba.com
f:id:karasuex54:20190311182835p:plain
テーブルになってるので「馬名、騎手...」などが取れます。(これはテーブルからのデータ取得はやったことあるから比較的簡単だと思う)
では、まず上の https://db.netkeiba.com/race/list/20180106/ のHTMLを見ていきたいと思います。
f:id:karasuex54:20190311184345p:plain
どうやら「中山」「京都」というのをそれぞれclass:race_top_hold_listとしてその下を探ればいけそうですね。

import requests
from bs4 import BeautifulSoup

BASE_URL = 'https://db.netkeiba.com/race/list/20180106/'
def get_url():
    global BASE_URL
    html = requests.get(BASE_URL)
    soup = BeautifulSoup(html.text, 'html.parser')
    for race_top in soup.find_all(class_='race_top_hold_list'):
        for race_data in race_top.dd.ul.find_all('li'):
            print(race_data.dl.dd.a.get('href'))
get_url()

上を起動したところ

/race/201806010101/
/race/201808010101/

と出力されましたが予想された出力数と異なります。(予想では12レースが2行ですので24個出力されるはず...)
取得されないところはどうやらJavaScriptを実行させないといけないみたいです。以下のサイトを参考に話をすすめます。
qiita.com
ブラウザで開いてからhtmlを取得させるので、ブラウザをPythonで操作するためにSeleniumというライブラリを使います。
加えて、開いてからhtmlを取得するさいにブラウザが起動しきる前に取得するとJavaScriptが実行され終わってないので上と同じ結果になりうると考えtimeライブラリも用いて改善したコードが次になります。
また、連続してウェブスクレイピングでサイトにアクセスするので今後のためにもとsleep関数を使えるようにしました。

import requests
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
import time

BASE_URL = 'https://db.netkeiba.com/race/list/20180106/'
def get_url():
    global BASE_URL
    options = Options()
    options.set_headless(True)
    driver = webdriver.Chrome(chrome_options=options)
    driver.get(BASE_URL)
    time.sleep(3)
    html = driver.page_source.encode('utf-8')
    soup = BeautifulSoup(html, 'html.parser')
    for race_top in soup.find_all(class_='race_top_hold_list'):
        for race_data in race_top.dd.ul.find_all('li'):
            print(race_data.dl.dd.a.get('href'))
get_url()

上を実行したところ

/race/201806010101/
/race/201806010102/
/race/201806010103/
/race/201806010104/
/race/201806010105/
/race/201806010106/
/race/201806010107/
/race/201806010108/
/race/201806010109/
/race/201806010110/
/race/201806010111/
/race/201806010112/
/race/201808010101/
/race/201808010102/
/race/201808010103/
/race/201808010104/
/race/201808010105/
/race/201808010106/
/race/201808010107/
/race/201808010108/
/race/201808010109/
/race/201808010110/
/race/201808010111/
/race/201808010112/

と出力されうまくいったと思います。