数据爬虫:R语言爬虫实战

就目前国内R相关的论坛和社区而言,关于R爬虫的文章大多集中在两个包:RCurl和rvest。RCurl功能强大,但对用户并不够友好,一般看完简单的介绍后仍然不懂,Hadley曾仿照RCurl写过一款精简版的包——httr,功能虽不如RCurl那么齐全,但对于用户而言绝对友好。rvest作为一款方便快捷的R爬虫包,类似于Python的BeautifulSoup,配上CSS选择器简直就是结构化网页数据抓取的利器。但rvest对于动态加载的网页却很难抓取,对于需要提交表单请求、应用AJAX进行动态加载数据的网页,RCurl可以实现其中大部分功能。这里在简要概述R爬虫生态的基础上,将对rvest实现结构化网页的数据抓取、RCurl/httr实现动态网页抓取、构造GET/POST表单、实现模拟登录、通过R向网页提交cookie等内容进行简单的讲解和探讨。

需要强调的是,爬虫本身就是一项系统性工程,涉及如何通过软件与网页进行通信、下载解析网页、从网页中提取目标信息以及如何将抓取到的数据存入本地数据库等内容。这里仅针对前两个环节如何在R中实现进行讨论。

01

静态网页数据抓取利器rvest

所谓静态网页,就是你打开一个目标网页,在网页里可以直接看到想要抓取的数据,点击鼠标右键查看源代码后发现在HTML结构中可以原原本本地找到刚刚在网页里的目标数据,这就是静态网页。对于这样的网页,rvest可以提供一套较为完整的数据抓取方案,配上一些小工具,就可以快速实现爬虫。以豆瓣网为例,用rvest可以轻松爬取豆瓣电影Top 250(豆瓣电影Top 250:https://movie.douban.com/top250),有兴趣的读者不妨尝试一下。

一个完整的爬虫过程可以简要地概括为“抓”“析”“存”三个阶段,大意是(1)通过程序语言将目标网页抓取下载下来,(2)应用相关函数对URL进行解析并提取目标数据,(3)最后将数据存入本地数据库。无论一个爬虫框架有多复杂,大体都离不开这三大过程,其间涉及网页遍历、批量抓取、如何设置代理、cookie登入、伪装报头、GET/POST表单提交等复杂的技术细节,这些都增加了爬虫难度。下面简单看一下rvest数据抓取的几个核心函数:

read_html():下载并解析网页

html_nodes():定位并获取节点信息

html_text():提取节点属性文本信息

尽管rvest没有提供数据存储函数,上述三个函数已经可以简单实现网络爬虫的前两个过程了。下面以链家杭州二手房网页为例,利用rvest构建一个简单的爬虫流程。

链家杭州二手房网页

#加载所需的包:

library("xml2")

library("rvest")

library("dplyr")

library("stringr")

#对爬取页数进行设定并创建数据框:

I <- 1:100

house_inf <- data.frame()

#利用for循环封装爬虫代码,进行批量抓取:

for (i in 1:100){

#发现url规律,利用字符串函数进行url拼接并规定编码:

web <- read_html(str_c("http://hz.lianjia.com/ershoufang/pg", i), encoding = "UTF-8")

#提取房名信息:

house_name <- web%>%html_nodes(".houseInfo a")%>%html_text()

#提取房名基本信息并消除空格

house_basic_inf <- web%>%html_nodes(".houseInfo")%>%html_text()

house_basic_inf <- str_replace_all(house_basic_inf," ","")

#提取二手房地址信息

house_address <- web%>%html_nodes(".positionInfo a")%>%html_text()

#提取二手房总价信息

house_totalprice <- web%>%html_nodes(".totalPrice")%>%html_text()

#提取二手房单价信息

house_unitprice <- web%>%html_nodes(".unitPrice span")%>%html_text()

#创建数据框存储以上信息

House<-data.frame(house_name,house_basic_inf,house_address,house_totalprice,house_unitprice)

house_inf <- rbind(house_inf,house)

}

#将数据写入csv文档

write.csv(house_inf, file="../house_inf.csv")

抓取效果如下表所示。

抓取效果表

利用rvest进行静态网页的数据抓取非常简单易学好上手。几行代码即可实现R语言爬虫,对初学者也是相当友好。需要说明的是,这里定位HTML节点信息时使用了前文提到的selectorGadget选择器。

02

httr包实现对网页动态加载数据的抓取

对于网页动态加载的数据,继续使用rvest可能就不合适了。这时R提供了其他选择来实现相应的抓取目的。httr包相当于RCurl的精简版,相对轻巧易上手,对于用户而言也比较友好。不过,在爬取之前需要掌握HTML的基本知识。httr包与RCurl的核心函数对比如下表所示。

httr包与RCurl的核心函数对比

下面就以网易云课堂为例,简要叙述利用AJAX加载数据的网页信息抓取思路。

网易云课堂的网页示例如下。想要了解网易云提供了哪些课程,这些课程中又有哪些课程比较受欢迎,不妨使用爬虫爬取数据一探究竟。

网易云课程

打开网易云课堂,账号登录后点击鼠标右键,打开开发者工具定位到XHR,尝试寻找几次之后可以发现课程数据都封装在一个studycourse.json的文件中。点击preview可以发现数据以json形式非常规整地排列(如下图),就可以开始构建数据抓取方案了。

查找数据所在的真实URL

接下来定位到Headers版块,重点关注版块中的如下信息:General信息下的Request URL, Request Method, Status Code;Response Headers信息下的Connection, Content-Type;Request Headers信息下的Accept, Cookie, Referer, User-Agent以及最后的Request Payload信息。获取这些信息之后,就可以在R中构造爬虫请求了。

可以看到请求响应状态码为200,说明爬虫请求得到成功响应。

剩下的事情就是提取响应结果中的目标信息了,可以先简单查看一下数据在结果中的位置,再做处理(见下图)。

POST方法请求结果的数据结构

找到目标数据后可采用一些信息提取方法将数据从这个庞大的列表中抽出,具体操作各位读者不妨动手尝试一下。构建完整爬虫和单次执行POST请求方法一样,可以使用循环遍历来实现,响应结果一般是个较为庞大的列表,需要大家花一些时间进行信息提取,这里就不再赘述,感兴趣的读者可以自己动手尝试。