前回の記事でせっかくスピード指数をスクレイピングしてデータベースを作ったのだから、次のレースの検討に活かしたい‼️そうすれば、きっと…(笑)。というわけで、今週末開催されるレースの出走テーブルをnetkeibaさんからスクレイピングさせてもらうことにしました。
スピード指数のスクレイピングについてはこちら

出走テーブルのスクレイピング
スクレイピングを始める前に
Rでスクレイピングをするならrvestパッケージを使うのが簡単です。また、スクレイピングをするためにはHTML/CSSの理解も必要。とりあえず、これだけ知っていればスクレイピングは始められます。


コードの概要
出走テーブルの入手は以下のようなステップで行います。
- 出走テーブルを入手したい日付の設定
- 指定した日付のrace_idを取得
- 入手したrace_idに対応するページから出走テーブルページのhtmlデータを読み込む
- htmlデータから各馬共通の条件を抽出
- htmlデータから馬ごとのデータを抽出
- 4,5のデータを合体
- 入手したrace_idの個数分、3〜6を繰り返す
race_idの取得
入力値 :
race_date : 出走テーブルを取得したい日付。yyyymmdd形式。
戻り値:
指定した日に開催されるレースのrace_id。このrace_idでhtmlページ等は識別されている。
get_race_ids <- function(race_date){
#netkeiba開催日のページ
url_base <- "https://race.netkeiba.com/top/race_list_sub.html?kaisai_date="
url <- paste0(url_base, race_date)
#race_idの抽出
race_ids <- read_html(url, encoding = "UTF-8") %>%
html_nodes("a") %>%
html_attr("href") %>%
str_subset(".*race_id=") %>%
str_replace(".*race_id=", "") %>%
str_replace("&rf=.*", "") %>%
unique()
cat(" Sleep")
Sys.sleep(1)
cat(" Done\n")
race_ids
}
出走テーブルのページの読み込み
入力値: race_id
戻り値: race_idのページに対応するhtmlデータ
get_sheduled_race_html <- function(race_id){
url_base <- "https://race.netkeiba.com/race/shutuba.html?race_id="
url <- paste0(url_base, race_id)
html <- read_html(url, encoding = "EUC-JP")
cat(" Sleep")
Sys.sleep(1)
cat(" Done\n")
html
}
各馬共通の条件を抽出
入力値:
html: htmlデータ
race_id: race_id
戻り値:
全馬共通のレース情報(data.frame型)
get_sheduled_race_cond <- function(html, race_id){
#レース
race_No <- html %>%
html_element(".RaceNum") %>%
html_text() %>%
str_remove("R") %>%
as.integer()
#レース名
race_name <- html %>%
html_element(".RaceName") %>%
html_text() %>%
str_trim()
race_data01 <- html %>%
html_element(".RaceData01") %>%
html_text() %>%
str_remove_all("\n")
race_data02 <- html %>%
html_element(".RaceData02") %>%
html_text() %>%
str_split("\n") %>%
unlist()
# 開催
kaisai <- paste0(race_data02[2:4], collapse = "")
#競馬場
place <- race_data02[3]
#クラス
class <- paste0(race_data02[5:6], collapse = "")
#馬場
turf <- race_data01 %>%
str_split("/") %>%
.[[1]] %>%
.[2] %>%
str_trim() %>%
str_sub(1,1)
# 距離
distance <- race_data01 %>%
str_split("/") %>%
.[[1]] %>%
.[2] %>%
str_extract("\\d+") %>%
as.integer()
#左右
rotation <- race_data01 %>%
str_split("/") %>%
.[[1]] %>%
.[2] %>%
str_replace("^.*\\((.)\\)$", "\\1")
#戻り値用のdata.frameの準備
df.cond <- tibble("race_id" = race_id,
"開催" = kaisai,
"競馬場" = place,
"レース" = race_No,
"レース名" = race_name,
"クラス" = class,
"馬場" = turf,
"距離" = distance,
"左右" = rotation)
df.cond
}
馬ごとのデータの抽出
入力値:
html: htmlデータ
race_id: race_id
戻り値:
馬ごとのレース情報(data.frame型)
get_sheduled_race_horse <- function(html, race_id){
# 馬ごとのデータ(出馬表)
df.horse <- html %>%
html_element(".Shutuba_Table") %>%
html_table()
# data.frameの調整
names(df.horse) <- unlist(df.horse[1, ])
df.horse <- df.horse[-1, ]
df.horse <- df.horse %>%
select(`枠`, `馬番`, `馬名`, `性齢`, `斤量`, `騎手`, `厩舎`) %>%
mutate(race_id = race_id, .before = everything())
df.horse
}
出走テーブル取得関数(ある開催日のデータ取得)
入力値:
race_date: データを取得したい開催日
戻り値:
race_dateに対応する出走テーブル情報(data.frame型)
get_sheduled_race_table <- function(race_date){
# race_idの取得
race_ids <- get_race_ids(race_date)
#
df.cond <- NULL
df.horse <- NULL
for(race_id in race_ids){
# htmlデータの読み込み
html <- get_sheduled_race_html(race_id)
# 全馬共通条件の処理
df.cond.tmp <- get_sheduled_race_cond(html, race_id)
# 馬ごとのデータの処理
df.horse.tmp <- get_sheduled_race_horse(html, race_id)
# data.frameの合体
if(is.null(df.cond)){
df.cond <- df.cond.tmp
df.horse <- df.horse.tmp
}else{
df.cond <- rbind(df.cond, df.cond.tmp)
df.horse <- rbind(df.horse, df.horse.tmp)
}
}
# data.frameの合体
df.race.table <- left_join(df.cond, df.horse)
df.race.table
}
オッズ、人気順
ここで紹介したrvestを用いたスクレイピングは軽快に動作するのですが、netkeibaの出馬表データのうち、オッズ、人気順のデータは取得できません。オッズ、人気順を取得するためには、RSeleniumパッケージを利用する必要がありますが、動作は重くなります。活用法に応じて適宜使い分けが必要です。RSeleniumを用いた方法はこちら。

まとめ
今回のコードで週末に予定されているレースに出走する馬とレースの条件を入手できるようになりました。入手した出走テーブル情報と前回取得したスピード指数をリンクさせることで、より精度の高い検討ができるようになるはず(笑)。
スピード指数のスクレイピングはこちら

出馬表とスピード指数のスクレイピング結果を組み合わせるとこんなにわかりやすくなります。


競争結果のスクレイピングはこちら



