Se realiza una introducción al web scraping con el paquete rvest para la cosecha de datos de la web.
El “web scraping” es un proceso automatizado de recolección de datos e información de los sitios web. R es un lenguaje de programación muy popular para el web scraping. En él se utilizará un popular paquete de R llamado rvest para el raspado de datos web. rvest es un paquete que facilita el scrape (o cosecha) de datos de páginas web html, inspirado en librerías como beautiful soup. Está diseñado para trabajar con magrittr de manera que puedas expresar operaciones complejas como elegantes pipelines compuestos de piezas simples y fáciles de entender (Wickham 2021).
Para realizar el web scraping (raspado de datos web), las librerías más usuales son rvest y rselenium. En este caso daremos uso al paquete rvest (Wickham 2021). Para la limpieza de datos se usará el paquete tidyverse (Wickham et al. 2019).
Los datos a explorar serán de la página web de Worldometer. Esta página contiene diferentes reportes estadídticos; sin embargo, a nosotros nos interesa los reportes diarios del COVID-19 del mundo. Para ello se procederá de la siguiente manera:
#Raspar datos formato tabla
url = "https://www.worldometers.info/coronavirus/"
datacovid = read_html(url) %>%
html_table()
head(datacovid)
[[1]]
# A tibble: 238 x 22
`#` `Country,Other` TotalCases NewCases TotalDeaths NewDeaths
<int> <chr> <chr> <chr> <chr> <chr>
1 NA "North America" 39,918,340 "+12,259" 901,223 "+390"
2 NA "Asia" 52,085,649 "+181,453" 703,621 "+4,538"
3 NA "South America" 29,331,975 "+11,596" 908,166 "+247"
4 NA "Europe" 46,808,469 "+38,336" 1,076,895 "+1,023"
5 NA "Africa" 4,929,333 "+5,436" 131,967 "+88"
6 NA "Oceania" 69,077 "+49" 1,252 ""
7 NA "" 721 "" 15 ""
8 NA "World" 173,143,564 "+249,129" 3,723,139 "+6,286"
9 1 "USA" 34,178,104 "+3,352" 611,710 "+99"
10 2 "India" 28,685,804 "+113,445" 343,954 "+3,235"
# … with 228 more rows, and 16 more variables: TotalRecovered <chr>,
# NewRecovered <chr>, ActiveCases <chr>, Serious,Critical <chr>,
# Tot\U00a0Cases/1M pop <chr>, Deaths/1M pop <chr>,
# TotalTests <chr>, Tests/1M pop <chr>, Population <chr>,
# Continent <chr>, 1 Caseevery X ppl <chr>,
# 1 Deathevery X ppl <chr>, 1 Testevery X ppl <int>,
# New Cases/1M pop <dbl>, New Deaths/1M pop <dbl>,
# Active Cases/1M pop <chr>
[[2]]
# A tibble: 238 x 22
`#` `Country,Other` TotalCases NewCases TotalDeaths NewDeaths
<int> <chr> <chr> <chr> <chr> <chr>
1 NA "Asia" 51,904,196 "+210,332" 699,083 "+4,107"
2 NA "North America" 39,906,081 "+32,047" 900,833 "+1,027"
3 NA "South America" 29,320,379 "+167,900" 907,919 "+4,142"
4 NA "Europe" 46,770,133 "+50,729" 1,075,872 "+1,208"
5 NA "Africa" 4,923,897 "+14,498" 131,879 "+253"
6 NA "Oceania" 69,028 "+211" 1,252 ""
7 NA "" 721 "" 15 ""
8 NA "World" 172,894,435 "+475,717" 3,716,853 "+10,737"
9 1 "China" 91,170 "+24" 4,636 ""
10 2 "USA" 34,174,752 "+17,821" 611,611 "+574"
# … with 228 more rows, and 16 more variables: TotalRecovered <chr>,
# NewRecovered <chr>, ActiveCases <chr>, Serious,Critical <chr>,
# Tot\U00a0Cases/1M pop <chr>, Deaths/1M pop <chr>,
# TotalTests <chr>, Tests/1M pop <chr>, Population <chr>,
# Continent <chr>, 1 Caseevery X ppl <chr>,
# 1 Deathevery X ppl <chr>, 1 Testevery X ppl <int>,
# New Cases/1M pop <chr>, New Deaths/1M pop <dbl>,
# Active Cases/1M pop <chr>
[[3]]
# A tibble: 238 x 22
`#` `Country,Other` TotalCases NewCases TotalDeaths NewDeaths
<int> <chr> <chr> <chr> <chr> <chr>
1 NA "Asia" 51,693,864 "+211,296" 694,976 "+4,237"
2 NA "North America" 39,874,034 "+34,275" 899,806 "+713"
3 NA "South America" 29,152,479 "+179,599" 903,777 "+4,321"
4 NA "Europe" 46,719,404 "+52,612" 1,074,664 "+1,404"
5 NA "Africa" 4,909,399 "+13,439" 131,626 "+307"
6 NA "Oceania" 68,817 "+135" 1,252 ""
7 NA "" 721 "" 15 ""
8 NA "World" 172,418,718 "+491,356" 3,706,116 "+10,982"
9 1 "China" 91,146 "+24" 4,636 ""
10 2 "USA" 34,156,931 "+16,881" 611,037 "+512"
# … with 228 more rows, and 16 more variables: TotalRecovered <chr>,
# NewRecovered <chr>, ActiveCases <chr>, Serious,Critical <chr>,
# Tot\U00a0Cases/1M pop <chr>, Deaths/1M pop <chr>,
# TotalTests <chr>, Tests/1M pop <chr>, Population <chr>,
# Continent <chr>, 1 Caseevery X ppl <chr>,
# 1 Deathevery X ppl <chr>, 1 Testevery X ppl <int>,
# New Cases/1M pop <chr>, New Deaths/1M pop <dbl>,
# Active Cases/1M pop <chr>
En este caso se pudo obtener tres tablas con su respectiva información. La primera tabla se refiere a la información COVID de hoy. La segunda tabla es la información COVID de ayer y la tercera es información de hace dos días.
Para este propósito realizaremos la limpieza de datos de la primera tabla.
# Asignar a un objeto la primera tabla
table1 = datacovid[[1]]
head(table1)
# A tibble: 6 x 22
`#` `Country,Other` TotalCases NewCases TotalDeaths NewDeaths
<int> <chr> <chr> <chr> <chr> <chr>
1 NA North America 39,918,340 +12,259 901,223 "+390"
2 NA Asia 52,085,649 +181,453 703,621 "+4,538"
3 NA South America 29,331,975 +11,596 908,166 "+247"
4 NA Europe 46,808,469 +38,336 1,076,895 "+1,023"
5 NA Africa 4,929,333 +5,436 131,967 "+88"
6 NA Oceania 69,077 +49 1,252 ""
# … with 16 more variables: TotalRecovered <chr>, NewRecovered <chr>,
# ActiveCases <chr>, Serious,Critical <chr>,
# Tot\U00a0Cases/1M pop <chr>, Deaths/1M pop <chr>,
# TotalTests <chr>, Tests/1M pop <chr>, Population <chr>,
# Continent <chr>, 1 Caseevery X ppl <chr>,
# 1 Deathevery X ppl <chr>, 1 Testevery X ppl <int>,
# New Cases/1M pop <dbl>, New Deaths/1M pop <dbl>,
# Active Cases/1M pop <chr>
Los datos no estan limpios para operar algun análisis exploratorio, para ello necesitamos eliminar las primeras filas de continentes y las últimas filas de totales. El propósito es solamente quedarse con los países.
Para este proceso, necesito filtrar a traves de la columna #, ya que solamente anumera a los países.
El objeto aux es para diferencias entre los números perdidos (NA) y los dátos existentes en la columna #. La función is.na identificará datos faltantes. Si identifica NA nos dirá TRUE y se encuentra información será FALSE. Esto nos ayuda a filtrar de forma más sencilla y quedarnos con los datos que requerimos.
#Filtrado de datos
aux = is.na(table1$'#')
tablecountry = table1[!aux,]
tablecountry
# A tibble: 222 x 22
`#` `Country,Other` TotalCases NewCases TotalDeaths NewDeaths
<int> <chr> <chr> <chr> <chr> <chr>
1 1 USA 34,178,104 "+3,352" 611,710 "+99"
2 2 India 28,685,804 "+113,445" 343,954 "+3,235"
3 3 Brazil 16,803,472 "" 469,784 ""
4 4 France 5,694,076 "" 109,857 ""
5 5 Turkey 5,276,468 "+6,169" 47,976 "+94"
6 6 Russia 5,108,129 "+8,947" 123,037 "+377"
7 7 UK 4,506,016 "+6,238" 127,823 "+11"
8 8 Italy 4,227,719 "+2,557" 126,415 "+73"
9 9 Argentina 3,884,447 "" 79,873 ""
10 10 Germany 3,702,866 "+1,176" 89,637 "+32"
# … with 212 more rows, and 16 more variables: TotalRecovered <chr>,
# NewRecovered <chr>, ActiveCases <chr>, Serious,Critical <chr>,
# Tot\U00a0Cases/1M pop <chr>, Deaths/1M pop <chr>,
# TotalTests <chr>, Tests/1M pop <chr>, Population <chr>,
# Continent <chr>, 1 Caseevery X ppl <chr>,
# 1 Deathevery X ppl <chr>, 1 Testevery X ppl <int>,
# New Cases/1M pop <dbl>, New Deaths/1M pop <dbl>,
# Active Cases/1M pop <chr>
La base de datos aún presenta signos + y , en las columnas. El siguiente procedimiento es quitar esos signos y convertirlo a datos numéricos.
#Eliminando los signos
tableclean = tablecountry %>%
mutate_at(3:15, parse_number)
head(tableclean)
# A tibble: 6 x 22
`#` `Country,Other` TotalCases NewCases TotalDeaths NewDeaths
<int> <chr> <dbl> <dbl> <dbl> <dbl>
1 1 USA 34178104 3352 611710 99
2 2 India 28685804 113445 343954 3235
3 3 Brazil 16803472 NA 469784 NA
4 4 France 5694076 NA 109857 NA
5 5 Turkey 5276468 6169 47976 94
6 6 Russia 5108129 8947 123037 377
# … with 16 more variables: TotalRecovered <dbl>, NewRecovered <dbl>,
# ActiveCases <dbl>, Serious,Critical <dbl>,
# Tot\U00a0Cases/1M pop <dbl>, Deaths/1M pop <dbl>,
# TotalTests <dbl>, Tests/1M pop <dbl>, Population <dbl>,
# Continent <chr>, 1 Caseevery X ppl <chr>,
# 1 Deathevery X ppl <chr>, 1 Testevery X ppl <int>,
# New Cases/1M pop <dbl>, New Deaths/1M pop <dbl>,
# Active Cases/1M pop <chr>
Ahora nuestra base de datos desde la colunma 3 al 15 ya estan en formato numérica. La cual posibilita realizar operaciones estadíticas.
rvest es muy manejable para raspar datos de la web. En esta opurtunidad solamente vimos una opción de cosecha de datos disponibles en formato tabla. Para datos que no esten en formato tabla se requiere utilizar una herramienta llamada selector gadget. Esta herramienta ayuda a extraer nodos de html y a traves de ellos capturamos información.
For attribution, please cite this work as
Santos (2021, June 1). Franklin Santos: Cosecha de datos de la web. Retrieved from https://franklinsantos.com/posts/2021-05-31-webscraping/
BibTeX citation
@misc{santos2021cosecha,
author = {Santos, Franklin},
title = {Franklin Santos: Cosecha de datos de la web},
url = {https://franklinsantos.com/posts/2021-05-31-webscraping/},
year = {2021}
}