Curso
Quando você precisa fazer web scraping, normalmente usaria o pacote rvest, do Hadley Wickham. Esse pacote oferece uma solução simples e pronta para buscar o código HTML que gera uma página. No entanto, quando o site ou a página usa JavaScript para exibir os dados do seu interesse, o rvest não dá conta sozinho. Uma solução é usar o PhantomJS.
(Quer praticar a importação de mais dados em R? Experimente este tutorial.)
Carregar os pacotes necessários
Como primeiro passo, você vai carregar no workspace todos os pacotes de que precisamos para esta análise (se ainda não estiverem instalados no seu ambiente local, use install.packages() para disponibilizá-los):
library(rvest)
library(stringr)
library(plyr)
library(dplyr)
library(ggvis)
library(knitr)
options(digits = 4)
Extraindo dados gerados por JavaScript com R
O próximo passo é coletar os dados do TechStars usando PhantomJS. Veja o arquivo .js básico a seguir:
// scrape_techstars.js
var webPage = require('webpage');
var page = webPage.create();
var fs = require('fs');
var path = 'techstars.html'
page.open('http://www.techstars.com/companies/stats/', function (status) {
var content = page.content;
fs.write(path,content,'w')
phantom.exit();
});
Basicamente, o script renderiza a página HTML depois que o JavaScript subjacente faz o seu trabalho, permitindo buscar a página com todas as tabelas. Para manter tudo em R no restante da análise, sugerimos usar a função system() para chamar o PhantomJS (você precisa baixar e instalar o PhantomJS e colocá-lo no seu diretório de trabalho):
# Deixe o phantomJS extrair o techstars; a saída vai para techstars.html
system("./phantomjs scrape_techstars.js")
Depois desse pequeno desvio, você finalmente tem um arquivo HTML, techstars.html, no seu sistema local, que pode ser extraído com o rvest. Ao inspecionar a página do Techstars, dá para ver que as tabelas de interesse estão em divs com a classe CSS batch:
batches <- html("techstars.html") %>%
html_nodes(".batch")
class(batches)
[1] "XMLNodeSet"
Agora você tem uma lista de objetos XMLNodeSet: cada objeto contém os dados de um batch da TechStars. Neles, encontramos informações sobre a localização do batch, o ano, a estação, além das empresas, suas sedes atuais, status atual e o total de investimento captado. Não entraremos em detalhes sobre os passos de coleta e limpeza a seguir; você pode executar o código e inspecionar os resultados. Você verá algumas limpezas personalizadas para garantir que cada informação fique bem formatada:
batch_titles <- batches %>%
html_nodes(".batch_class") %>%
html_text()
batch_season <- str_extract(batch_titles, "(Fall|Spring|Winter|Summer)")
batch_year <- str_extract(batch_titles, "([[:digit:]]{4})")
# a localização é tudo no título do batch que não é ano nem estação
batch_location <- sub("\\s+$", "",
sub("([[:digit:]]{4})", "",
sub("(Fall|Spring|Winter|Summer)","",batch_titles)))
# cria o data frame com informações do batch
batch_info <- data.frame(location = batch_location,
year = batch_year,
season = batch_season)
breakdown <- lapply(batches, function(x) {
company_info <- x %>% html_nodes(".parent")
companies_single_batch <- lapply(company_info, function(y){
as.list(gsub("\\[\\+\\]\\[\\-\\]\\s", "", y %>%
html_nodes("td") %>%
html_text()))
})
df <- data.frame(matrix(unlist(companies_single_batch),
nrow=length(companies_single_batch),
byrow=T,
dimnames = list(NULL, c("company","funding","status","hq"))))
return(df)
})
# adiciona info do batch ao breakdown
batch_info_extended <- batch_info[rep(seq_len(nrow(batch_info)),
sapply(breakdown, nrow)),]
breakdown_merged <- rbind.fill(breakdown)
# une todas as informações
techstars <- tbl_df(cbind(breakdown_merged, batch_info_extended)) %>%
mutate(funding = as.numeric(gsub(",","",gsub("\\$","",funding))))
Com uma combinação de funções do R base, rvest, plyr e dplyr, agora temos o data frame techstars; um conjunto de dados de todas as empresas da TechStars, com todas as informações públicas bem formatadas:
techstars
## Source: local data frame [535 x 7]
##
## company funding status hq location year season
## 1 Accountable 110000 Active Fort Worth, TX Austin 2013 Fall
## 2 Atlas 1180000 Active Austin, TX Austin 2013 Fall
## 3 Embrace 110000 Failed Austin, TX Austin 2013 Fall
## 4 Filament Labs 1490000 Active Austin, TX Austin 2013 Fall
## 5 Fosbury 300000 Active Austin, TX Austin 2013 Fall
## 6 Gone! 840000 Active San Francisco, CA Austin 2013 Fall
## 7 MarketVibe 110000 Acquired Austin, TX Austin 2013 Fall
## 8 Plum 1630000 Active Austin, TX Austin 2013 Fall
## 9 ProtoExchange 110000 Active Austin, TX Austin 2013 Fall
## 10 Testlio 1020000 Active Austin, TX Austin 2013 Fall
## .. ... ... ... ... ... ... ...
names(techstars)
## [1] "company" "funding" "status" "hq" "location" "year"
## [7] "season"
Conclusão
Usando a combinação de ferramentas e códigos acima, conseguimos extrair dados de um site que usa JavaScript para gerar seu conteúdo. Como dá para ver, é um processo bem estruturado, que pode ser reproduzido facilmente depois que o código inicial está pronto. Quer aprender R e está procurando tutoriais e cursos de ciência de dados e R? Confira a DataCamp