Ejemplo. Obteniendo los datos de las disertaciones del Departamento de Estadística de Stanford.
Problema:
Queremos obtener los datos de las tesis realizadas en el Departamento de Estadística de Stanford, para ver el trabajo que realizan los alumnos provenientes de esta institución. Queremos obtener los títulos de los trabajos, así como información de los autores y de los asesores de las disertaciones.
Este ejemplo nos permitirá trabajar con el uso de la función
rvest::html_table(), la cual nos ayuda en caso de que querramos hacer Web-Scraping con páginas que ya contienen los datos de interés estructurados en tablas.
Paso 1. Examinamos la página de interés:
La página de Bienvenida se puede consultar en el siguiente enlace
https://statistics.stanford.edu/people/alumni
Fig. 1: Página de interés
En esta página, podemos ver que la información ya viene de manera tabular. Cuando una página ya tiene información de manera tabular, nos facilita la extracción de la información, debido a que esta ya viene estructurada y simplemente necesitamos extraerla.
Ahora, examinamos la página 2 para ver como van variando las url conforme vamos avanzando de página:
Fig. 2: Páginas disponibles
De ir a las distintas páginas, podemos ver que el cambio en las urls se da al final de estas, en el componente page=0. La tabla siguiente nos muestra como se va dando el cambio.
Ojo: Veamos que la página 1 inicia con page=0.
Trabajamos con el caso n = 1
Trabajando el caso n = 1: Recordemos que trabajar el caso
n = 1es trabajar el primer caso, para después generalizar con los demás casos posteriores.
Vamos a trabajar con la extracción de los datos de la página siguiente:
https://statistics.stanford.edu/people/alumni?page=1
Paso 1: Leemos el HTML con read_html():
# Librerías necesarias para trabajar
library(rvest)
library(tidyverse)
# Leemos el código HTML
codigo_html <- read_html("https://statistics.stanford.edu/people/alumni?page=1")Paso 2. Extraer las tablas
La diferencia con el método visto en clase y lo que vamos a ver en este ejemplo radica en que la información esta ahora presentada de manera tabular. Esto hace que ya no sea necesario ubicar la rama donde se encuentra el dato de interés, y simplemente podamos extraer todas las tablas en un solo paso.
# Extraemos todas las tablas, sin buscar su nodo o rama.
tablas <- html_table(codigo_html)
class(tablas)## [1] "list"
Ojo! Recordemos que cada página tiene su algoritmo de WS propio, por lo que, a veces, jalar todas las tablas a nuestra sesión de RStudio puede provocar que jalemos también tablas basura. En estos casos habría que filtrar estas tablas antes de guardarlas en nuestro resultado final.
Paso 3: Dar formato a la información resultante.
El objeto tablas es un objeto tipo list que almacena, dentro de cada elemento de la lista, un data.frame con la información de las tesis y los autores por cada cohorte o generación de estudiantes.
# Para acceder a los elementos guardados dentro de una lista, usamos el doble corchete.
tablas[[1]] # Accede al primer elemento de la lista| Cohort | Student | Advisor Name | Committee Names | Dissertation |
|---|---|---|---|---|
| 2018-2019 | Paulo Orenstein | Diaconis | Chatterjee, Wong | Topics in Robust Mean Estimation |
| 2018-2019 | Feng Ruan | Duchi | Johnstone, Candes | Adapting local minimax theory to modern applications |
| 2018-2019 | Pragya Sur | Candes | Montanari, Johnstone | A Modern Maximum Likelihood Theory for High-Dimensional Logistic Regression |
| 2018-2019 | David Walsh | Johari (MS&E) | Efron, Owen | How to design and analyze online A/B tests within decentralized organizations |
| 2018-2019 | Jeha Yang | Johnstone | Owen, Donoho | Edgeworth approximations for spiked PCA models and applications |
# Para acceder a los elementos guardados dentro de una lista, usamos el doble corchete.
tablas[[2]] # Accede al segundo elemento de la lista| Cohort | Student | Advisor Name | Committee Names | Dissertation |
|---|---|---|---|---|
| 2017-2018 | Joseph Arthur | Wong | Owen, Tang | Detection and validation of genomic structural variation from DNA sequencing data |
| 2017-2018 | Cyrus DiCiccio | Romano | Taylor, Tibshirani | Hypothesis Testing Using Multiple Data Splitting |
| 2017-2018 | Zhou Fan | Montanari/Johnstone | Candes | Eigenvalues in multivariate random effects models |
| 2017-2018 | Kelvin Guu | Liang (CS) | Wong, Mackey, Manning (CS) | Learning to generate text, programs (and beyond) from weak supervision |
| 2017-2018 | Ya Le | Hastie | Efron, Taylor | Topics in statistical learning with a focus on large-scale data |
| 2017-2018 | Snigdha Panigrahi | Taylor | Tibshirani, Sabatti | An approximation-based framework for post-selective inference |
| 2017-2018 | Kris Sankaran | Holmes | Switzer, Efron | Discovery and Visualization of Latent Structure with Applications to the Microbiome |
Estas tablas poseen una estructura similar (mismo número y nombre de columnas), lo cual permite que las podamos pegar una sobre otra sin problemas. Recordemos, del primer semestre, que la función para pegar data.frames uno encima de otro es la función rbind.data.frame().
Lo que vamos a hacer entonces, es un loop que 1) saque cada data.frame de la lista que lo contiene y 2) lo pegue a un nuevo data.frame, apilando estas tablas una encima de la otra.
# Primero, necesito saber cuantas tablas tiene la lista:
length(tablas) # Aqui veo que son "n" tablas## [1] 3
no_tablas_en_lista <- length(tablas) # lo guardo en un objeto
# Genero una tabla vacia para irla llenando con las tablas dentro de la lista:
tabla_parcial <- data.frame()
# Hacemos un loop sobre las tablas
# Aqui hacemos lo descrito arriba:
for (j in 1:no_tablas_en_lista){
tabla_parcial <- rbind.data.frame(tabla_parcial, tablas[[j]])
}Y ya aquí podemos ver que se extrajeron y se pegaron los datos contenidos en las tablas de esta página.
| Cohort | Student | Advisor Name | Committee Names | Dissertation |
|---|---|---|---|---|
| 2018-2019 | Paulo Orenstein | Diaconis | Chatterjee, Wong | Topics in Robust Mean Estimation |
| 2018-2019 | Feng Ruan | Duchi | Johnstone, Candes | Adapting local minimax theory to modern applications |
| 2018-2019 | Pragya Sur | Candes | Montanari, Johnstone | A Modern Maximum Likelihood Theory for High-Dimensional Logistic Regression |
| 2018-2019 | David Walsh | Johari (MS&E) | Efron, Owen | How to design and analyze online A/B tests within decentralized organizations |
| 2018-2019 | Jeha Yang | Johnstone | Owen, Donoho | Edgeworth approximations for spiked PCA models and applications |
| 2017-2018 | Joseph Arthur | Wong | Owen, Tang | Detection and validation of genomic structural variation from DNA sequencing data |
| 2017-2018 | Cyrus DiCiccio | Romano | Taylor, Tibshirani | Hypothesis Testing Using Multiple Data Splitting |
| 2017-2018 | Zhou Fan | Montanari/Johnstone | Candes | Eigenvalues in multivariate random effects models |
| 2017-2018 | Kelvin Guu | Liang (CS) | Wong, Mackey, Manning (CS) | Learning to generate text, programs (and beyond) from weak supervision |
| 2017-2018 | Ya Le | Hastie | Efron, Taylor | Topics in statistical learning with a focus on large-scale data |
| 2017-2018 | Snigdha Panigrahi | Taylor | Tibshirani, Sabatti | An approximation-based framework for post-selective inference |
| 2017-2018 | Kris Sankaran | Holmes | Switzer, Efron | Discovery and Visualization of Latent Structure with Applications to the Microbiome |
| 2016-2017 | Edgar Dobriban | Donoho | Owen, Johnstone | Topics in High-Dimensional Asymptotics |
| 2016-2017 | Murat A. Erdogdu | Montanari/Bayati | Candes | Stein’s Lemma and Subsampling in Large-Scale Optimization |
| 2016-2017 | Julia Fukuyama | Holmes | Wong, Relman (Med) | Multivariate Methods for the Analysis of Structured Data |
| 2016-2017 | Katelyn Xiang Gao | Owen | Tibshirani, Mackey | Scalable Estimation and Inference for Massive Linear Mixed Models with Crossed Random Effects |
| 2016-2017 | Jack Gorham | Mackey/Candes | Owen | Measuring Sample Quality with Stein’s Method |
| 2016-2017 | Ruojun Huang | Dembo | Chatterjee, Diaconis | Monotone interactions of random walks and graphs |
| 2016-2017 | Lucas Janson | Candes | Mackey, Hastie | A model-free approach to high-dimensional inference |
| 2016-2017 | Bai Jiang | Wong | Lai, Diaconis | Two Parameter Inference Methods in Likelihood-free Models: Approximate Bayesian Computation and Contrastive Divergence |
Paso 4: Generalizar el proceso a las demás páginas.
Una vez que ya vimos el caso n = 1, vamos a extrapolar el proceso a los demás casos.
Para esto, recordemos que lo que va variando en los demás casos (las demás páginas) es el número al final de la página. Entonces, generamos un objeto que almacene estas páginas.
Una pregunta válida sería… ¿Cuántas páginas hay?, esto lo podemos saber si oprimimos el botón last dentro del carrusel. De ahí vemos que el número total de páginas es 26.
Fig. 3: Forma de saber cuantas paginas existen en total
# Construimos los enlaces para las 26 páginas:
#(Recordemos que el conteo en las urls inicia desde el cero)
paginas <- paste0("https://statistics.stanford.edu/people/alumni?page=", 0:25)
print(paginas)## [1] "https://statistics.stanford.edu/people/alumni?page=0"
## [2] "https://statistics.stanford.edu/people/alumni?page=1"
## [3] "https://statistics.stanford.edu/people/alumni?page=2"
## [4] "https://statistics.stanford.edu/people/alumni?page=3"
## [5] "https://statistics.stanford.edu/people/alumni?page=4"
## [6] "https://statistics.stanford.edu/people/alumni?page=5"
## [7] "https://statistics.stanford.edu/people/alumni?page=6"
## [8] "https://statistics.stanford.edu/people/alumni?page=7"
## [9] "https://statistics.stanford.edu/people/alumni?page=8"
## [10] "https://statistics.stanford.edu/people/alumni?page=9"
## [11] "https://statistics.stanford.edu/people/alumni?page=10"
## [12] "https://statistics.stanford.edu/people/alumni?page=11"
## [13] "https://statistics.stanford.edu/people/alumni?page=12"
## [14] "https://statistics.stanford.edu/people/alumni?page=13"
## [15] "https://statistics.stanford.edu/people/alumni?page=14"
## [16] "https://statistics.stanford.edu/people/alumni?page=15"
## [17] "https://statistics.stanford.edu/people/alumni?page=16"
## [18] "https://statistics.stanford.edu/people/alumni?page=17"
## [19] "https://statistics.stanford.edu/people/alumni?page=18"
## [20] "https://statistics.stanford.edu/people/alumni?page=19"
## [21] "https://statistics.stanford.edu/people/alumni?page=20"
## [22] "https://statistics.stanford.edu/people/alumni?page=21"
## [23] "https://statistics.stanford.edu/people/alumni?page=22"
## [24] "https://statistics.stanford.edu/people/alumni?page=23"
## [25] "https://statistics.stanford.edu/people/alumni?page=24"
## [26] "https://statistics.stanford.edu/people/alumni?page=25"
Ahora, construimos un data.frame vacío para irlo llenando con todos los datos que vayamos extrayendo.
Después, pegamos todo el código del caso n = 1 y lo repetimos para cada página contenida en el objeto paginas.
# Copiamos y pegamos todo el código escrito previamente, y lo metemos en un loop.
for (pagina in paginas){
# Defino la pagina
url <- pagina # Una pagina del contador
# Leo el codigo
code <- read_html(url)
# Obtengo el nodo de las tablas enteras:
tablas <- html_table(code)
length(tablas) # Aqui veo que son "n" tablas
# Genero una tabla vacia para irla llenando para esta página particular
tabla_parcial <- data.frame()
# Hacemos un loop sobre las tablas
for (j in length(tablas)){
tabla_parcial <- rbind.data.frame(tabla_parcial, tablas[[j]])
}
# Le pego el resultado de la página n
# a la tabla que va a estar capturando todo:
tabla_total <- rbind.data.frame(tabla_total,
tabla_parcial)
# Hacemos un contador de avance que nos mande mensajitos
print(paste0("Ya descargaste datos de: ", pagina))
}## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=0"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=1"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=2"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=3"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=4"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=5"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=6"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=7"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=8"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=9"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=10"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=11"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=12"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=13"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=14"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=15"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=16"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=17"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=18"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=19"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=20"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=21"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=22"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=23"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=24"
## [1] "Ya descargaste datos de: https://statistics.stanford.edu/people/alumni?page=25"
Y listo… de esta manera extrapolamos el proceso n = 1 a todas las paginas, extraemos en una sola tabla todos los datos y ya tenemos una base de datos lista para analizar o trabajar con ella.