在本教程中,我们将展示以从亚马逊网站的一个可公开访问的URL 中提取产品评论为目标,使用R的rvest(R用户使用率最高的爬虫包)进行网络抓取所涉及的所有步骤。
使用R语言进行网页抓取的入门
第一步:了解我们将在本教程中使用的工具。
了解工具:R 和 rvest
R是一种功能丰富且易于使用的语言,它可以用于统计分析和数据可视化,为数据整理和动态类型提供有用的工具。
rvest——来自英文单词“harvest”(收割)——是提供网络抓取功能的最流行的爬虫包之一,这也要归功于其极其友好的用户界面。Vanilla rvest 仅允许用户从一个网页中提取数据,这非常适合起步阶段初学者的探索。之后可以使用polite库扩展它以实现抓取多个页面的需求。
设置开发环境
如果您尚未在RStudio 中使用过R语言,请按照此处的说明进行安装。
完成后,打开控制台并安装rvest:
install.packages("rvest")
作为tidyverse集合的一部分,官方建议使用集合中的其他包进一步扩展 rvest 的内置功能,例如用于代码可读性的magrittr或用于处理 HTML 和 XML 的xml2。可以通过直接安装 tidyverse 来做到这一点:
install.packages("tidyverse")
了解网页
网页抓取是一种在合规的自动化流程中从网站检索数据的技术。
由该定义从而产生了三个重要的考虑因素:
数据有多种格式。
不同的网站有各不相同的方式显示信息。
抓取的数据需要合法合规。
要了解如何从URL中抓取信息,首先需要了解网页内容是如何通过HTML 标记语言和 CSS 表单样式语言展示的。
HTML提供网页的内容和结构——加载到网络浏览器中以创建树状文档对象模型(DOM)——通过使用“标签”组织内容。
标签具有层次结构,每个标签都有一个特定的功能,应用于其开始() 和结束 () 语句中包含的所有内容:
<!DOCTYPE html>
<html lang="en-gb" class="a-ws a-js a-audio a-video a-canvas a-svg a-drag-drop a-geolocation a-history a-webworker a-autofocus a-input-placeholder a-textarea-placeholder a-local-storage a-gradients a-transform3d -scrolling a-text-shadow a-text-stroke a-box-shadow a-border-radius a-border-image a-opacity a-transform a-transition a-ember" data-19ax5a9jf="dingo" data-aui-build-date="3.22.2-2022-12-01">
▶<head>..</head>
▶<body class="a-aui_72554-c a-aui_accordion_a11y_role_354025-c a-aui_killswitch_csa_logger_372963-c a-aui_launch_2021_ally_fixes_392482-t1 a-aui_pci_risk_banner_210084-c a-aui_preload_261698-c a-aui_rel_noreferrer_noopener_309527-c a-aui_template_weblab_cache_333406-c a-aui_tnr_v2_180836-c a-meter-animate" style="padding-bottom: 0px;">..</body>
</html>
标签<html>是任何网页的最小组件,其中嵌套有<head>,和<body>标签。<head>和 <body> 本身是其他标签的“父母”,<div>(对于文档部分)和<p>(对于段落)是它们最常见的“孩子”。
在上面的代码片段中,可以看到与每个HTML“元素”关联的“属性”:lang、class和style是预先构建的;开头的属性data-是亚马逊自定义的。
class连同id属性对于网络抓取特别感兴趣,因为它们允许我们分别针对一组元素或其中的某个特定元素。这最初是为了在 CSS 中设置样式。
CSS 提供网页的样式。从着色到定位和调整大小,你可以选择任何HTML元素并为其样式属性分配新值。你还可以通过样式属性在HTML元素中内联应用CSS样式,如在上面的代码片段中所见:
<body .. style="padding-bottom: 0px;">
在纯CSS 中,会被写作:
body {padding-bottom: 0px;}
在这里,主体是“选择器”,padding-bottom是“属性”,0px是“值”。
任何标签, class, 或者id可以被用作 CSS 选择器。
用户可以通过script标签通过JavaScript编程语言提供的功能与网页上显示的内容进行动态交互。在用户交互之后,显示的内容可能会发生变化,可能会出现新的内容;我们稍后会讨论到高级网络抓取工具可以模仿用户交互。
了解开发者工具
主要的网页浏览器提供内置的开发人员工具,允许收集和实时更新网页上的技术信息,用于日志记录、调试、测试和性能分析。在本教程种,我们将使用Chrome的DevTools来进行。
可以从浏览器右上角的‘更多工具’中访问开发人员工具:

在Chrome浏览器中打开开发者工具的流程
在开发者工具中,可以点击“元素”选项卡滚动浏览原始的HTML。当滚动浏览HTML的任何行时,你会看到在网页中呈现的以蓝色突出的对应元素:

从Chrome浏览器中的开发者工具访问选择的元素的过程
你还可以单击左上角红框内的图标,然后从网页中选择任何呈现的元素以反定向到其原始的HTML副本,并且以蓝色突出显示。
这两个过程是你在本教程中所需要的提取CSS 描述符的全部过程。
深入研究 R 中的 Web 抓取:教程
在本节中,我们将探索如何通过网络抓取亚马逊 URL来提取产品评论。
先决条件
确保您的 Rstudio 环境中安装了以下内容:
R = 4.2.2
rvest = 1.0.3
整洁宇宙 = 1.3.2
交互式浏览网页
你可以使用 Chrome 浏览器中的开发者工具浏览你的URL中的HTML并创建包含我们感兴趣的想要抓取信息的HTML元素的所有类和 ID 的列表,在本文中即产品评论:

从Chrome浏览器的开发者工具中选择的所看到的亚马逊产品页面中的用户评价
每个用户评价都属于div一个id格式为:
customer_review_$INTERNAL_ID.
上面截图中用户评价对应的div的HTML内容如下:
<div id="customer_review-R2U9LWUSIPY0GS" class="a-section celwidget" data-csa-c-id="kj23dv-axnw47-69iej3-apdvzi" data-cel-widget="customer_review-R2U9LWUSIPY0GS">
<div data-hook="genome-widget" class="a-row a-spacing-mini">..</div>
<div class="a-row">
<a class="a-link-normal" title="4.0 out of 5 stars" href="" target="_blank">https://www.amazon.co.uk/gp/customer-reviews/R2U9LWUSIPY0GS/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&ASIN=B07SR4R8K1">
<i data-hook="review-star-rating" class="a-icon a-icon-star a-star-4 review-rating">
<span class="a-icon-alt">4.0 out of 5 stars</span>
</i>
</a>
<span class="a-letter-space"></span>
<a data-hook="review-title" class="a-size-base a-link-normal review-title a-color-base review-title-content a-text-bold" href="" target="_blank">https://www.amazon.co.uk/gp/customer-reviews/R2U9LWUSIPY0GS/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&ASIN=B07SR4R8K1">
<span>Very good controller if a little overpriced</span>
</a>
</div>
<span data-hook="review-date" class="a-size-base a-color-secondary review-date">..</span>
<div class="a-row a-spacing-mini review-data review-format-strip">..</div>
<div class="a-row a-spacing-small review-data">
<span data-hook="review-body" class="a-size-base review-text">
<div data-a-expander-name="review_text_read_more" data-a-expander-collapsed-height="300" class="a-expander-collapsed-height a-row a-expander-container a-expander-partial-collapse-container" style="max-height:300px">
<div data-hook="review-collapsed" aria-expanded="false" class="a-expander-content reviewText review-text-content a-expander-partial-collapse-content">
<span>In all honesty I'm not sure why the price is quite as high ….</span>
</div>
…</div>
…</span>
…</div>
…</div>
你感兴趣的每条用户评价都有其独特的类别:作为标题的review-title-content、作为正文的review-text-content和作为评价的review-rating。
你可以直接使用“simple selector”以检查该类别在文档中是否是唯一的。一种更简单的方法是改用 CSS 描述符,即使将来该类被分配给新元素,它也将保持其唯一性。
通过右键单击 DevTools 中的元素并选择Copy selector来简单地检索 CSS 描述符:

从Chrome浏览器的开发者工具中为一个元素复制 CSS selector的过程
你可以通过以下方式来定义你的三个选择器:
customer_review-R2U9LWUSIPY0GS > div:nth-child(2) > a.a-size-base.a-link-normal.review-title.a-color-base.review-title-content.a-text-bold > span for the title
customer_review-R2U9LWUSIPY0GS > div.a-row.a-spacing-small.review-data > span > div > div.a-expander-content.reviewText.review-text-content.a-expander-partial-collapse-content > span for the body
customer_review-R2U9LWUSIPY0GS > div:nth-child(2) > a:nth-child(1) > i.review-rating > span for the rating
*.review-rating was manually added for better consistency.
用于网页抓取的 CSS selector与XPath的对比
在本教程中我们将使用CSS selector来识别用于网页抓取的元素。另一种常用方法是使用 XPath,即 XML 路径,它通过元素在 DOM 中的完整路径来标识元素。
你可以按照与 CSS selector相同的过程提取完整的 XPath。例如,评论标题是:
/html/body/div[2]/div[3]/div[6]/div[32]/div/div/div[2]/div/div[2]/span[2]/div/div/div[3]/div[3]/div/div[1]/div/div/div[2]/a[2]/span
CSS selector会稍微快一些,但是XPath具有更好的向后兼容性。除了这些细小的差异之外,选择二者中的哪一个更多是取决于个人喜好而不是技术方面的区别。
以编程方式从网页中提取信息
虽然我们可以直接使用控制台开始探索如何抓取URL的网页数据,但考虑到可追溯性和再现性,我们将通过使用source()控制来创建一个脚本从而运行。
创建脚本后,第一步是加载已安装的库:
library(”rvest”)
library(”tidyverse”)
然后,你可以按如下编程方式来提取你所感兴趣的内容。首先,创建一个变量,你将在其中存储要搜索的URL:
HtmlLink<- "https://www.amazon.co.uk/Xbox-Elite-Wireless-
Controller-2/dp/B07SR4R8K1/ref=sr_1_1_sspa?
crid=3F4M36E0LDQF3"
接下来,从URL中提取亚马逊标准标识号 (ASIN),将其用作唯一的产品 ID:
ASIN <- str_match(HtmlLink, "/dp/([A-Za-z0-9]+)/")[,2]
使用RegEx清理通过网络抓取所提取的文本是常见且推荐的动作,因为可以保数据质量。
现在,就可以下载网页当中的HTML内容:
HTMLContent <- read_html(HtmlLink)
read_html() 函数是 xml2 包的一部分。
如果你print()了内容,我们就会发现它与之前分析的原始 HTML 结构相匹配:
{html_document}
<html lang="en-gb" class="a-no-js" data-19ax5a9jf="dingo">
[1] <head>\n<meta http-equiv="Content-Type" content="text/ht ...
[2] <body class="a-aui_72554-c a-aui_accordion_a11y_role_354 ...
你现在可以为页面上的所有产品评论提取三个感兴趣的节点。使用 Chrome 的 DevTools 提供的 CSS Descriptors,修改为从字符串中删除特定客户评论标识符#customer_review-R2U9LWUSIPY0GS和“ >”连接符;你还可以利用 rvest 的 html_nodes() 和 html_text() 功能将 HTML 内容保存在单独的对象中。
以下命令将提取评论标题:
review_title <- HTMLContent %>%
html_nodes("div:nth-child(2) a.a-size-base.a-link-normal.review-title.a-color-base.review-title-content.a-text-bold span") %>%
html_text()
review_title中的一个条目示例是“Very good controller if a little overpriced.”。
下面的代码将提取评论正文:
review_body <- HTMLContent %>%
html_nodes("div.a-row.a-spacing-small.review-data span div div.a-expander-content.reviewText.review-text-content.a-expander-partial-collapse-content span") %>%
html_text()
review_body中的一个条目示例是“In all honesty, I’m not sure why the price…”。
您可以使用以下命令提取评论评分:
review_rating <- HTMLContent %>%
html_nodes("div:nth-child(2) a:nth-child(1) i.review-rating
span") %>%
html_text()
review_rating中的一个条目示例是“4.0 out of 5 stars”。
为了提高这个变量的质量,只提取评级“4.0”并将其转换为 int:
review_rating <- substr(review_rating, 1, 3) %>% as.integer()
管道功能 %>% 由 magrittr 工具包提供。
现在是时候导出 tibble 中抓取的内容以进行数据分析了。
tibble是一个 R 包,也属于 tidyverse 集合,用于操作和打印数据帧。
df <- tibble(review_title, review_body, review_rating)
输出数据帧如下:

tibble 输出的抓取数据
最后,推荐将代码重构到函数 scrape_amazon <- function(HtmlLink) ,因为这是一个最佳实践方案并且能更好地准备扩展到多个 URL的代码。
扩展到多个 URL
在创建网页数据抓取模板后,就可以通过网页抓取和爬虫为亚马逊上所有顶级竞争对手的产品创建 URL列表。
当扩展到多个 URL 以提供解决方案时,你需要概述应用程序的技术要求。
拥有明确定义的技术需求将确保你正确的支持业务需求并与现有系统达到无缝集成。
根据具体的技术要求,需要更新抓取功能以支持以下组合:
实时或批处理
输出格式,例如 JSON、NDJSON、CSV 或 XLSX
输出目标,例如电子邮件、API、webhook 或云存储
上文已经说过,你可以使用polite扩展 rvest来抓取多个网页。polite 通过使用三个主要功能创建和管理网页收集会话,完全符合网络主机的 robots.txt 文件以及内置速率限制和响应缓存:
bow()为特定 URL 创建抓取会话,即,它向您介绍网络主机并请求抓取权限。
scrape()访问 URL 的 HTML;您可以通过管道将函数传入html_nodes()和html_text()传出 rvest 以检索特定内容。
nod()将会话的 URL 更新到下一页,而无需重新创建会话。
直接从他们的网站上引用,“有礼貌的会话的三大组成部分是先寻求许可,然后慢慢来,从不问第二遍。”
下一步:预建还是自建?
要开发可以为企业提取优质数据的最先进的网页数据抓取工具,需要具备以下的功能:
具有网页数据提取专业知识的数据专家团队
一个 DevOps 工程师团队,在代理管理和反机器人规避方面具有专业知识,可以通过验证码从而解锁并不太公开访问的网站
一个在创建用于实时和批量数据提取的基础设施方面具有专业知识的数据工程师团队
了解隐私数据保护法律要求(如 GDPR 和 CCPA)的法律专家团队
网络内容有多种格式,很难找到结构完全相同的两个网站。网站越复杂,要抓取的功能和数据越多,所需的编程知识就越高级,更不用说解决方案所需的额外时间和资源了。
一般来说,你肯定希望至少实现以下这些高级功能:
最大限度地减少验证码和机器人检测的机会:这里的一个简单方法是添加一个随机 sleep() 以避免网页服务器和常规请求模式过载。另一种更有效的方法是使用user_agent或你的代理服务器在不同的IP之间分发请求。
抓取 Javascript 支持的网站:在以上的亚马逊示例中,选择特定产品变量时 URL是不会更改的。这对于抓取评论是可以接受的,因为它们是共享的,但对于抓取产品规格而言则不行。如果要模拟动态网页中的用户交互,可以使用RSelenium等工具来自动化网页浏览器的导航功能。
当想要访问资源有限的网页数据、确保数据质量或出现需要解锁更高级网页的案例时,预构建的网页抓取工具可能是正确的选择。