Rで競馬スピード指数をスクレイピング:ソースコード

R

netkeibaのレース条件のスクレイピング結果から、race_idを取り出して、その値をもとに、「競馬新聞&スピード指数(無料)」のサイトからスピード指数をスクレイピングしています。

スクレイピングを始める前に

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

Rでスクレイピングするならrvest 表もリンクもテキストも
Rでスクレイピングをするならrvestパッケージを使うのがベスト。表データ、リンク先URL、テキストなどのデータを簡単に入手できます。netkeibaのレース結果を題材にrvestパッケージの使い方をまとめています。
スクレイピングに必要な最低限のHTML/CSSの知識
スクレイピングでデータを収集するためには、HTMLで書かれたWebページの文書構造を理解し、どこに目的のデータが記載されているかをコンピュータに教えてやる必要があります。このページではスクレイピングに最低限必要なHTML/CSSの知識をまとめています。

スピード指数を取得する

このページは以下の記事に対応するRのソースコードを記載しています。

データサイエンスで競馬に挑戦!Rでスピード指数をスクレイピング

 

ソースコード

library(tidyverse)
library(lubridate)
library(rvest)


get_speed_index <- function(race_id){
  #urlの設定
  race_id2 <- substr(race_id, 3, 12)
  url_base <- "http://jiro8.sakura.ne.jp/index.php?code="
  url <- paste0(url_base, race_id2)
  
  #スクレイピング
  df.speed <- read_html(url, encoding = "CP932") %>% 
    html_element(css = "table.c1") %>% 
    html_table()
  
  Sys.sleep(1)
  
  #取得したデータの後処理
  
  #必要な行の抽出
  n_start <- str_which(df.speed$X1, "[牡|牝|せ]")
  df.speed2 <- df.speed[c(2, n_start:nrow(df.speed)), ]
  df.speed3 <- df.speed2[1:15, ]
  
  
  #必要な列の抽出
  n_col <- df.speed3[1,] %>% 
    as.character() %>% 
    str_which("馬番")
  
  n_col <- n_col -1
  df.speed4 <- df.speed3[, 1:n_col]
  
  #行と列の入れ替え(転置)
  df.speed5 <- t(df.speed4) 
  df.speed5 <- data.frame(df.speed5) 
  
  #データ形式の整理
  df.speed6 <- df.speed5 %>% 
    mutate(race_id = race_id, 
           X1 = as.integer(X1),
           X12 = as.numeric(X12), 
           X13 = as.numeric(X13), 
           X14 = as.numeric(X14), 
           X15 = as.numeric(X15),
           X6 = as.integer(str_remove(X6, "着"))
    ) %>% 
    relocate(race_id,) 
  
  #行名、列名の整理
  rownames(df.speed6) <- NULL
  colnames(df.speed6) <- c("race_id", "馬番", "性齢", "斤量2", 
                           "騎手", "調教師", "着順", "オッズ",
                           "レース結果", "ペース/脚質/上3F", 
                           "通過順", "馬体重", "先行指数", 
                           "ペース指数", "上がり指数", "スピード指数")
  
  df.speed6 <- df.speed6 %>% 
    arrange(着順) %>% 
    relocate(着順, .after = race_id)
  
  df.speed6
}



df.race.cond <- readRDS("df.race.cond.2012to2021.rds")
race_ids <- df.race.cond$race_id

filename.speed_index <-  "df.speed_index.rds"

#####################################################
#  1回目の場合(df.speed_indexが存在しない場合)
#####################################################
#
i <- 1
race_id <- race_ids[i]

df.speed_index <- get_speed_index(race_id)
saveRDS(df.speed_index, filename.speed_index)

###############################################################
#  2回め以降(filename.speed_indexで指定したファイルがある場合はここから)
###############################################################
df.speed_index <- readRDS(filename.speed_index)
(n_done <- length(unique(df.speed_index$race_id)))


i <- 0
id_count <- 0
tmp.df.speed_index <- NULL
tmp.filename.speed_index <- "tmp.df.speed_index.rds"


(id_max <- length(race_ids))
(max_id_to_calc <- min(n_done + 200000, id_max))   #最大処理回数(途中の確認用)


system.time({
  while(id_count < max_id_to_calc){
    i <- i + 1
    id_count <- n_done + i
    cat(paste("id_count =", id_count,
              "(", 
              floor(id_count/id_max*100*10) / 10,
              "%)",
              format(Sys.time(), "%H:%M:%S \n"),
              sep = " "
    )
    )
    race_id <- race_ids[id_count]

    # tmpファイルの処理
    if( is.null(tmp.df.speed_index)){
      tmp.df.speed_index <- get_speed_index(race_id)
    }else{
      tmp.df.speed_index <- rbind(tmp.df.speed_index, 
                                  get_speed_index(race_id))
    }
    
    if(id_count %% 100 == 0 | id_count == max_id_to_calc){
      cat("Save\n")
      df.speed_index <- rbind(df.speed_index, tmp.df.speed_index)

      saveRDS(df.speed_index, tmp.filename.speed_index)

      tmp.df.speed_index <- NULL

      i <- 0
      n_done <- length(unique(df.speed_index$race_id))
    }
  }
  
})

(n_done <- length(unique(df.speed_index$race_id)))

saveRDS(df.speed_index, filename.speed_index)