Este paper visa fazer uma rápida introdução e exemplificação de web scraping(coleta de dados da internet), resolvendo um problema para muitos estatísticos e/ou aspirantes a data science amantes do principal esporte nacional, o futebol. É comum ver no início da faculdade, jovens dando os primeiros passos em análise de dados e/ou modelagem buscando por dados de futebol(eu sou o exemplo vivo rs), perdi muito tempo googlando atrás de uma base de jogos estruturadas no início da faculdade. Assim sendo, o objetivo desse paper é ensinar a buscar e estruturar dados de jogos do campeonato brasileiro de 2012 à 2019. que ficará disponível nesse repostirório no meu github
O site da CBF é bem simples e intuitivo, os dados de jogos e os respectivos resultados do campeonato brasileiro podem ser obtidos nesse link https://www.cbf.com.br/futebol-brasileiro/competicoes/campeonato-brasileiro-serie-a/2019. Observe que no final do link aparece o 2019 que redireciona para a página do campeonato de 2019.
É possível ver que temos disponíveis as tabelas de 2012 à 2020(que ainda não iniciou), e que ao selecionar cada um dos anos disponíveis, a alteração feita na url é somente no último termo como destacado no link da foto, ao qual está com 2019 como valor atual, o que nos leva a página do campeonato de 2019. Temos aqui o primeiro padrão observado. Vamos guardar essa informação mais para frente.
O que queremos são as informações do quadro a direita da tabela de classificação, onde temos as informações das rodadas e resultado dos jogos. A questão aqui é o que estamos buscando. O primeiro passo é inspecionar o html, que a primeira vista parece algo de outro mundo, mas que se olharmos com calma pode ser feito sem muito conhecimento sobre o assunto, eu mesmo não sou especialista no assunto(muito longe disso rs). Para quem quiser entender mais afundo sobre html, existem muitos papers e livros sobre o assunto, um que indico e me ajudou bastante a entender a estrutura foi um tutorial da w3schools.com. Vamos então avaliar a estrutura do quadro que contém os dados de interesse:
Dessa forma conseguimos encontrar padrões e observar a principal classe de interesse aside-rodadas, classe a qual engloba todos os dados com informações sobre as rodadas do Brasileirão. Com isso em mente, vamos para o R!
Para essa extração, os pacotes necessários são os seguintes: rvest, xml2, stringr e glue.
library(stringr)
library(rvest)
library(glue)
Como mencionado, é possível notar que a classe aside-rodadas engloba todos os dados da tabela de jogos, vamos então fazer a leitura desses dados utilizando os pacotes rvest e xml2:
url <- glue("https://www.cbf.com.br/futebol-brasileiro/competicoes/campeonato-brasileiro-serie-a/2019")
resultados <- url %>%
read_html() %>%
html_nodes(".aside-rodadas")
head(resultados)
## {xml_nodeset (1)}
## [1] <aside class="aside-rodadas swiper-container"><div class="swiper-wrapper" ...
Dessa forma, temos a estrutura html da tabela de resultados dos jogos atribuído a lista resultados. precisamos agora extrair as informações que são pertinentes da tabela e estrutura-la para análises posteriores. Os campos que estamos buscando são:
- Time Casa: é possível notar na estrutura que as classes que englobam as siglas dos times da casa são
pull-leftetime-sigla;- Time Fora: para o time de fora, as classes são
pull-rightetime-sigla- Placar: por último, mas não menos importante, o placar, que é agrupado pela classe
partida-horario.
Sendo assim, conseguimos extrair a partir da estrutura html que atribuímos a resultados, com as classes identificadas, as informações de interesse e estruturar nosso dataframe.
#Extraindo informações de time da casa
casa <- resultados %>%
html_nodes(".pull-left .time-sigla") %>%
html_text()
#Extraindo informações de time de fora
fora <- resultados %>%
html_nodes(".pull-right .time-sigla") %>%
html_text()
#Extraindo informações de time do placar
placar <- resultados %>%
html_nodes(".partida-horario") %>%
html_text() %>%
str_extract("[0-9]{1}\ x\ [0-9]{1}")
#Gerando valores de rodadas
rodada <- 0:(length(placar)-1) %/% 10 + 1
#Estruturando dados coletados em dataframe
df <- data.frame(cbind(rodada = rodada,
casa = casa,
placar = placar,
fora = fora,
ano = rep(2019,length(rodada) ) ) )
df %>%
head() %>%
knitr::kable() %>%
kableExtra::kable_styling()
## Warning in kableExtra::kable_styling(.): Please specify format in kable.
## kableExtra can customize either HTML or LaTeX outputs. See https://
## haozhu233.github.io/kableExtra/ for details.
| rodada | casa | placar | fora | ano |
|---|---|---|---|---|
| 1 | SAO | 2 x 0 | BOT | 2019 |
| 1 | ATL | 2 x 1 | AVA | 2019 |
| 1 | CHA | 2 x 0 | INT | 2019 |
| 1 | FLA | 3 x 1 | CRU | 2019 |
| 1 | GRE | 1 x 2 | SAN | 2019 |
| 1 | CEA | 4 x 0 | CSA | 2019 |
E voìla! Temos um um dataframe dos jogos do brasileirão, extraído diretamente do site da CBF.
Porém, isso não é tudo, lembra que falei para guardar a informação da mudança no link ao selecionar o ano do campeonato? Então, agora é a hora de utilizar essa informação!
Faremos um loop utilizando o auxílio do pacote glue para alterar o ano da url e faremos um incremento dos dados na tabela final para termos os dados de todos os jogos dos campeonatos desde 2012.
for(i in 2012:2019) {
url <- glue("https://www.cbf.com.br/futebol-brasileiro/competicoes/campeonato-brasileiro-serie-a/{i}")
resultados <- url %>%
read_html() %>%
html_nodes(".aside-rodadas")
casa <- resultados %>%
html_nodes(".pull-left .time-sigla") %>%
html_text()
fora <- resultados %>%
html_nodes(".pull-right .time-sigla") %>%
html_text()
placar <- resultados %>%
html_nodes(".partida-horario") %>%
html_text() %>%
str_extract("[0-9]{1}\ x\ [0-9]{1}")
rodada <- 0:(length(placar)-1) %/% 10 + 1
df <- if( i == 2012)
{
data.frame(cbind(rodada = rodada,
casa = casa,
placar = placar,
fora = fora,
ano = rep(i,length(rodada) ) ) ) }
else{
data.frame(rbind(df, cbind(rodada = rodada,
casa = casa,
placar = placar,
fora = fora,
ano = rep(i,length(rodada) ) ) ))
}
}
# write.csv(df, "Brasileirao_Jogos_2012_2019.csv") #salvando df
summary(df) %>%
knitr::kable() %>%
kableExtra::kable_styling()
| rodada | casa | placar | fora | ano | |
|---|---|---|---|---|---|
| 1 : 80 | ATL : 285 | 1 x 0 : 463 | ATL : 285 | 2012 :380 | |
| 10 : 80 | COR : 266 | 1 x 1 : 370 | COR : 266 | 2013 :380 | |
| 11 : 80 | SAN : 171 | 2 x 1 : 293 | SAN : 171 | 2014 :380 | |
| 12 : 80 | CRU : 152 | 0 x 0 : 275 | CRU : 152 | 2015 :380 | |
| 13 : 80 | FLA : 152 | 2 x 0 : 274 | FLA : 152 | 2016 :380 | |
| 14 : 80 | FLU : 152 | (Other):1364 | FLU : 152 | 2017 :380 | |
| (Other):2560 | (Other):1862 | NA’s : 1 | (Other):1862 | (Other):760 |
E dessa forma temos o nosso df estruturado com os jogos dos Brasileirões de 2012 a 2019. Até a próxima!