跳至主要内容

使用 R 与 PhantomJS 进行网页抓取

使用 PhantomJS 在 R 中抓取由 Javascript 生成数据的简短教程。
· 5分钟 阅读

使用 AI 探索

当您需要进行网页抓取时,通常会使用 Hadley Wickham 的 rvest 包。该包提供开箱即用的简便方案来获取生成网页的 html 代码。然而,当网站或网页使用 JavaScript 来展示您感兴趣的数据时,rvest 包就缺少所需的功能。一个解决方案是使用 PhantomJS。

(想练习将更多数据导入 R?请尝试本教程。)

加载所需的包

第一步,您需要将本次分析所需的所有包加载到工作区(如果您尚未在本地系统安装这些包,请使用 install.packages() 进行安装):

library(rvest)
library(stringr)
library(plyr)
library(dplyr)
library(ggvis)
library(knitr)
options(digits = 4)

使用 R 抓取由 Javascript 生成的数据

下一步是使用 PhantomJS 收集 TechStars 数据。请查看以下基础 .js 文件:

// 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();
});

该脚本的基本作用是在底层的 javascript 代码执行完毕后渲染 HTML 页面,使您能够获取包含所有表格的 HTML 页面。为便于在后续分析中继续留在 R 环境中,我们建议您使用 system() 函数调用 PhantomJS(您需要先下载并安装 PhantomJS,并将其放在您的工作目录中):

# 让 phantomJS 抓取 techstars,输出写入 techstars.html
system("./phantomjs scrape_techstars.js")

经过这段小小的绕行后,您终于在本地系统上得到了一个 HTML 文件 techstars.html,接下来即可用 rvest 抓取。对 Techstars 网页的检查显示,我们所需的表格位于 css 类为 batch 的 div 中:

batches <- html("techstars.html") %>%
  html_nodes(".batch")

class(batches)
[1] "XMLNodeSet"

您现在拥有一个由 XMLNodeSet 对象组成的列表:每个对象都包含单个 TechStars 批次的数据。我们可以在其中找到关于批次所在地点、年份、季节,以及公司、公司现总部、当前状态和其累计融资额等信息。下面我们不深入介绍数据收集与清洗的每一步;您可以自行运行代码并查看其效果。您会发现一些自定义清洗步骤,旨在确保每一条信息都格式良好:

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})")
# location info is everything in the batch title that is not year info or season info
batch_location <- sub("\\s+$", "",
                      sub("([[:digit:]]{4})", "",
                          sub("(Fall|Spring|Winter|Summer)","",batch_titles)))

# create data frame with batch info.
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)
})

# Add batch info to breakdown
batch_info_extended <- batch_info[rep(seq_len(nrow(batch_info)),
                                  sapply(breakdown, nrow)),]
breakdown_merged <- rbind.fill(breakdown)

# Merge all information
techstars <- tbl_df(cbind(breakdown_merged, batch_info_extended)) %>%
  mutate(funding = as.numeric(gsub(",","",gsub("\\$","",funding))))

结合核心 R、rvest、plyr 与 dplyr 的函数,我们现在得到了 techstars 数据框;这是一份包含全部 TechStars 公司的数据集,且所有公开信息都已整洁格式化:

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"

结语

通过上述工具与代码的组合,我们成功从一个使用 JavaScript 生成数据的网站中抓取了数据。可以看到,这是一个非常结构化的流程,一旦有了初始代码,后续就能轻松完成。想学习 R,并寻找数据科学与 R 的教程和课程?请访问 DataCamp

主题