Introduction
rvestでスクレイピングするシリーズ。
今回は、以下記事でふれられている、「グランパスは先行逃げ切り特化型」説を検証するためのデータをこしらえていく。
grapo.net
サッカーって、そもそもリードされてから逆転するのが難しい競技ではありますが、こうも極端だと笑ってしまいます。
ハーフタイムでリードされてたら、勝てないどころか勝点0ってアンタ………そりゃきついぜ。
(上記サイトよりラグ氏)
本当にグランパスが他チームと比較して「先行逃げ切り特化型」なのかは、データにもとづく比較に基づいて判断する必要があるだろう
。
rvestでのスクレイピングに関する、基本的な解説はコチラ↓
ronri-rukeichi.hatenablog.com
どのページからとってくるか
前後半のscoreだけ取得するのであれば、Jリーグ公式記録ページ(例:湘南vs浦和)が手っ取り早い。
一覧ページもおあつらえ向きにあるので、一覧のリンクを取得するのもアホほど楽なのである。
しかし、シュート数を取得するとなると、話はかわってくる。
フットボールラボ*1の試合結果ページ(例:2019年の札幌vs清水)をみると、
得点の時間帯だけでなく、シュート、さらにはポゼッション率についても15分の粒度で得ることができる。
これをとりにいくのが、のちのちの利用機会を考えてもよいだろう。
データ取得の方法:得点編
場合わけ(得点をとってない場合もあるよねという話)
点数に関して、以下のようなテーブルをスクレイピング対象として、時間帯別の得点を取得してくるわけだが、
サッカーにおいてそこまで珍しくないスコアレスドローの試合(例:札幌vs 名古屋)においては、このテーブル自体がなくなる。
ので、デバッグ用のケースとして、以下のみっつの種類のURLを用意しておくのがよいだろう。
- 無得点
- いずれかのチームのみが得点
- Home/Away両方のチームが得点
上の得点テーブルはcssセレクターでいえば".tblCompare+.lineTbl table"*2によって取得することができる。
そして、上のセレクタで取得できる要素数が1であれば得点の入った試合、0であればスコアレスな試合、といった形で場合わけができる。
データ取得to整形
目標のテーブルが取得できたら、以下のような関数をかけばサクっとお目当てのデータがとれる
#####-------===[内部関数:Score tableから前後半/分/Home or Away、を取得する]===-------##### #[1], tbl : スコア表のテーブル scoreTimeTbl <- function(tbl){ min_HorA <- function(chr){ c_n <- nchar(chr) half <- substr( chr ,1, 2 ) #前後半のいずれかを判別するための文字列 min_chr <- substr( chr , 3 , c_n - 1) ret_c <- c( half, min_chr) names( ret_c) <- c("Half","Minutes") return(ret_c) }# function ##--- データフレーム形式に変換する---## score_df <- as.data.frame(do.call( what = rbind , args=lapply(tbl[,3], min_HorA ))) score_df$Half <- factor( score_df$Half , levels=c("前半","後半")) score_df$Minutes <- as.numeric( as.character(score_df$Minutes)) ##--- Home / Awayの変数をつくる---## home_idx <-which( tbl[,1] != "") away_idx <-which( tbl[,5] != "") h_a <- factor( rep( NA, nrow( tbl)) ,levels=c("Home", "Away")) h_a[home_idx] <- "Home" h_a[away_idx] <- "Away" score_df$HorA <- h_a return( score_df) } #function #####-------===[内部関数:scoreTimeTblの戻り値を前後半のスコアに変換]===-------##### getHalfScore <- function(score_df){ df_1st <- dplyr::filter( score_df , Half == "前半") df_2nd <- dplyr::filter( score_df , Half == "後半") #結局欲しいのは、前後半のゴール数/被ゴール数、という形式になってくるといえる。 goal_h_1st <- length(which( df_1st$HorA == "Home")) goal_a_1st <- length(which( df_1st$HorA == "Away")) goal_h_2nd <- length(which( df_2nd$HorA == "Home")) goal_a_2nd <- length(which( df_2nd$HorA == "Away")) #どっちが先制したかを判定し、変数として追加する goal_first_h <- ifelse( score_df[1,"HorA" ] == "Home", 1 , 0 ) goal_first_a <- ifelse( score_df[1,"HorA" ] == "Away", 1 , 0 ) # 戻り値としてdata frame形式に変換する rdf <- data.frame( Goal_For_1st = c(goal_h_1st , goal_a_1st ), Goal_Against_1st = c( goal_a_1st , goal_h_1st), Goal_For_2nd = c( goal_h_2nd , goal_a_2nd), Goal_Against_2nd = c( goal_a_2nd , goal_h_2nd), Goal_First = c( goal_first_h, goal_first_a)) rownames( rdf) <- c("Home","Away") return( rdf) } #function
使い方は以下の通り。
scr_page <- read_html( "https://www.football-lab.jp/sapp/report/?year=2019&month=03&date=09") st_df <- getScoreTbl(scr_page) st_df # Goal_For_1st Goal_Against_1st Goal_For_2nd Goal_Against_2nd Goal_First # Home 2 1 3 1 1 # Away 1 2 1 3 0
また、ここから、先制したかorされたかという変数も作成することができる。
時間帯別のポゼッション/シュート数を取得する
時間帯別のシュート/ポゼッションもfootball labのページでは15分刻みで記載されている。
これらの情報も、以下の方法で取得できる。
Possessionを取得する
cssセレクタ的には、".homePoss em"や".awayPoss em"で、ポゼッションの情報にアクセスする。
以下のような関数を用意する。
getPossession <- function( gpage ){ ##--- Home --- ## hm_ps_l <- html_nodes(gpage, css= ".homePoss em") #タグで取得 hm_ps_v <- sapply( hm_ps_l , function( ps_node){ pos_txt <- html_text( ps_node) #XX% pos_n <- nchar( pos_txt) return( as.numeric( substr( pos_txt , 1, pos_n- 1))) }) #sapply ##--- Away --- ## aw_ps_l <- html_nodes(gpage, css= ".awayPoss em") #タグで取得 aw_ps_v <- sapply( aw_ps_l , function( ps_node){ pos_txt <- html_text( ps_node) #XX% pos_n <- nchar( pos_txt) return( as.numeric( substr( pos_txt , 1, pos_n- 1))) }) #sapply return( list(Home = hm_ps_v , Away = aw_ps_v)) } #Function
つかった結果はこちら、
> getPossession( scr_page) # $Home # [1] 42.4 42.8 50.5 50.0 45.8 65.6 # $Away # [1] 57.6 57.2 49.5 50.0 54.2 34.4
ポゼッションも時間帯別に取得できている。
Conclusion
これで、時間帯別の各データがそろった。
次の記事で実際の分析を行いたいが、その前に差分を取得するプログラムを実装しなくては。
Astral Chain OP(オープニングテーマ)Savior Full Version
Enjoy!!