Capítulo 7 Extracción de datos de la web
En apartados anteriores hemos visto cómo importar ficheros para trabajar con los datos. Veremos ahora cómo obtenerlos desde la web.
7.1 Importación de tablas desde Wikipedia
Comenzaremos con el paquete htmltab
que nos permite importar tablas disponibles en Wikipedia. Procederemos a extraer los datos de población mundial de una tabla disponible en: https://en.wikipedia.org/wiki/World_population.
Por defecto, si no ofrecemos ningún argumento, la función importa la primera tabla disponible, tal como nos indica el mensaje de respuesta.
library(htmltab)
<- htmltab("https://en.wikipedia.org/wiki/World_population") tabla
## Argument 'which' was left unspecified. Choosing first table.
Si queremos importar otra tabla (por ejemplo, la octava) sólo hay que indicarlo. Lo hacemos y visualizamos las primeras filas.
<- htmltab("https://en.wikipedia.org/wiki/World_population", 8)
tabla8 head(tabla8)
## Year Population Yearly growth >> % Yearly growth >> Number Density(pop/km)
## 3 1951 2,584,034,261 1.88% 47,603,112 17
## 4 1952 2,630,861,562 1.81% 46,827,301 18
## 5 1953 2,677,608,960 1.78% 46,747,398 18
## 6 1954 2,724,846,741 1.76% 47,237,781 18
## 7 1955 2,773,019,936 1.77% 48,173,195 19
## 8 1956 2,822,443,282 1.78% 49,423,346 19
## Urban population >> Number Urban population >> %
## 3 775,067,697 30%
## 4 799,282,533 30%
## 5 824,289,989 31%
## 6 850,179,106 31%
## 7 877,008,842 32%
## 8 904,685,164 32%
Procederemos ahora a obtener la población de los municipios catalanes desde otra tabla también disponible en Wikipedia. En este caso, el mensaje de warning nos indica que, dado que la última columna parece estar vacía, la ha suprimido. No obstante, también nos ofrece información sobre cómo resolver el problema si queremos conservar este campo.
<- htmltab("https://en.wikipedia.org/wiki/Municipalities_of_Catalonia", 1) Municipis
## Warning: Columns [No. ofEMDs] seem to have no data and are removed. Use
## rm_nodata_cols = F to suppress this behavior.
Si visualizamos la estructura de la tabla, vemos que la información está en formato character (chr), por lo que no podremos hacer cálculos (por ejemplo, ¿cuál es la población media de los municipios catalanes?).
str(Municipis)
## 'data.frame': 948 obs. of 6 variables:
## $ Municipality : chr "Abella de la Conca" "Abrera" "Ã\200ger" "Agramunt" ...
## $ Comarca : chr "Pallars JussÃ" "Baix Llobregat" "Noguera" "Urgell" ...
## $ Province : chr "Lleida" "Barcelona" "Lleida" "Lleida" ...
## $ Population(2014): chr "170" "12,125" "594" "5,515" ...
## $ Area(km) : chr "78.3" "19.9" "160.6" "79.6" ...
## $ Density : chr "2.2" "609.3" "3.7" "69.3" ...
Vamos a eliminar las comas correspondientes a los miles, convertir los datos a formato numérico y calcular la media de población por municipio.
$`Population(2014)` <- gsub(",", "", Municipis$`Population(2014)`) #eliminar comas
Municipis$`Population(2014)` <- as.numeric(Municipis$`Population(2014)`) #convertir a numérico
Municipismean(Municipis$`Population(2014)`) #calcular la media
## [1] 15862.66
En realidad, si nos fijamos en la tabla original, veremos que la cifra es errónea, ya que está sumando la última fila con el total a las poblaciones de los municipios (por eso el resultado es aproximadamente el doble).
Veamos como importar de nuevo la tabla, eliminar la última fila y rehacer el cálculo (la eliminación de las comas y la conversión a formato numérico las hemos unido en una única línea).
<- htmltab("https://en.wikipedia.org/wiki/Municipalities_of_Catalonia", 1) Municipis
## Warning: Columns [No. ofEMDs] seem to have no data and are removed. Use
## rm_nodata_cols = F to suppress this behavior.
<- Municipis[-c(948),] #elimina la última fila
Municipis2 $`Population(2014)` <- as.numeric(gsub(",", "", Municipis2$`Population(2014)`))
Municipis2mean(Municipis2$`Population(2014)`)
## [1] 7939.707
Podemos filtrar los municipios de la provincia de Barcelona.
<- Municipis2[Municipis2$Province == "Barcelona", 1:4]
Barcelona head(Barcelona)
## Municipality Comarca Province Population(2014)
## 3 Abrera Baix Llobregat Barcelona 12125
## 6 Aguilar de Segarra Bages Barcelona 251
## 8 Aiguafreda Vallès Oriental Barcelona 2498
## 30 Alella Maresme Barcelona 9651
## 45 Alpens Osona Barcelona 300
## 51 L'Ametlla del Vallès Vallès Oriental Barcelona 8283
O los municipios grandes, entendiendo como tales los que tienen una población superior a 50.000 habitantes.
<- Municipis2[Municipis2$`Population(2014)` > 50000, 1:4]
Grans_municipis head(Grans_municipis, 10)
## Municipality Comarca Province Population(2014)
## 80 Badalona Barcelonès Barcelona 217210
## 92 Barcelona Barcelonès Barcelona 1602386
## 206 Castelldefels Baix Llobregat Barcelona 63255
## 228 Cerdanyola del Vallès Vallès Occidental Barcelona 57402
## 252 Cornellà de Llobregat Baix Llobregat Barcelona 86234
## 331 Girona Gironès Girona 97227
## 342 Granollers Vallès Oriental Barcelona 59930
## 358 L'Hospitalet de Llobregat Barcelonès Barcelona 253518
## 387 Lleida Segrià Lleida 139176
## 411 Manresa Bages Barcelona 75297
7.2 Importación de páginas web (primer ejemplo)
Vamos a importar los datos de los 50 libros más leídos a España según la web https://www.goodreads.com/book/most_read“. Para ello, utilizaremos el paquete rvest
.
library(rvest)
Almacenamos el código HTML de la página de la que obtener los datos
<- read_html("https://www.goodreads.com/book/most_read") webpage
A continuación, extraemos los títulos de los libros. Para conocer las etiquetas, podéis utilizar una extensión del navegador como SelectorGadget (o la opción “Inspecciona” con el botón derecho del ratón).
<- html_nodes(webpage,'.bookTitle') titulos_html
Convertimos los títulos de html a texto y los visualizamos
<- html_text(titulos_html)
titulos head(titulos, 5)
## [1] "\n From Blood and Ash (Blood and Ash, #1)\n"
## [2] "\n The Seven Husbands of Evelyn Hugo\n"
## [3] "\n Beautiful World, Where Are You\n"
## [4] "\n Dune (Dune, #1)\n"
## [5] "\n Normal People\n"
Vamos a eliminar el símbolo “” y los espacios iniciales
<- gsub("\n ","",titulos)
titulos2 head(titulos2, 5)
## [1] "From Blood and Ash (Blood and Ash, #1)\n"
## [2] "The Seven Husbands of Evelyn Hugo\n"
## [3] "Beautiful World, Where Are You\n"
## [4] "Dune (Dune, #1)\n"
## [5] "Normal People\n"
También eliminados el símbolo “” al final. Comprobamos que es correcto.
<- gsub("\n","",titulos2)
titulos3 head(titulos3, 5)
## [1] "From Blood and Ash (Blood and Ash, #1)"
## [2] "The Seven Husbands of Evelyn Hugo"
## [3] "Beautiful World, Where Are You"
## [4] "Dune (Dune, #1)"
## [5] "Normal People"
Hacemos lo mismo con los autores
<- html_nodes(webpage,'a.authorName')
autores_html <- html_text(autores_html)
autores head(autores)
## [1] "Jennifer L. Armentrout" "Taylor Jenkins Reid" "Sally Rooney"
## [4] "Frank Herbert" "Sally Rooney" "Madeline Miller"
Y lo mismo con los ratings
<- html_nodes(webpage,'.minirating')
rating_html <- html_text(rating_html)
rating rating
## [1] " 4.30 avg rating — 181,924 ratings"
## [2] " 4.45 avg rating — 583,661 ratings"
## [3] " 3.85 avg rating — 52,699 ratings"
## [4] " 4.24 avg rating — 944,941 ratings"
## [5] " 3.85 avg rating — 640,017 ratings"
## [6] " 4.41 avg rating — 530,595 ratings"
## [7] " 4.09 avg rating — 636,881 ratings"
## [8] " 4.53 avg rating — 1,534 ratings"
## [9] " 4.21 avg rating — 74,366 ratings"
## [10] " 4.32 avg rating — 14,815 ratings"
## [11] " 4.08 avg rating — 878 ratings"
## [12] " 4.47 avg rating — 71,394 ratings"
## [13] " 4.09 avg rating — 438,766 ratings"
## [14] " 4.25 avg rating — 398,129 ratings"
## [15] " 3.97 avg rating — 609,068 ratings"
## [16] " 4.08 avg rating — 22,066 ratings"
## [17] " 4.18 avg rating — 766,421 ratings"
## [18] " 4.12 avg rating — 10,574 ratings"
## [19] " 4.41 avg rating — 429,846 ratings"
## [20] " 3.88 avg rating — 387,517 ratings"
## [21] " 3.78 avg rating — 38,904 ratings"
## [22] " 4.47 avg rating — 551,096 ratings"
## [23] " 4.58 avg rating — 544,359 ratings"
## [24] " 4.53 avg rating — 142,958 ratings"
## [25] " 4.35 avg rating — 235,045 ratings"
## [26] " 4.23 avg rating — 378,577 ratings"
## [27] " 3.83 avg rating — 34,221 ratings"
## [28] " 4.33 avg rating — 278,292 ratings"
## [29] " 3.70 avg rating — 185,641 ratings"
## [30] " 4.03 avg rating — 145,002 ratings"
## [31] " 3.97 avg rating — 213,459 ratings"
## [32] " 4.27 avg rating — 3,386,128 ratings"
## [33] " 4.30 avg rating — 12,091 ratings"
## [34] " 4.17 avg rating — 14,112 ratings"
## [35] " 4.11 avg rating — 1,126,044 ratings"
## [36] " 4.36 avg rating — 355,598 ratings"
## [37] " 4.10 avg rating — 21,572 ratings"
## [38] " 4.44 avg rating — 379,941 ratings"
## [39] " 4.59 avg rating — 1,733 ratings"
## [40] " 4.22 avg rating — 27,813 ratings"
## [41] " 3.82 avg rating — 266,147 ratings"
## [42] " 4.42 avg rating — 474,355 ratings"
## [43] " 4.61 avg rating — 101,257 ratings"
## [44] " 4.22 avg rating — 436,395 ratings"
## [45] " 4.46 avg rating — 12,808 ratings"
## [46] " 4.59 avg rating — 365,169 ratings"
## [47] " 3.87 avg rating — 14,896 ratings"
## [48] " 4.19 avg rating — 3,586,642 ratings"
## [49] " 4.47 avg rating — 7,979,054 ratings"
## [50] " 4.69 avg rating — 41,576 ratings"
Combinamos en un dataframe títulos, autores y ratings. El resultado lo exportamos a un fichero txt.
<- data.frame(Titulo = titulos3, Autor = autores, Rating = rating)
libros write.table(libros, file = "Libros", sep = "\t")
7.3 Importación de páginas web (segundo ejemplo)
<- read_html("https://m.imdb.com/chart/bestpicture/")
pelis
<- html_nodes(pelis,'.best-picture-item-title')
titles_html <- html_text(titles_html)
titles head(titles, 10)
## [1] " Nomadland\n(2020)\n"
## [2] " Gisaengchung\n(2019)\n"
## [3] " Green Book\n(2018)\n"
## [4] " The Shape of Water\n(2017)\n"
## [5] " Moonlight\n(2016)\n"
## [6] " Spotlight\n(2015)\n"
## [7] " Birdman or (The Unexpected Virtue of Ignorance)\n(2014)\n"
## [8] " 12 Years a Slave\n(2013)\n"
## [9] " Argo\n(2012)\n"
## [10] " The Artist\n(2011)\n"
<- gsub("\n","",titles)
titles2 head(titles2)
## [1] " Nomadland(2020)" " Gisaengchung(2019)"
## [3] " Green Book(2018)" " The Shape of Water(2017)"
## [5] " Moonlight(2016)" " Spotlight(2015)"
Vamos ahora con los años.
<- html_nodes(pelis,'.titlemeter')
year_html <- html_text(year_html)
year head(year)
## [1] "\n2020 winner\n" "\n2019 winner\n" "\n2018 winner\n" "\n2017 winner\n"
## [5] "\n2016 winner\n" "\n2015 winner\n"
<- gsub("\n","",year)
year2 <- gsub(" winner","",year2)
year3 head(year3,50)
## [1] "2020" "2019" "2018" "2017" "2016" "2015" "2014" "2013" "2012" "2011"
## [11] "2010" "2009" "2008" "2007" "2006" "2005" "2004" "2003" "2002" "2001"
## [21] "2000" "1999" "1998" "1997" "1996" "1995" "1994" "1993" "1992" "1991"
## [31] "1990" "1989" "1988" "1987" "1986" "1985" "1984" "1983" "1982" "1981"
## [41] "1980" "1979" "1978" "1977" "1976" "1975" "1974" "1973" "1972" "1971"
Y ahora con la puntuación.
<- html_nodes(pelis,'.spacing-right-small')
puntos_html <- html_text(puntos_html)
puntos puntos
## [1] "7.4" "8.6" "8.2" "7.3" "7.4" "8.1" "7.7" "8.1" "7.7" "7.9" "8.0" "7.5"
## [13] "8.0" "8.1" "8.5" "7.7" "8.1" "8.9" "7.2" "8.2" "8.5" "8.3" "7.1" "7.8"
## [25] "7.4" "8.3" "8.8" "8.9" "8.2" "8.6" "8.0" "7.4" "8.0" "7.7" "8.1" "7.2"
## [37] "8.3" "7.4" "8.0" "7.2" "7.7" "7.8" "8.1" "8.0" "8.1" "8.7" "9.0" "8.3"
## [49] "9.2" "7.7" "7.9" "7.8" "7.4" "7.9" "7.7" "8.0" "7.8" "6.5" "8.3" "7.5"
## [61] "8.3" "8.1" "6.7" "8.1" "6.8" "7.7" "8.1" "7.6" "6.6" "7.2" "8.2" "7.5"
## [73] "7.6" "7.3" "8.1" "7.9" "7.0" "8.5" "7.6" "7.7" "8.1" "8.1" "7.9" "7.2"
## [85] "6.7" "7.7" "8.1" "5.9" "7.4" "5.9" "8.1" "5.7" "7.5" "8.1"
Por último, combinamos todos los campos (títulos, años y puntuaciones) en un dataframe y lo exportamos.
<- data.frame(Titulo = titles2, Year = year3, Puntuacion = puntos)
peliculas
write.table(peliculas, file = "Pelis", sep = "\t")
7.4 Ejercicio 7. Extracción de datos de la web
La siguiente página web recoge una selección de los 100 mejores discos de la historia según una revista musical. Intenta extraer la información relativa a los títulos de los discos, los grupos y la descripción de cada álbum.
The 500 Greatest Albums of All Time: 100-1
https://www.nme.com/photos/the-500-greatest-albums-of-all-time-100-1-1426116
De manera opcional, puedes intentar hacer lo mismo con la siguiente página que incluye una lista de 100 ciudades del mundo. Si lo prefieres, puedes escoger cualquier otra página web que te interese o puedes probar a importar a R alguna tabla disponible en Wikipedia.
World’s best cities