08A - Web scraping

Si quieres correr estos scripts localmente, acá puedes descargar el proyecto comprimido en .zip. Paquetes que necesitas tener instalados antes de comenzar con el proyecto: tidyverse, glue, rvest.

Inicio: cargar paquetes

library(tidyverse)
library(glue)   
## 
## Attaching package: 'glue'
## The following object is masked from 'package:dplyr':
## 
##     collapse
library(rvest) # para hacer web scraping
## Loading required package: xml2
## 
## Attaching package: 'rvest'
## The following object is masked from 'package:purrr':
## 
##     pluck
## The following object is masked from 'package:readr':
## 
##     guess_encoding

glue::glue()

nombre <- "Andrés"
glue("Hola, mi nombre es {nombre}")
## Hola, mi nombre es Andrés
glue("HOLA, MI NOMBRE ES {str_to_upper(nombre)}")
## HOLA, MI NOMBRE ES ANDRÉS

Web scraping

  • El web scraping es la extracción automatizada de información a partir de sitios web. Aparte de alimentar sitios como Knasta, que lo realizan periódicamente, nos permite obtener datos de fuentes no tradicionales (¡cualquier sitio web!).

  • La información que podemos obtener es igual a la que podríamos hacer manualmente (copiando y pegando a un Excel, por ejemplo), pero podemos automatizar tareas muy tediosas.

  • Hoy veremos web scraping para páginas “estáticas” en vez de “dinámicas”.

Descargar un sitio web

Comenzaremos trabajando con las columnas de El Mostrador. Dejé el código comentado porque ya hice la descarga y no tenemos para qué correr todos/as esto (no queremos colapsar un sitio haciendo web scraping).

download_html(url  = "https://www.elmostrador.cl/noticias/opinion/columnas/",
              file = "webs/mostrador_1.html")

Cargar el html

web_mostrador_p1 <- read_html("webs/mostrador_1.html", 
                              encoding = "UTF-8") # buena idea para páginas en español

Extraer la información a partir de la estructura de la página, con rvest

El primer paso es encontrar el “selector” de CSS que contiene nuestra información. En la mayoría de los casos nos bastará con usar SelectorGadget. Tus apuntes sobre cómo usar SelectorGadget:

Comencemos con los títulos:

titulos_mostrador_p1 <- web_mostrador_p1 %>% 
  html_nodes("h4 a") %>% 
  html_text()
titulos_mostrador_p1
##  [1] "Carta abierta a las alcaldesas y los alcaldes de Chile"                            "We the people"                                                                    
##  [3] "Enfrentar la sequía a corto y largo plazo"                                         "Escaños reservados: el día clave para cambiar la historia"                        
##  [5] "Rodrigo Delgado y su responsabilidad en los guetos verticales de Estación Central" "El aprendizaje político de nuestro presidencialismo"                              
##  [7] "Dumping chino en la industria de las bolas de acero"                               "Tiltil: el sacrificio de Chile"                                                   
##  [9] "EE.UU., el acuerdo climático de París y los beneficios económicos"                 "EE.UU. y el valor de las instituciones"

Para sacar los links de un elemento, en vez de su texto, debemos reemplazar html_text() por html_attr("href"):

links_mostrador_p1 <- web_mostrador_p1 %>% 
  html_nodes("h4 a") %>% 
  html_attr("href")
links_mostrador_p1
##  [1] "https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/carta-abierta-a-las-alcaldesas-y-los-alcaldes-de-chile/"           
##  [2] "https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/we-the-people/"                                                    
##  [3] "https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/enfrentar-la-sequia-a-corto-y-largo-plazo/"                        
##  [4] "https://www.elmostrador.cl/destacado/2020/11/12/escanos-reservados-el-dia-clave-para-cambiar-la-historia/"                         
##  [5] "https://www.elmostrador.cl/destacado/2020/11/12/rodrigo-delgado-y-su-responsabilidad-en-los-guetos-verticales-de-estacion-central/"
##  [6] "https://www.elmostrador.cl/destacado/2020/11/12/el-aprendizaje-politico-de-nuestro-presidencialismo/"                              
##  [7] "https://www.elmostrador.cl/noticias/opinion/2020/11/11/dumping-chino-en-la-industria-de-las-bolas-de-acero/"                       
##  [8] "https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/11/tiltil-el-sacrificio-de-chile/"                                    
##  [9] "https://www.elmostrador.cl/noticias/opinion/2020/11/11/ee-uu-el-acuerdo-climatico-de-paris-y-los-beneficios-economicos/"           
## [10] "https://www.elmostrador.cl/destacado/2020/11/11/ee-uu-y-el-valor-de-las-instituciones/"

(Ejercicio a)

Obtén el autor/a de cada artículo. Llama al vector “autores_mostrador_p1”. Tu código:

Ahora podemos crear un data frame con toda información:

df_mostrador_p1 <- tibble(
  titulo = titulos_mostrador_p1,
  link   = links_mostrador_p1,
  autor  = autores_mostrador_p1,
)
df_mostrador_p1
## # A tibble: 10 x 3
##    titulo                                                                         link                                                                                                                         autor                                      
##    <chr>                                                                          <chr>                                                                                                                        <chr>                                      
##  1 Carta abierta a las alcaldesas y los alcaldes de Chile                         https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/carta-abierta-a-las-alcaldesas-y-los-alcaldes-de-chile/      Francois Richard                           
##  2 We the people                                                                  https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/we-the-people/                                               Alejandro Reyes                            
##  3 Enfrentar la sequía a corto y largo plazo                                      https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/enfrentar-la-sequia-a-corto-y-largo-plazo/                   Miguel Ángel Sánchez                       
##  4 Escaños reservados: el día clave para cambiar la historia                      https://www.elmostrador.cl/destacado/2020/11/12/escanos-reservados-el-dia-clave-para-cambiar-la-historia/                    Jorge Millaquén                            
##  5 Rodrigo Delgado y su responsabilidad en los guetos verticales de Estación Cen~ https://www.elmostrador.cl/destacado/2020/11/12/rodrigo-delgado-y-su-responsabilidad-en-los-guetos-verticales-de-estacion-c~ Patricio Herman                            
##  6 El aprendizaje político de nuestro presidencialismo                            https://www.elmostrador.cl/destacado/2020/11/12/el-aprendizaje-politico-de-nuestro-presidencialismo/                         Juan Carlos Arellano                       
##  7 Dumping chino en la industria de las bolas de acero                            https://www.elmostrador.cl/noticias/opinion/2020/11/11/dumping-chino-en-la-industria-de-las-bolas-de-acero/                  Rene González Aguilera y Héctor Medina Ale~
##  8 Tiltil: el sacrificio de Chile                                                 https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/11/tiltil-el-sacrificio-de-chile/                               Eva Aburto                                 
##  9 EE.UU., el acuerdo climático de París y los beneficios económicos              https://www.elmostrador.cl/noticias/opinion/2020/11/11/ee-uu-el-acuerdo-climatico-de-paris-y-los-beneficios-economicos/      Alejandro Bernales                         
## 10 EE.UU. y el valor de las instituciones                                         https://www.elmostrador.cl/destacado/2020/11/11/ee-uu-y-el-valor-de-las-instituciones/                                       Santiago Escobar

Descargar múltiples páginas con una iteración

walk(.x = 2:5,
     .f = ~ {
       download_html(url  = glue("https://www.elmostrador.cl/noticias/opinion/columnas/page/{.x}/"),
                     file = glue("webs/mostrador_{.x}.html"))
       Sys.sleep(2) # pausa
     })

Nuestros pasos siguientes tendrán el objetivo de procesar estos sitios web (5, pero podrían ser muchos más) para crear una base de datos única. Ocuparemos funciones personalizadas e iteraciones en el proceso.

Generalizar el proceso de limpieza de los datos con una función

Lo que hicimos para obtener nuestro data frame con información (df_mostrador_p1) se puede resumir en los siguientes pasos:

  1. Descargar el sitio (ya está hecho)
  2. Cargar el html a R
  3. Extraer los vectores para título, link y autor(a), usando selectores.
  4. Crear el data frame con estos vectores.

Esto puede pensarse como una “receta”, que debería funcionar para cualquier archivo (página de columnas descargada desde El Mostrador). La vamos a crear como una función personalizada:

f_procesar_sitio <- function(archivo){
  web <- read_html(archivo, encoding = "UTF-8")
  
  titulos <- web %>% 
    html_nodes("h4 a") %>% 
    html_text()
  
  links <- web %>% 
    html_nodes("h4 a") %>% 
    html_attr("href")
  
  autores <- web %>% 
    html_nodes(".col-md-10 p") %>% 
    html_text() %>% 
    str_remove("^por ")
  
  df_info <- tibble(
    titulo = titulos,
    link   = links,
    autor  = autores
  )
  
  return(df_info) # lo que devuelve/entrega la función
}

Ahora la función toma cualquier archivo como argumento y nos entrega lo que esperamos:

f_procesar_sitio(archivo = "webs/mostrador_3.html")
## # A tibble: 10 x 3
##    titulo                                                                                 link                                                                                                                                    autor                   
##    <chr>                                                                                  <chr>                                                                                                                                   <chr>                   
##  1 Un nuevo pacto social para la función pública                                          https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/09/un-nuevo-pacto-social-para-la-funcion-publica/                          Eduardo Abarzúa Cruz    
##  2 ¿Quién quiere ser constituyente?                                                       https://www.elmostrador.cl/destacado/2020/11/09/quien-quiere-ser-constituyente/                                                         Germán Silva Cuadra     
##  3 Estados Unidos: el ocaso de un imperio                                                 https://www.elmostrador.cl/destacado/2020/11/09/estados-unidos-el-ocaso-de-un-imperio/                                                  Felipe Herrera Aguirre  
##  4 FF.AA. y Defensa Nacional en la Constitución del 2022                                  https://www.elmostrador.cl/destacado/2020/11/09/ff-aa-y-defensa-nacional-en-la-constitucion-del-2022/                                   Richard Kouyoumdjian In~
##  5 El riesgo del endeudamiento y la quiebra de los negocios                               https://www.elmostrador.cl/destacado/2020/11/09/por-que-tras-la-crisis-covid-19aumentara-el-endeudamiento-y-la-quiebra-de-los-negocios/ Max Campillay Viñas     
##  6 Convención Constitucional Abierta: Los mecanismos de participación ciudadana que debi~ https://www.elmostrador.cl/noticias/opinion/2020/11/08/convencion-constitucional-abierta-los-mecanismos-de-participacion-ciudadana-que~ Patricio Contreras      
##  7 La ciudadanía aleccionando a la política                                               https://www.elmostrador.cl/noticias/opinion/2020/11/08/la-ciudadania-aleccionando-a-la-politica/                                        Pablo Paniagua          
##  8 Educación en Derechos Humanos: una deuda del Estado por una sociedad más democrática   https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/08/educacion-en-derechos-humanos-una-deuda-del-estado-por-una-sociedad-ma~ Sebastián Santos        
##  9 Día del Urbanismo: los nuevos desafíos en la transformación de los territorios         https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/08/dia-del-urbanismo-los-nuevos-desafios-en-la-transformacion-de-los-terr~ Pía Monardes            
## 10 Una brutalidad geográfica                                                              https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/08/una-brutalidad-geografica/                                              Enrique Aliste

Así, podemos iterar esta función en nuestros cinco archivos para crear una base completa (páginas 1-5). Ahora no utilizaremos walk(), sino que map_dfr() (aquí decidí no conservar el número de página).

archivos <- list.files("webs/", full.names = T)
archivos
## [1] "webs/mostrador_1.html" "webs/mostrador_2.html" "webs/mostrador_3.html" "webs/mostrador_4.html" "webs/mostrador_5.html"
df_mostrador_1_5 <- map_dfr(.x = archivos,
                            .f = ~ {f_procesar_sitio(.x)})
df_mostrador_1_5
## # A tibble: 50 x 3
##    titulo                                                                         link                                                                                                                         autor                                      
##    <chr>                                                                          <chr>                                                                                                                        <chr>                                      
##  1 Carta abierta a las alcaldesas y los alcaldes de Chile                         https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/carta-abierta-a-las-alcaldesas-y-los-alcaldes-de-chile/      Francois Richard                           
##  2 We the people                                                                  https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/we-the-people/                                               Alejandro Reyes                            
##  3 Enfrentar la sequía a corto y largo plazo                                      https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/12/enfrentar-la-sequia-a-corto-y-largo-plazo/                   Miguel Ángel Sánchez                       
##  4 Escaños reservados: el día clave para cambiar la historia                      https://www.elmostrador.cl/destacado/2020/11/12/escanos-reservados-el-dia-clave-para-cambiar-la-historia/                    Jorge Millaquén                            
##  5 Rodrigo Delgado y su responsabilidad en los guetos verticales de Estación Cen~ https://www.elmostrador.cl/destacado/2020/11/12/rodrigo-delgado-y-su-responsabilidad-en-los-guetos-verticales-de-estacion-c~ Patricio Herman                            
##  6 El aprendizaje político de nuestro presidencialismo                            https://www.elmostrador.cl/destacado/2020/11/12/el-aprendizaje-politico-de-nuestro-presidencialismo/                         Juan Carlos Arellano                       
##  7 Dumping chino en la industria de las bolas de acero                            https://www.elmostrador.cl/noticias/opinion/2020/11/11/dumping-chino-en-la-industria-de-las-bolas-de-acero/                  Rene González Aguilera y Héctor Medina Ale~
##  8 Tiltil: el sacrificio de Chile                                                 https://www.elmostrador.cl/noticias/opinion/columnas/2020/11/11/tiltil-el-sacrificio-de-chile/                               Eva Aburto                                 
##  9 EE.UU., el acuerdo climático de París y los beneficios económicos              https://www.elmostrador.cl/noticias/opinion/2020/11/11/ee-uu-el-acuerdo-climatico-de-paris-y-los-beneficios-economicos/      Alejandro Bernales                         
## 10 EE.UU. y el valor de las instituciones                                         https://www.elmostrador.cl/destacado/2020/11/11/ee-uu-y-el-valor-de-las-instituciones/                                       Santiago Escobar                           
## # ... with 40 more rows

(Ejercicio b)

  1. Obtén el texto de la columna más reciente.

  2. Generaliza lo anterior en una función que tome una URL (columna de El Mostrador) y devuelva su texto.

  3. Itera la función para completar “df_mostrador_p1” con una nueva columna de texto.