Web scraping con R

Introducción

En este trabajo se discute la potencialidad de R para realizar web scraping.
Web scraping o screen scraping es el proceso de extracción automatizada de datos contenidos en un sitio web.

Este es un proceso que suele presentarse comúnmente en el entorno laboral, y se resuelve de forma manual “copiando y pegando” los datos de un directorio online o página web, pero esto no es manejable en un entorno con alta escalabilidad.

Aunque este proceso se considera algo básico y rudimentario en los entornos de programación no se puede negar que es una técnica de gran ayuda cuando nos enfrentamos a este problema.

Herramientas de web scraping

Las herramientas de web scraping conocidas también como “scrapeadores” están especialmente diseñadas para extraer información de sitios web de forma automática.

  • Import.io: extrae datos casi de cualquier web
  • Mozenda.com: el binomio de web scraping y data as a service más completo
  • Dexi.io: herramienta de web scraping para usuarios avanzados
  • Salestools.io: un scraper para equipos comerciales
  • Hunter.io: una herramienta de web scraping para capturar correos electrónicos
  • Parsehub.com: una herramienta de web scraping especializada en páginas dinámicas
  • Webhose.io: transforman los datos desestructurados de una web en dato estructurados
  • Apifier.com: el web scraper para los que dominan JavaScript
  • Diffbot.com: inteligencia artificial para la extracción de datos
  • 80legs.com: un plan gratuito para web scraping

Los usos más comunes para estas herramientas son:

  • Extracción de datos de contacto y contenidos de una web
  • Creación de análisis y canales RSS a partir de los contenidos de una página web
  • Seguimiento de la evolución de precios de distintos productos, indicadores macroeconómicos, sociales, etc.
  • Marketing de contenidos
  • Posicionamiento y control de imagen, marcas y visibilidad en redes sociales e internet.

Web scraping con R y RSelenium

Con la ayuda de R y el paquete RSelenium podemos capturar el código fuente de una página web, guardarlo en una base de datos, interactuar con la web y extraer solo información necesaria, entre otros.


Iniciamos el procedimiento instalando y cargando los paquetes Rselenium y XML.

library(RSelenium)
library(XML)

Utilizamos la función rsDriver para abrir un navegador, el cual usaremos para navegar sobre cualquier página web y posterior captura de información. La primera ejecución tarda unos minutos, ya que esta función instala el servidor Selenium y los drivers de los navegadores en nuestro equipo, una vez instalados, se abrirá un navegador por defecto chrome.

## checking Selenium Server versions:
## BEGIN: PREDOWNLOAD
## BEGIN: DOWNLOAD
## BEGIN: POSTDOWNLOAD
## checking chromedriver versions:
## BEGIN: PREDOWNLOAD
## BEGIN: DOWNLOAD
## BEGIN: POSTDOWNLOAD
## checking geckodriver versions:
## BEGIN: PREDOWNLOAD
## BEGIN: DOWNLOAD
## BEGIN: POSTDOWNLOAD
## checking phantomjs versions:
## BEGIN: PREDOWNLOAD
## BEGIN: DOWNLOAD
## BEGIN: POSTDOWNLOAD
## [1] "Connecting to remote server"
## $applicationCacheEnabled
## [1] FALSE
## 
## $rotatable
## [1] FALSE
## 
## $mobileEmulationEnabled
## [1] FALSE
## 
## $networkConnectionEnabled
## [1] FALSE
## 
## $chrome
## $chrome$chromedriverVersion
## [1] "2.31.488763 (092de99f48a300323ecf8c2a4e2e7cab51de5ba8)"
## 
## $chrome$userDataDir
## [1] "C:\\Users\\crbdl\\AppData\\Local\\Temp\\scoped_dir8196_7347"
## 
## 
## $takesHeapSnapshot
## [1] TRUE
## 
## $pageLoadStrategy
## [1] "normal"
## 
## $databaseEnabled
## [1] FALSE
## 
## $handlesAlerts
## [1] TRUE
## 
## $hasTouchScreen
## [1] FALSE
## 
## $version
## [1] "60.0.3112.101"
## 
## $platform
## [1] "Windows NT"
## 
## $browserConnectionEnabled
## [1] FALSE
## 
## $nativeEvents
## [1] TRUE
## 
## $acceptSslCerts
## [1] TRUE
## 
## $locationContextEnabled
## [1] TRUE
## 
## $webStorageEnabled
## [1] TRUE
## 
## $browserName
## [1] "chrome"
## 
## $takesScreenshot
## [1] TRUE
## 
## $javascriptEnabled
## [1] TRUE
## 
## $cssSelectorsEnabled
## [1] TRUE
## 
## $setWindowRect
## [1] TRUE
## 
## $unexpectedAlertBehaviour
## [1] ""
## 
## $id
## [1] "0af78210537904cd2d3c8fcd6ae26526"

Una vez instalado el servidor ya podemos navegar sobre cualquier web, para esto utlizamos la función navigate.

Probemos con google:

remDr$navigate("http://google.com.ec")

Probemos con nuestra web oficial:

remDr$navigate("http://www.rusersgroup.com")

Manejamos al navegador con las siguientes funciones:

Atrás

remDr$goBack()

Adelante

remDr$goForward()

Obtener dirección

remDr$getCurrentUrl()
## [[1]]
## [1] "http://rusersgroup.com/"

Obtener título de la página web

remDr$getTitle()
## [[1]]
## [1] "R Users Group - Ecuador"

Maximizamos el navegador

#remDr$maxWindowSize()

Obtenemos una captura de pantalla de la página web

#remDr$screenshot(display = TRUE)

Volvamos a google y realicemos una búsqueda, para conocer con que elemento de la web debemos interactuar para realizar una búsqueda debemos localizar la sección que nos interesa dentro del código fuente, para nuestro caso, la entrada para búsquedas en google es el input “q”, si buscamos en el código fuente observamos lo siguiente:

<input class="lst lst-tbb sbibps" id="lst-ib" maxlength="2048" name="q" autocomplete="off" title="Buscar" type="text" value="" aria-label="Buscar">

Una vez detectada la sección utilizamos la función findElement utilizando como argumento el input “q” identificado de la siguiente forma:

remDr$navigate("http://www.google.com.ec")
webElem <- remDr$findElement(using = "css", "[name = 'q']")

Enviamos el texto a buscar con la función sendKeysToElement y el argumento key=“enter”

webElem$sendKeysToElement(list("R Users Group - Ecuador", key = "enter"))

o a su vez “007”

remDr$goBack()
webElem <- remDr$findElement(using = "css", "[name = 'q']")
webElem$sendKeysToElement(list("R Users Group - Ecuador", "\uE007"))

Una vez mostrados los resultados lo lógico es capturarlos, para esto nuevamente debemos buscar la secciòn que nos interesa, si observamos el código fuente vemos que cada resultado se encuentra dentro de un:

<h3 class = "r"> 

Por ejemplo el resultado:

R Users Group - Ecuador - Inicio | Facebook https://es-la.facebook.com › Lugares › Quito

Vemos que se encuentra en:

<h3 class="r"><a href="https://es-la.facebook.com/Rusersgroup/" onmousedown="return rwt(this,'','','','2','AFQjCNEOMP69o2UwXXISkHegFv5JBXIo4Q','','0ahUKEwid3cmjxuzVAhVIQyYKHYGtDMwQFggpMAE','','',event)">R Users Group - Ecuador - Inicio | Facebook</a></h3>

Una vez identificados procedemos a capturar con la función findElements y css selector de la siguiente forma:

webElems <- remDr$findElements(using = 'css selector', "h3.r")

Posterior a esto podemos aplicar la función getElementText para cada uno de los elementos capturados de la siguiente forma:

resHeaders <- unlist(lapply(webElems, function(x){x$getElementText()}))
resHeaders
##  [1] "Estimados: R User Group-Ecuador... - Miguel Alfonso Flores Sánchez ..."
##  [2] "R Users Group - Ecuador - Inicio | Facebook"                           
##  [3] "¿Quiénes somos? - R Users Group - Ecuador"                             
##  [4] "R Users Group - Ecuador"                                               
##  [5] "R Users Ecuador | LinkedIn"                                            
##  [6] "R Users Group - Ecuador | LinkedIn"                                    
##  [7] "Santiago Miño R. - Users - Datos Abiertos Ecuador"                     
##  [8] "R Users Group - Ecuador - YouTube"                                     
##  [9] "Local R User Group Directory (Revolutions) - Revolution Analytics Blog"
## [10] "RUsers Group-Ecuador (@rusersgroup) | Twitter"

Así mismo podemos obtener su url y su descripción:

webElems <- remDr$findElements(using = 'css selector', "div.s")
detalle <- unlist(lapply(webElems, function(x){x$getElementText()}))
detalle_lista <- strsplit(detalle, "\n")
url <- unlist(lapply(detalle_lista, function(x){x[1]}))
url
##  [1] "https://es-es.facebook.com/InecEcuador/posts/590279127669991"                 
##  [2] "https://es-la.facebook.com › Lugares › Quito"                                 
##  [3] "rusersgroup.com/about"                                                        
##  [4] "rusersgroup.com/"                                                             
##  [5] "https://ec.linkedin.com/in/r-users-ecuador-28510bab"                          
##  [6] "https://www.linkedin.com/company/r-users-group-ecuador - Traducir esta página"
##  [7] "catalogo.datosabiertos.gob.ec/en/user/smino"                                  
##  [8] "https://www.youtube.com/channel/UC-nYzfrbDhiA03hww0PCpXg"                     
##  [9] "blog.revolutionanalytics.com/local-r-groups.html"                             
## [10] "https://twitter.com/rusersgroup"
webElems <- remDr$findElements(using = 'css selector', "div.s")
detalle <- unlist(lapply(webElems, function(x){x$getElementText()}))
detalle_lista <- strsplit(detalle, "\n")
desc <- unlist(lapply(detalle_lista, function(x){x[2]}))
desc
##  [1] "Estimados: R User Group-Ecuador http://t.co/ui0zqS8bZK, ha compartido material sobre Modelos Lineales:..."                                                    
##  [2] "R Users Group - Ecuador, Quito. 488 Me gusta. R Users Group - Ecuador es una comunidad creada con el propósito de promover el uso del software..."            
##  [3] "R Users Group - Ecuador es una comunidad creada con el propósito de promover el uso del software estadístico R Project, además de fomentar la aplicación ..." 
##  [4] "Bienvenido a la web oficial de usuarios de R en Ecuador."                                                                                                     
##  [5] "Ecuador - Attended Escuela Politécnica Nacional"                                                                                                              
##  [6] "3 ago. 2017 - R Users Group - Ecuador es una comunidad creada con el propósito de promover el uso del software estadístico R Project, además de ..."          
##  [7] "Datasets · Organizations · Groups · About. Search Datasets. Home · Users · Santiago Miño R. Datasets · Activity Stream. Datasets. User hasn't created any ..."
##  [8] "Traducir esta página"                                                                                                                                         
##  [9] "Traducir esta página"                                                                                                                                         
## [10] "Traducir esta página"

Así mismo podemos navegar sobre varias páginas de resultados y capturarlos haciendo clicks con la función clickElement, esto y más opciones las mostraremos en futuras publicaciones.

Adicional, para cerrar el navegador debemos utilizar la función close y para cerrar el servidor selenium debemos utilizar la función stop.

remDr$close()
rD$server$stop()
## [1] TRUE