El objetivo de esta página es explicar paso por paso cómo se hace web scraping.
Recordemos que esta es una práctica se define como el proceso de extracción de datos amlacenados en una página web. El objetivo es la recopilación de información que almacena un servidor en la web.
Primero descarguemos las librerías y guardemos en un objeto la dirección de la página de interner de nuestro interés para el ejercicio.
library(rvest)
library(tidyverse)
url <- "https://en.wikipedia.org/wiki/Legality_of_cannabis"
Con la función read_html podemos leer el código fuente de la página de internet y luego lo guardamos en un objeto.
code <- read_html(url)
code
Aquí vemos cómo se imprime el objeto code
Más adelante vemos los nodos que nos interesan. En este caso son los artículos por cada país y a partir de eso podemos guardar la cadena de texto en el objeto node.
# Nodos de interés... (enlaces al articulo de cada pais en particular)
#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(1) > td:nth-child(4) > div > a
#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(2) > td:nth-child(4) > div > a
#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(3) > td:nth-child(4) > div > a
#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(4) > td:nth-child(4) > div > a
# ...
#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(206) > td:nth-child(4) > div > a
node <- "#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(2) > td:nth-child(4) > div > a"
Con la función html_table podemos un nodo en tabla y guardarla en un objeto.
tablas <- html_table(code, fill = TRUE)
Después, la idea es hacer una tabla (tibble) con el texto y los atributos de la rama que necesitamos. El [[1]] es el elemento 1 de la lista de países en la dirección con la que estamos trabajando. En este punto hay que puntualizar:
Esto con el objetivo de configurar el código “/wiki/Cannabis_in_Afghanistan”. Y no solo "“Cannabis in Afghanistan” extraido con el html_text de la línea de en medio.
tabla_con_todo <- tablas[[1]] %>% as_tibble()
html_node(code, node) %>% html_text()
html_node(code, node) %>% html_attr("href")
En la imagen podemos ver la impresión de la ramificación con la que trabajaremos
Creamos un objeto con el data frame que se nutrirá de un bucle de descarga automatizada.
articulos_x_pais <- data.frame()
Aquí es importante aclarar que for (i in 2:206) es el loop o bucle. Donde i comenzará del número 2 en la lista de países (el 1 es Afganistán, como vimos anteriormente). La i es nuestra variable, por ello en la función **paste0()* aparece dentro de unos paréntesis de la cadena de texto (nodo) con el que trabajaremos.
for (i in 2:206){
node <- paste0("#mw-content-text > div.mw-parser-output > table > tbody > tr:nth-child(", i, ") > td:nth-child(4) > div > a")
A través de la función html_node vamos a analzar los objetos code y node y luego extraer el texto con html_text de esta remificación, para guardarlo en el objeto texto.
texto <- html_node(code, node) %>% html_text()
A través de la función html_node vamos a analzar los objetos code y node y luego extraer los atributos del nodo html_attr, en específico nos interesa el enlace (href) de una página, para luego guardarlo en el objeto enlace
enlace <- html_node(code, node) %>% html_attr("href")
Con la función paste0 escribimos el pedazo de URL constante así como el objeto enlace que contiene las variables de los atributos. Luego volvemos a guardar esto en el mismo objeto.
enlace <- paste0("https://en.wikipedia.org/", enlace)
Las instrucciones para el loop continúan… pero ahora debemos dar la instrucción de qué haremos cuando se descarguen. Para ello creamos un data frame que contenga la variable “articulos_x_pais” y el tibble compuesto por las variables texto y enlace.
articulos_x_pais <- rbind.data.frame(articulos_x_pais,
tibble(texto = texto,
enlace = enlace))
Finalmente, imprimimos el loop pero dentro de esta función, le ordenamos a R que nos imprima en la consola los datos extraídos del 2 al 206 conforme vaya extrayendo los datos.
print(paste0("Dato extraído no. ", i, "/206"))
}
En este proceso primero veremos una lista de datos extraídos del 2 al 206
Después podemos ver el tibble sobre cómo se generó la descarga con las variables texto y enlace. Es la información guardada en el objeto articulos_x_pais
Ahora vamos a utilizar el objeto articulos_x_pais (el tibble que recientemente creamos con la descarga de datos) para filtrar y extraer de las “celdas” de la variable texto las NA, y luego generamos una nueva columna con mutate pero que quede vacía.
articulos_x_pais
articulos_x_pais <- articulos_x_pais %>%
filter(!is.na(texto)) %>%
mutate(contenido_paginas = NA)
Ahora generamos un nuevo loop, esta ocasión la variable i va de la observación 1 pasando por las filas que contiene articulos_x_pais.
Y para evitar errores, usamos la función tryCatch, esto previo a que iniciemos el bucle con la {.
for(i in 1:nrow(articulos_x_pais)){
tryCatch({
Ahora bien, para generar la segunda url con la que trabajaremos es necesario tomar del tibble articulos_x_pais y la variable enlace con la variable i.
url2 <- articulos_x_pais$enlace[i]
Ahora buscamos generar un code2 con la fucnción que lee el código fuente de una página web con el objeto url2 (que incluye la variable i).
code2 <- read_html(url2)
Ahora con la función html_nodes extraemos los datos de una rama (code 2) para luego extraer el texto con la función html_text y luego pegarlo a través de la funcion paste0 para guardarlo en un nuevo objeto, llamado parrafos_de_cada_articulo.
parrafos_de_cada_articulo <- html_nodes(code2, "p") %>%
html_text() %>%
paste0(collapse = "<br>")
Con el objeto parrafos_de_cada_articulo damos la instrucción de la descarga así como la leyenda que queremos que se imprima en la consola cuando se descarguen los datos (texto) de los artículos por país (i).
articulos_x_pais$contenido_paginas[i] <- parrafos_de_cada_articulo
print(paste0("Descargados párrafos del articulo de: ", articulos_x_pais$texto[i]))
},
Con function(e), en el objeto e, le damos a instrucción de qué leyenda imprimir cuando haya un error porque no haya datos para descargar en la página.
error = function(e){
print(paste0("Error!, no hay datos en esta pagina: ", articulos_x_pais$texto[i]))
Antes de cerrar el loop, y el TryCatch escrbimos la cadena de texto “No hay artículo” que nos avisará en la consola cuando no haya artículo en la página por vada elemento de la variable i.
```r
articulos_x_pais$contenido_paginas[i] <- "No hay artículo"
})
}
```
En este caso no hubo errores, afortunadamente.
Aquí podemos ver cómo se fue descargando por país
Bueno, pues en dos tablas la primera es tabla_con_todo y la segunda articulos_x_pais. Ahora la podemos imprimir o ver y revisar el contenido.
# Bases finales
tabla_con_todo
articulos_x_pais
Aquí podemos ver el tibble sobre cómo se generó la descarga para la tabla con toda la información descargada
Y aquí podemos ver el tibble sobre cómo se generó la descarga para la base de datos artículos por país
Se puden hacer cruces de datos para ver en qué países el uso de la cannabis es legal para uso medicinal o recrativo, así como sus variantes.
Otra opción es hacer nubes de palabras con cada artículo por país.
También se puede hacer una búsqueda de artículos de manera más precisa a través de la base de datos “Artículos por país”.