競馬のお勉強 その3
からすさんです。
競馬のお勉強その1(競馬のお勉強 その1 - karasuex54’s blog)とその2(競馬のお勉強 その2 - karasuex54’s blog)では、seleniumを使ったウェブスクレイピングを行いましたが、そうすると実行時間が長くなるのでいくつか改善点(前のが愚直だったから今回のが普通やと思えるけどな...)を言っていこうかと思います。
その1で欲しいのはレースを記述してるhref属性の値でした。そこで
www.shoshinsha.com
a属性を見ていきます。
import requests from bs4 import BeautifulSoup import re def get_url(): BASE_URL = 'https://db.netkeiba.com/race/list/20180106/' r = requests.get(BASE_URL) r.encoding = r.apparent_encoding soup = BeautifulSoup(r.text, 'html.parser') for a in soup.find_all('a'): print(a) get_url()
(はてな記法でPythonにすると色がつかずpythonにすると色がついた...知見を得た)
上を実行すると出力されるaに
... <a href="/race/201806010101/" title="3歳未勝利">3歳未勝利</a> <a href="/race/movie/201806010101"><img border="0" src="/style/netkeiba.ja/image/icon_douga.png">レース映像</img></a> <a href="/race/201806010102/" title="3歳未勝利">3歳未勝利</a> <a href="/race/movie/201806010102"><img border="0" src="/style/netkeiba.ja/image/icon_douga.png"/>レース映像</a> <a href="/race/201806010103/" title="3歳新馬">3歳新馬</a> <a href="/race/movie/201806010103"><img border="0" src="/style/netkeiba.ja/image/icon_douga.png"/>レース映像</a> <a href="/race/201806010104/" title="4歳上500万下">4歳上500万下</a> <a href="/race/movie/201806010104"><img border="0" src="/style/netkeiba.ja/image/icon_douga.png"/>レース映像</a> ...
とレース内容を得ることができました。次に得られたa全部に対してhrefを正規表現で絞り込んでいこうと思います。
今回は欲しい情報が「/race/20~~」とわかっているので、
for a in soup.find_all('a', href=re.compile('/race/20')): print(a)
と変えその出力は
... <a href="/race/201806010104/" title="4歳上500万下">4歳上500万下</a> <a href="/race/201806010105/" title="3歳未勝利">3歳未勝利</a> <a href="/race/201806010106/" title="3歳500万下">3歳500万下</a> <a href="/race/201806010107/" title="4歳上500万下">4歳上500万下</a> <a href="/race/201806010108/" title="4歳上1000万下">4歳上1000万下</a> <a href="/race/201806010109/" title="招福S(1600万下)">招福S(1600万下)</a> <a href="/race/201806010110/" title="ジュニアC(OP)">ジュニアC(OP)</a> <a href="/race/201806010111/" title="日刊スポ賞中山金杯(G3)">日刊スポ賞中山金杯(G3)</a> <a href="/race/201806010112/" title="4歳上1000万下">4歳上1000万下</a> <a href="/race/201808010101/" title="3歳未勝利">3歳未勝利</a> <a href="/race/201808010102/" title="3歳未勝利">3歳未勝利</a> <a href="/race/201808010103/" title="3歳未勝利">3歳未勝利</a> <a href="/race/201808010104/" title="4歳上500万下">4歳上500万下</a> ...
欲しいところが出てきました^^(レース数24個のね)
あとは割愛します。
その2に関しては上のコードで
r = requests.get(BASE_URL)
r.encoding = r.apparent_encoding
soup = BeautifulSoup(r.text, 'html.parser')
を利用すればいいのでおわおわりです。やったねたえちゃん
Twitterに自動投稿
ここをみた
shiguregaki.hatenablog.com
以上
競馬のお勉強 その2
からすさんです。
前回はある日のレース一覧のurlを取得することに成功しました。
今回はあるレースのサイトに対して(次に示すよ)
db.netkeiba.com
上のサイトにあるテーブルを一つずつ取得していこうと思います。
取得したhtml内からtableを探し、その下から手に入れます。とりあえずコード書きましょう。
下に書いたのを置いとくね
import requests from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.chrome.options import Options import time def get_uma(): GET_UMA = 'https://db.netkeiba.com/race/201806030301/' options = Options() options.set_headless(True) driver = webdriver.Chrome(chrome_options=options) driver.get(GET_UMA) time.sleep(2) html = driver.page_source.encode('utf-8') soup = BeautifulSoup(html, 'html.parser') print(len(soup.table.tbody.find_all('tr'))) for tr in soup.table.tbody.find_all('tr')[1:]: for td in tr.find_all('td'): print(td.text.replace(' ','').replace('\n',''),end=' ') print() get_uma()
seleniumを使ったらhtml内の文字バケなおるしやるの簡単だったからやりました。seleniumを使わずにやったんだけどわからなかったから甘えたよ。
td内で出力したら改行されたり空白があってむかついたので消しました。目障りなものは消した方がいいです、後のDBへの格納のために...
実行したら
1 2 4 マローネメタリコ 牝3 54 二本柳壮 1:12.8 ** 10-9 36.3 47.5 10 486(0) [東]萩原清 柏瀬金之介 500.0 2 5 10 クロスデスティニー 牝3 54 大野拓弥 1:13.1 1.3/4 ** 7-6 37.3 22.9 7 478(0) [東]奥平雅士 キャロットファーム 200.0 3 5 9 アポロアミ 牝3 54 津村明秀 1:13.1 クビ ** 2-2 38.1 3.2 2 434(+2) [東]矢野英一 アポロサラブレッドクラブ 130.0 4 2 3 クインズティガ 牝3 54 戸崎圭太 1:13.3 1 ** 4-3 38.0 3.0 1 458(+2) [東]奥平雅士 亀田和弘 75.0 5 3 5 ベリンダ 牝3 54 三浦皇成 1:13.4 3/4 ** 9-10 37.3 19.3 6 434(+8) [東]栗田徹 ノースヒルズ 50.0 6 6 12 ボナデア 牝3 54 宮崎北斗 1:13.5 クビ ** 3-3 38.3 48.3 11 488(-6) [東]中川公成 山上和良 7 7 13 ラブヘネシー 牝3 51 横山武史 1:13.9 2.1/2 ** 4-3 38.6 42.4 9 432(-6) [東]蛯名利弘 増田陽一 8 6 11 ダブルミリオン 牝3 54 柴田大知 1:13.9 クビ ** 7-8 38.1 10.5 4 462(0) [東]小笠倫弘 サラブレッドクラブ・ラフィアン 9 8 16 ミヤビフィオーラ 牝3 54 松岡正海 1:14.1 1.1/2 ** 1-1 39.1 4.3 3 422(-2) [東]中舘英二 村上義勝 10 1 1 パンテラ 牝3 54 北村宏司 1:14.3 1.1/4 ** 6-6 38.7 15.9 5 426(-4) [東]田島俊明 佐藤範夫 11 4 8 プリプリクインダム 牝3 51 菊沢一樹 1:14.8 3 ** 11-11 38.1 181.9 13 466(-20) [東]菊沢隆徳 澤田孝之 12 8 15 ヒミコ 牝3 54 吉田隼人 1:14.9 クビ ** 13-12 38.1 31.9 8 448(-2) [東]武井亮 幅田京子 13 4 7 エスパージョー 牝3 54 丸山元気 1:15.4 3 ** 15-15 36.9 230.0 14 442(0) [東]根本康広 泉一郎 14 1 2 フェアリーソング 牝3 54 ミナリク 1:15.7 2 ** 14-14 38.4 70.4 12 424(+2) [東]加藤征弘 高橋正雄 15 3 6 ラブソングレイ 牝3 51 木幡育也 1:17.5 大 ** 11-12 40.8 378.8 16 402(0) [東]菊川正達 キヨタケ牧場 16 7 14 グリーンライト 牝3 53 木幡初也 1:21.4 大 ** 16-16 42.0 236.3 15 464(0) [東]加藤和宏 畠山牧場
成功しました。アムロ感激ぃ~
競馬のお勉強 その1
初めましての人は初めまして、からすさんと申します。
競馬で取得したデータから上位を予想できることがゴールにし、いくつかのステップを目標に記録をつけていければと思っています。
データを取ろうとしているサイト名は「netkeiba.com」さんから
www.netkeiba.com
無料だからです。
今回は、「過去1年分の競馬馬データを取得する」ことを目標に進めていきます。
なぜ、過去1年分だけなのか?全部取ってくればいいじゃないかって見ている方の一部の人は思いますが、データ量が多くなれば時間がかかるのと、予想する馬は次に開催されるレースでそれに影響(が大きいと思われる)のは2年前、3年前じゃなくて過去1年間のデータであると考えたからです。
過去一年分の競馬馬データはどう絞り込むのか?僕はレースの開催日から絞り込むことを考えてみました。
日付ごとに調べる2018年1月6日では
2018年01月06日のレース情報 | 競馬データベース - netkeiba.com
と開催されたレースが各地毎に出てきます。このサイトから各レース先へのリンクが取得できれば
3歳未勝利|2018年01月06日 | 競馬データベース - netkeiba.com
テーブルになってるので「馬名、騎手...」などが取れます。(これはテーブルからのデータ取得はやったことあるから比較的簡単だと思う)
では、まず上の https://db.netkeiba.com/race/list/20180106/ のHTMLを見ていきたいと思います。
どうやら「中山」「京都」というのをそれぞれ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/
と出力されうまくいったと思います。