随着网络的发展,越来越多的数据被动态生成。这使得通过API提取数据变得越来越困难。R语言中的网络爬虫技术应运而生,为那些项目需要海量数据的数据科学家提供了帮助。
值得庆幸的是,编程语言也在不断演进以应对这些挑战。R 便是此类语言的典型代表,它专为高效处理海量任务而设计。
在本教程中,我将通过探讨R在实际应用中的价值,带您了解其基本原理。我还将介绍R网络爬虫领域中最受欢迎的包之一——rvest。随后,我将演示R在提取网站数据方面的具体运作方式。

随着网络的发展,越来越多的数据被动态生成。这使得通过API提取数据变得越来越困难。R语言中的网络爬虫技术应运而生,为那些项目需要海量数据的数据科学家提供了帮助。
值得庆幸的是,编程语言也在不断演进以应对这些挑战。R 便是此类语言的典型代表,它专为高效处理海量任务而设计。
在本教程中,我将通过探讨R在实际应用中的价值,带您了解其基本原理。我还将介绍R网络爬虫领域中最受欢迎的包之一——rvest。随后,我将演示R在提取网站数据方面的具体运作方式。
R是S编程语言的开源版本,融合了Scheme的语义。它于1993年中期首次亮相,1995年开源,并于2000年发布了首个稳定的测试版。
Ross Ihaka 和 Robert Gentleman 设计 R 的初衷是“快速且忠实地将想法转化为软件”。
R 是一种函数式编程语言,在数据科学家中广为人知。其最常见的应用场景包括:
与 SAS 和 SPSS 相比,R 是全球使用最广泛的分析工具。其活跃且支持性强的社区拥有近 200 万用户。
若我们观察一些将 R 融入业务的企业及其具体做法,会发现:
然而,与其他编程语言相比,R 始终与 Python 处于竞争之中。两者都提供了网络爬虫工具,并且拥有活跃的开发者社区。
差异主要体现在目标受众上。Python 拥有非常易学的语法和众多高级特性,这使其对初学者和非技术用户更具吸引力。
R 初看可能略显晦涩,但它更专注于统计分析。它提供了更丰富的内置数据分析和可视化工具。因此,对于处理海量数据的项目(如网络爬虫),它可能是一个更好的选择。
rvest 是 R 语言中用于网页抓取的最受欢迎的包之一。它提供了强大且简单的解析功能。Python 的 BeautifulSoup 是其灵感来源,且它是 tidyverse 集合的一部分。
听起来不错,但既然 R 本身就有能完成相同任务的原生库,为什么还要使用 rvest 呢?第一个充分的理由是:rvest 实际上是 httr 和 xml2 包的封装。这意味着它既能处理 GET 请求,又能进行 HTML 解析。
因此,您只需使用一个库而非两个,代码将变得更加简洁紧凑。不仅如此,rvest 还能接受字符串作为输入,并处理 XML 解析和文件下载。
然而,我们需要考虑到网站上存在更多动态生成的内容。原因多种多样:性能、用户体验等。由于 rvest 无法处理 JavaScript 的执行,因此此时你需要寻找替代方案。
好了,理论部分到此为止。让我们看看 R 在实际应用场景中的表现。在本教程中,我选取了一本非常著名的书籍——乔治·奥威尔的《1984》在 Goodreads 上的页面。您可以在此处访问该网站:https://www.goodreads.com/book/show/61439040-1984。
我想了解这本书的受欢迎程度随时间推移的变化情况。为此,我将抓取评论列表,并提取每条评论的日期和评分。最后,我会将数据保存到外部文件中,以便后续由其他程序进行处理。
但首先,您必须确保已具备编写代码所需的一切条件。
关于集成开发环境(IDE),你有两种选择:
在本教程中,我将使用后者。您可以在此处下载:https://www.rstudio.com/products/rstudio/download/。
RStudio Desktop的免费版本足以让你熟悉基础操作。和之前一样,请按照安装说明进行操作。
打开 RStudio 并创建一个新的空目录。我将在名为“goodreads-rvest.r”的新文件中编写代码。
在提取数据之前,您需要明确需要哪些数据。Rvest 同时支持 CSS 和 XPath 选择器,请根据需求选择。
如果您计划开展更复杂的爬取项目,建议您具备基本的 HTML 和 CSS 知识。这里有一个不错的入门练习平台。
如果您对 HTML 不太熟悉,也有一些非技术性的选择。例如,Chrome 浏览器提供了一个名为 SelectorGadget 的扩展程序。它允许您点击页面上的任意位置,并显示用于获取数据的 CSS 选择器。
然而,并非所有网站都像 Goodreads 那样简单。我将选择通过手动检查 HTML 来查找 CSS 选择器,从而提取数据。
在浏览器中访问目标网址,向下滚动至“社区评论”部分。然后右键单击该区域,选择“检查”以打开开发者工具。
ID 为“other_reviews”的容器正是我关注的重点。现在,请使用“检查”按钮查找评论日期和评分的 CSS 选择器。
因此,你会注意到以下几点:
确认所有先决条件后,你终于可以开始编写代码了。
install.packages('rvest')
将光标置于行尾,并点击代码编辑器上方的“运行”按钮。您将在控制台中看到包的安装进度。
安装仅需执行一次,因此现在您可以注释或删除前面的那行代码:
#install.packages('rvest')
现在需要加载(或导入)该库:
library(rvest)
我将使用 read_html 函数向目标网站发送一个 GET 请求,从而下载所需的 HTML 文档。通过这种方式,我将下载所需的 HTML 文档:
book_html <- read_html("https://www.goodreads.com/book/show/61439040-1984")
结果现已存储在 book_html 变量中,您只需在控制台输入以下内容即可查看:
如果您在任何时候需要查看要使用的函数的官方文档,请在控制台中输入:
help(function_name)
RStudio 将打开一个 HTTP 服务器,提供直达文档的链接。对于 read_html 函数,输出结果如下:
为了获取评论列表,我将使用 html_elements 函数。它将接收我之前找到的 CSS 选择器作为输入:
reviews <- book_html %>% html_elements('div.review')
结果将是一个 XML 节点列表,我将对其进行遍历以获取每个元素的日期和评分:
R 程序员使用管道运算符“%>%”来增强代码的灵活性。其作用是将左侧操作数的值作为参数传递给右侧操作数。
您可以将操作数进行链式调用(如本指南后文所示),从而帮助您大幅减少局部变量的使用。如果不使用管道运算符,上述代码行将如下所示:
reviews <- html_elements(book_html, 'div.review')
为了收集数据,我将在循环外部初始化两个向量。通过快速查看网站,我可以确保这两个向量具有相同的长度。
dates <- vector()ratings <- vector()
现在,在遍历评论列表时,我需要查找两个值:日期和评分。正如你之前所见,日期是一个带有 reviewDate 类的锚元素。
评分是一个带有 staticStars 类的 span 元素,其中每颗星对应五个 span 子元素。如果用户给出一颗星,则该 span 元素将具有 p10 类名,其余的则具有 p0 类名。
代码如下:
for (review in reviews) {
review_date = review %>% html_element('a.reviewDate') %>% html_text()
dates <- c(dates, review_date)
review_rating_element = review %>% html_element('span.staticStars')
valid_stars = review_rating_element %>% html_elements('span.p10')
review_rating = length(valid_stars)
ratings <- c(ratings, review_rating)
}请注意 html_element 函数;这不是笔误。当你需要提取一组 XML 节点时可以使用 html_elements,而提取单个节点时则使用 html_element。
在此示例中,我针对 HTML 文档中较小的一部分(即一条评论)使用了后者。我还使用了 html_text 函数来获取所找到元素的文本内容。
最后,我将这两个向量合并到一个数据框中,以便集中管理数据:
result = data.frame(date = dates, rating = ratings)
最终结果将如下所示:
众所周知,如果不将结果存储在某处,数据抓取便毫无意义。在 R 中,将数据写入 CSV 文件只需一行代码:
write.csv(result, "reviews.csv")
结果必须是矩阵或数据框(当前结果已符合),否则系统会尝试进行转换。运行代码并检查项目目录,你会发现可以使用文本编辑器、Excel文档等工具打开之前的表格。
结果必须是矩阵或数据框(当前数据已符合此格式),否则系统会尝试进行转换。运行代码并检查项目目录,你会发现可以使用文本编辑器、Excel 文档等工具打开之前的表格。
毋庸置疑,我们的数据列表仅包含 30 条记录。而网站上显示的评论超过 90,000 条,评分超过 300 万条。那么究竟发生了什么?答案是分页。
不仅如此,请返回浏览器并点击第二页。你会发现列表内容发生了变化,但 URL 却保持不变。这意味着他们使用状态来动态加载列表的另一部分。
在这种情况下,rvest可能派不上用场。相反,自动化浏览器可以模拟点击行为来加载列表的其余部分。RSelenium就是这样一个库的例子,但我将把这个主题留作后续练习。
希望本教程能为你提供一个扎实的 R 语言网络爬虫入门基础。现在,你在为下一个项目选择技术栈时,可以更轻松地做出决策。
但请注意,本文并未涵盖网络爬虫的诸多挑战。您可以在这本通俗易懂的指南中找到更详细的概念说明。

Raluca Penciuc 是 WebScrapingAPI 的全栈开发工程师,主要负责开发爬虫、优化规避机制,并探索可靠的方法以降低在目标网站上的被检测概率。