Curso
Cuando necesitas hacer web scraping, normalmente utilizarías el paquete rvest de Hadley Wickham. Este paquete ofrece una solución lista para usar para obtener el código HTML que genera una página web. Sin embargo, cuando el sitio o la página usa JavaScript para mostrar los datos que te interesan, al paquete rvest le falta la funcionalidad necesaria. Una solución es usar PhantomJS.
¿Quieres practicar la importación de más datos en R? Prueba este tutorial.
\nCarga los paquetes necesarios
\nComo primer paso, tendrás que cargar en tu espacio de trabajo todos los paquetes que necesitaremos para este análisis (si aún no los has instalado en tu sistema local, usa install.packages() para tenerlos disponibles):
library(rvest)\nlibrary(stringr)\nlibrary(plyr)\nlibrary(dplyr)\nlibrary(ggvis)\nlibrary(knitr)\noptions(digits = 4)\n\nScraping de datos generados con JavaScript en R
\nEl siguiente paso es recopilar los datos de TechStars usando PhantomJS. Echa un vistazo al siguiente archivo .js básico:
\n// scrape_techstars.js\n\nvar webPage = require('webpage');\nvar page = webPage.create();\n\nvar fs = require('fs');\nvar path = 'techstars.html'\n\npage.open('http://www.techstars.com/companies/stats/', function (status) {\n var content = page.content;\n fs.write(path,content,'w')\n phantom.exit();\n});\n\nEl script básicamente renderiza la página HTML después de que el código JavaScript haya hecho su trabajo, lo que te permite obtener la página con todas sus tablas. Para permanecer en R durante el resto del análisis, te sugerimos usar la función system() para invocar PhantomJS (tendrás que descargar e instalar PhantomJS y colocarlo en tu directorio de trabajo):
# Deja que PhantomJS haga scraping de TechStars; el resultado se guarda en techstars.html\nsystem(\"./phantomjs scrape_techstars.js\")\n\nTras este pequeño rodeo, por fin tienes un archivo HTML, techstars.html, en tu sistema local, que puede extraerse con rvest. Al inspeccionar la página de Techstars vemos que las tablas que nos interesan están en divs con la clase CSS batch:
batches <- html(\"techstars.html\") %>%\n html_nodes(\".batch\")\n\nclass(batches)\n\n[1] \"XMLNodeSet\"\n\nAhora tienes una lista de objetos XMLNodeSet: cada objeto contiene los datos de una cohorte de TechStars. Dentro podemos encontrar información sobre la ubicación de la cohorte, el año, la temporada, así como sobre las empresas, su sede actual, su estado actual y la financiación total que han levantado. No entraremos al detalle de los pasos de recopilación y limpieza de datos a continuación; puedes ejecutar el código tú mismo e inspeccionar qué hace. Verás que hay limpieza personalizada para asegurarnos de que cada dato quede bien formateado:
batch_titles <- batches %>%\n html_nodes(\".batch_class\") %>%\n html_text()\n\nbatch_season <- str_extract(batch_titles, \"(Fall|Spring|Winter|Summer)\")\nbatch_year <- str_extract(batch_titles, \"([[:digit:]]{4})\")\n# la ubicación es todo lo del título que no es año ni temporada\nbatch_location <- sub(\"\\\\s+$\", \"\",\n sub(\"([[:digit:]]{4})\", \"\",\n sub(\"(Fall|Spring|Winter|Summer)\",\"\",batch_titles)))\n\n# crea un data frame con la información de la cohorte\nbatch_info <- data.frame(location = batch_location,\n year = batch_year,\n season = batch_season)\n\nbreakdown <- lapply(batches, function(x) {\n company_info <- x %>% html_nodes(\".parent\")\n companies_single_batch <- lapply(company_info, function(y){\n as.list(gsub(\"\\\\[\\\\+\\\\]\\\\[\\\\-\\\\]\\\\s\", \"\", y %>%\n html_nodes(\"td\") %>%\n html_text()))\n })\n df <- data.frame(matrix(unlist(companies_single_batch),\n nrow=length(companies_single_batch),\n byrow=T,\n dimnames = list(NULL, c(\"company\",\"funding\",\"status\",\"hq\"))))\n return(df)\n})\n\n# añade la información de cohorte al desglose\nbatch_info_extended <- batch_info[rep(seq_len(nrow(batch_info)),\n sapply(breakdown, nrow)),]\nbreakdown_merged <- rbind.fill(breakdown)\n\n# combina toda la información\ntechstars <- tbl_df(cbind(breakdown_merged, batch_info_extended)) %>%\n mutate(funding = as.numeric(gsub(\",\",\"\",gsub(\"\\\\$\",\"\",funding))))\n\nCon una combinación de funciones base de R y de rvest, plyr y dplyr, ahora tenemos el data frame techstars; un conjunto de datos con todas las empresas de TechStars y toda la información pública, ya bien formateada:
techstars\n\n## Source: local data frame [535 x 7]\n##\n## company funding status hq location year season\n## 1 Accountable 110000 Active Fort Worth, TX Austin 2013 Fall\n## 2 Atlas 1180000 Active Austin, TX Austin 2013 Fall\n## 3 Embrace 110000 Failed Austin, TX Austin 2013 Fall\n## 4 Filament Labs 1490000 Active Austin, TX Austin 2013 Fall\n## 5 Fosbury 300000 Active Austin, TX Austin 2013 Fall\n## 6 Gone! 840000 Active San Francisco, CA Austin 2013 Fall\n## 7 MarketVibe 110000 Acquired Austin, TX Austin 2013 Fall\n## 8 Plum 1630000 Active Austin, TX Austin 2013 Fall\n## 9 ProtoExchange 110000 Active Austin, TX Austin 2013 Fall\n## 10 Testlio 1020000 Active Austin, TX Austin 2013 Fall\n## .. ... ... ... ... ... ... ...\n\nnames(techstars)\n\n## [1] \"company\" \"funding\" \"status\" \"hq\" \"location\" \"year\"\n## [7] \"season\"\n\nConclusión
\nCon la combinación de herramientas y código anterior hemos logrado extraer datos de un sitio web que usa JavaScript para generar su contenido. Como ves, es un proceso muy estructurado que se puede repetir fácilmente una vez tienes el código inicial. ¿Quieres aprender R y buscas tutoriales y cursos de ciencia de datos y R? Échale un vistazo a DataCamp.
\n