Ejercicio 2: documentación de Web scraping

El objetivo de esta página es explicar paso por paso cómo se hace web scraping.

Definición

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.

Pero vayamos a la explicación

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:

  1. Con la funicón html_node extraemos los datos de una de las ramas que nos interesan
  2. mientras que con html_text el texto de este nodo
  3. y finalmente con html_attr se descargarán los atributos.

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()

Iniciamos con el proceso automatizado

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

Viene un nuevo loop de descarga

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

¿Dónde quedaron guardados los datos descargados?

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

En resumidas cuentas

  1. Lo que hicimos fue tomar la ruta seleccionada del elemento que nos interesaba.
  2. Seleccionar la página 2, porque es la página que contienemás datos que nos ayudarán areescribir la ruta a otras páginas utilizando la misma sintaxis. Esto en comparación con la página 1.
  3. En este caso ya estaba inspeccionado el elemento. Así que vimos qué elementos de las cadenas de texto serían las constantes y cuáles las variables.
  4. Hicimos el loop para extraer los datos de la página 2 y luego programamos para que con el loop hiciera lo mismo con las más de 200 páginas que nos interesaban.
  5. La información que decargamos en el loop, la guardamos en data frame con un tibble adentro vacío.

¿Qué podemos hacer con las bases de datos, producto del web scraping?

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”.