Amazon 是网络上最大的公共商品数据目录之一。每个产品页面都会显示标题、价格、星级评分和库存状态,这些数据可用于竞争对手价格追踪、市场研究、品类分析和需求监测。手动保存一个产品轻而易举,但要保存数百甚至数千个产品,就需要一个爬虫,而这也正是 Amazon 防御机制开始发挥作用的地方。
本指南将向您介绍如何用 Ruby 抓取 Amazon 商品数据。您将构建一个可运行的小型脚本,通过 Crawling API 获取已渲染的商品页面,用 Nokogiri 解析内容,并提取一条干净的记录:商品标题、价格、评分和库存状态。整个教程仅涉及公开商品数据,结尾处的法律注意事项并非套话,请在对大规模数据进行爬取之前仔细阅读。
您将构建什么
一个 Ruby 脚本,接受 Amazon 商品 URL,通过 Crawling API 获取页面,然后用 Nokogiri 提取结构化记录。我们将从商品页面中提取以下字段:
- 标题 页面标题中显示的商品名称,例如"Echo Dot (5th Gen)"。
- 价格 购买框中显示的标价。
- 评分 平均星级评分(如果商品有评分)。
- 库存状态 库存状况,例如"In Stock"或"Currently unavailable"。
为何直接请求会在 Amazon 上失败
如果用裸 HTTP 客户端请求 Amazon 商品 URL,您很少能获得购物者看到的页面。有两个因素对您不利。首先,Amazon 会迅速标记自动流量:来自数据中心 IP 或请求模式不像真实浏览器的访问会遭遇 CAPTCHA 挑战、机器人检测页面或直接封锁,根本无法到达商品标记。其次,页面的部分内容会根据访客的地区、会话和设备动态渲染或变化,因此朴素的抓取方式往往返回精简或不一致的商品列表版本。
因此,一个可用的 Amazon 爬虫需要平台识别为真实购物者的 IP,并且在页面依赖渲染的地方,还需要一个真正运行页面的浏览器。您可以自行组装一个轮换住宅代理池和无头浏览器,但将它们组合在一起并保持稳定才是工作的主要难点。Crawling API 将两者合并为一次调用:您发送 URL,它会通过受信任的住宅 IP 获取页面,处理 CAPTCHA,并返回供您解析的完整 HTML。
Crawlbase 提供两种 token 类型。普通 token 获取页面 HTML,适合 Amazon 商品页面的默认选择。JavaScript (JS) token 会额外在真实浏览器中渲染页面,消耗更多积分,适用于仅在客户端脚本执行后才出现的内容。先从普通 token 开始,仅在所需字段返回空值时再切换到 JS token。
前置条件
在编写任何代码之前,您需要准备几样东西,都不需要太长时间。
基本的 Ruby 知识。 您应该能够编写并运行 Ruby 脚本,以及安装 gem。如果您是语言新手,Ruby 官方文档和任何入门课程都能让您达到本教程所假设的水平。
Ruby 2.7 或更高版本。 用 ruby --version 确认您的版本。如果没有安装,请从 ruby-lang.org 或通过 rbenv、rvm 等版本管理器进行安装。
Crawlbase 账户和 token。 注册账户,打开控制台,从账户页面复制您的普通请求 token。请像保管密码一样对待该 token:它用于验证您的请求,因此请勿将其提交到版本控制系统。Crawlbase 为您提供 1,000 次免费请求,无需信用卡,之后仅对成功的请求收费。
设置项目
创建一个名为 amazon_scraper.rb 的文件存放代码,然后安装爬虫所需的两个 gem:官方 Crawlbase 客户端和用于解析的 Nokogiri。
ruby --version gem install crawlbase gem install nokogiri
两个依赖项完成主要工作:crawlbase 是 Crawling API 的官方客户端,nokogiri 通过 CSS 选择器解析返回的 HTML,从而提取每个字段。如果您偏好使用 Gemfile,添加 gem 'crawlbase' 和 gem 'nokogiri',然后运行 bundle install。
了解 Amazon 商品页面
Amazon 商品页面将商品信息组织为稳定且可识别的元素。商品标题位于 id 为 productTitle 的标题标签中,价格显示在购买框内,平均评分在评论摘要中,库存状态在库存区块中。Amazon 的标记内容多且因类别而异,但这些核心字段具有一致的 id 和属性,可以精准定位。
在编写选择器之前,请在浏览器中打开商品页面,右键点击标题或价格,选择"检查",记录每个所需字段的 id 或 class。Amazon 会根据促销类型提供多种价格布局,因此在确定选择器前最好查看几个商品。像 #productTitle 这样的 id 是最耐用的锚点;基于 class 的价格 span 变化更频繁,因此计划针对线上页面进行验证。
步骤 1:获取商品页面
首先获取页面 HTML。引入 Crawlbase gem,用您的 token 初始化 API,指向商品 URL,然后发出请求。在解析之前先检查状态码,确保错误能及时暴露而不是静默失败。
require 'crawlbase' api = Crawlbase::API.new(token: 'YOUR_CRAWLBASE_TOKEN') url = 'https://www.amazon.com/dp/B09B8V1LZ3' response = api.get(url) if response.status_code == 200 html = response.body puts html[0..500] else puts "Request failed: #{response.status_code}" end
Crawlbase::API.new 调用会创建一个绑定到您 token 的客户端,api.get(url) 通过受信任的 IP 获取页面。响应包含 status_code 和 body;在读取 body 之前先检查状态码,可以让封锁或错误立即浮现,而不是产生令人困惑的解析失败。运行后您应该能在前 500 个字符中看到真正的 Amazon 商品标记,而不是机器人检测页面,这表明获取功能在您编写任何选择器之前已正常工作。
那个 api.get(url) 调用正在为您完成最难的部分。Amazon 需要从平台识别为真实购物者的 IP 发出请求,并一次性通过 CAPTCHA。Crawling API 通过轮换住宅 IP 获取页面,在服务端处理机器人检测,让您无需自行运行无头浏览器集群和代理池。先在免费套餐中指向商品 URL 试试。
步骤 2:用 Nokogiri 解析字段
拿到页面 HTML 后,将其载入 Nokogiri,通过选择器提取每个字段。Amazon 通过 #productTitle id 公开标题,通过购买框价格 span 公开价格,通过评论摘要公开平均评分,通过库存区块公开库存状态。当某个元素缺失时返回 nil 的小型辅助方法,可防止提取在某个特定商品没有该字段时崩溃。
require 'nokogiri' def text_at(doc, selector) node = doc.at_css(selector) node ? node.text.strip : nil end def parse_product(html) doc = Nokogiri::HTML(html) title = text_at(doc, '#productTitle') price = text_at(doc, '.a-price .a-offscreen') rating = text_at(doc, '#acrPopover .a-icon-alt') availability = text_at(doc, '#availability') { title: title, price: price, rating: rating, availability: availability } end
text_at 辅助方法查询单个元素并返回其去除首尾空格的文本,或在元素不存在时返回 nil,从而避免对空对象调用 .text 时抛出异常。对于价格,.a-price .a-offscreen 以价格的屏幕阅读器副本为目标,这是 Amazon 各种价格布局中最简洁的单一值。评分从 #acrPopover 提示文本(如"4.6 out of 5 stars"这样的字符串)读取,库存状态来自 #availability 区块。本教程旧版使用了较老的 #priceblock_ourprice id;Amazon 此后已迁移到 .a-price 结构,这正是针对线上页面验证选择器如此重要的原因。
Amazon 根据商品、促销类型和地区提供多种价格和库存布局,并会随时间调整 class 名称。请将上述选择器视为起始模板,而非合同。当某个字段返回 nil 时,请在浏览器的开发者工具中打开线上商品页面,找到当前的 id 或 class,并更新选择器。定期维护选择器是任何生产级爬虫的正常工作,不代表出了什么问题。
步骤 3:整合代码
现在将获取和解析整合为一个可运行的脚本。获取商品页面,将 HTML 交给解析器,打印结构化记录。
require 'crawlbase' require 'nokogiri' api = Crawlbase::API.new(token: 'YOUR_CRAWLBASE_TOKEN') def text_at(doc, selector) node = doc.at_css(selector) node ? node.text.strip : nil end def parse_product(html) doc = Nokogiri::HTML(html) { title: text_at(doc, '#productTitle'), price: text_at(doc, '.a-price .a-offscreen'), rating: text_at(doc, '#acrPopover .a-icon-alt'), availability: text_at(doc, '#availability') } end url = 'https://www.amazon.com/dp/B09B8V1LZ3' response = api.get(url) if response.status_code == 200 product = parse_product(response.body) product[:url] = url puts JSON.pretty_generate(product) else puts "Request failed: #{response.status_code}" end
这就是完整的爬虫。它引入两个 gem,构建客户端,获取页面,解析四个字段,并打印输出。JSON.pretty_generate 来自 Ruby 标准库,如果您的环境不会自动加载,请在顶部添加 require 'json'。将 url 替换为任意 Amazon 商品,相同的解析器即可处理,因为字段选择器基于页面结构,而非针对特定商品。
输出示例
用 ruby amazon_scraper.rb 运行脚本,您将得到一条干净的记录,可写入 JSON、CSV 或数据库。
{ "title": "Echo Dot (5th Gen, 2022 release) | Smart speaker with Alexa | Charcoal", "price": "$49.99", "rating": "4.7 out of 5 stars", "availability": "In Stock", "url": "https://www.amazon.com/dp/B09B8V1LZ3" }
您可以将这条记录存储起来、追加到 CSV,或导入价格监控仪表盘。由于解析器返回的是普通 Ruby 哈希,用标准库将其写入任意格式只需一行代码。
扩展到多个商品
单个商品只是演示;真实任务需要处理一批商品。最简洁的扩展方式是将 URL 存入数组,循环遍历,收集每条解析记录。请求之间加入短暂的停顿,以便控制速率,避免对 Amazon 进行密集轰炸。
urls = [ 'https://www.amazon.com/dp/B09B8V1LZ3', 'https://www.amazon.com/dp/B07FZ8S74R', 'https://www.amazon.com/dp/B08N5WRWNW' ] results = [] urls.each do |url| response = api.get(url) next unless response.status_code == 200 product = parse_product(response.body) product[:url] = url results << product puts "Scraped: #{product[:title]}" sleep 2 end puts JSON.pretty_generate(results)
next unless 守卫会跳过未返回干净 200 响应的 URL,这样一个失败的响应不会中断整个运行,而 sleep 2 则保持了合理的请求节奏。如果您有数千个 URL 并希望并发处理而无需自行管理队列,专为此设计的异步 Crawler 正适合这种场景。如果您需要收集商品 URL,关于抓取 Amazon 商品数据的配套指南和电商网络爬虫概述都可以从本文止步处继续深入。
保持不被封锁
即使有受信任的 IP 处理请求,Amazon 也会监控爬虫形态的流量。以下几个习惯能保持运行健康,适用于任何难以爬取的商业目标。
-
控制请求速率。 商品间加入延迟,而不是全速爬取列表。循环中的
sleep 2是下限,不是上限。 - 依赖轮换。 住宅 IP 池将请求分散到众多真实用户地址,避免单一地址触发速率限制。Crawling API 为您处理这些;如果自建技术栈,这是最值得投入的部分。
- 关注状态码。 当运行开始返回挑战或错误时,说明当前速率或 IP 层级已不够用。将其视为退让的信号,而非可以忽略的噪音。
更全面的操作指南,请参阅如何在不被封锁的情况下爬取网站。如果您想用另一种语言,Java 网络爬虫指南覆盖了相同的方法,只是使用了不同的技术栈。
抓取 Amazon 数据合法吗?
抓取 Amazon 数据是否被允许取决于 Amazon 的服务条款、您所在的司法管辖区以及您对数据的使用方式。Amazon 的使用条款限制了自动化访问,因此无论您的工具多么谨慎,爬取行为都可能违反这些条款。本文中的代码不会改变这一事实,只是让技术层面的工作得以实现。请阅读 Amazon 的使用条款和 robots.txt,并将两者作为数据收集的边界。
以下几条原则值得遵守。仅收集公开数据:商品标题、价格、评分和库存状态,这些信息任何人无需账户即可在商品页面看到。尊重 Amazon 的速率预期,将请求量控制在不对其服务器造成压力的范围内。避免收集个人数据,包括与可识别购物者、评论者或卖家相关的任何信息(超出公开列表范围),不要将受版权保护的媒体(如商品图片或评论文本)作为自有内容重新发布。如果您计划将数据用于商业目的,请获取许可或签订正式协议,而非假定沉默即意味着同意。
本指南刻意将范围限制在公开商品页面,因为这是保持合规的边界。它不涵盖登录后才可见的内容、账户或订单数据、支付或结账流程,也不涉及任何绕过身份验证的尝试。若需授权或批量访问,Amazon 通过其商品广告和卖家合作伙伴计划提供官方 API,当您需要大量数据、有保障的结构或商业权利时,那才是正确的工具。如果您的项目需要的不只是公开商品列表,官方 API 或数据协议才是正确路径,而非更聪明的爬虫。
核心要点
- Amazon 会封锁朴素请求。 裸 HTTP 客户端会遭遇 CAPTCHA 和机器人检测,因此您需要从受信任的 IP 发出请求,并通过这些防御。
-
Crawling API 处理最难的部分。 一次
api.get(url)调用即可通过轮换住宅 IP 和 CAPTCHA 层获取页面,让您无需自行运行代理池和浏览器集群。 -
Nokogiri 负责提取。 将 HTML 载入后,将标题、价格、评分和库存状态映射到当前选择器,如
#productTitle和.a-price .a-offscreen,并预期这些选择器会漂移。 -
用循环和延迟扩展规模。 遍历商品 URL 列表,根据状态码守卫,用
sleep控制请求速率,大量时使用异步 Crawler。 - 仅限公开数据。 尊重 Amazon 的条款和 robots.txt,对于授权或批量数据优先使用官方 Amazon API,切勿触及账户、订单或个人信息。
常见问题
为何普通 Ruby 请求会在 Amazon 上失败?
Amazon 会迅速标记自动流量。从数据中心 IP 发出的裸 Net::HTTP 或 open-uri 请求通常会收到 CAPTCHA、机器人检测页面或直接封锁,而非商品标记。要获取真实数据,您需要从 Amazon 识别为真实购物者的 IP 发出请求,并通过机器人检测,这正是 Crawling API 为您处理的工作。
Amazon 需要用普通 token 还是 JS token?
从普通 token 开始。对于标准 Amazon 商品页面,普通 token 可返回您所需的标题、价格、评分和库存状态,且消耗的积分更少。仅在您需要的特定字段在客户端渲染、使用普通 token 时返回空值的情况下,才切换到 JavaScript (JS) token。
价格应使用哪个选择器?
使用 .a-price .a-offscreen,它以价格的屏幕阅读器副本为目标,是 Amazon 各种价格布局中最一致的单一值。过去教程中的旧 #priceblock_ourprice id 在大多数页面上已不再匹配。由于 Amazon 提供多种价格布局,请在大规模运行之前针对线上商品验证该选择器。
如何一次抓取多个 Amazon 商品?
将商品 URL 存入数组,循环遍历,用相同函数解析每个页面,收集记录。根据状态码守卫,确保一个失败的响应不会中断整个运行,并在请求之间加入短暂的 sleep 以控制速率。对于数千个 URL,异步 Crawler 可无需您管理队列即可并发处理。
我可以从 Amazon 抓取订单、账户或仅限购买框的数据吗?
本指南不涵盖需要登录才能访问的数据。订单历史、账户详情和结账流程位于身份验证之后,因此不属于公开数据,爬取它们或绕过登录违反 Amazon 的条款。若需对更丰富数据的授权访问,正确路径是官方 Amazon API 或合作伙伴协议。
为何使用 Nokogiri 而不是正则表达式来解析 HTML?
Nokogiri 将页面解析为完整的 DOM,因此您可以通过 CSS 选择器或 XPath 选择字段,即使周围的标记发生变化也能获得可靠结果。针对 HTML 的正则表达式在 Amazon 重新排序属性或以不同方式嵌套元素时就会失效。对于任何真实的爬虫,像 Nokogiri 这样的解析器既更健壮,也更易于维护。
大规模爬取任何站点,无需与基础设施对抗。
Crawlbase 负责处理代理、指纹和 CAPTCHA,让你的团队专注于交付数据流水线,而非维护爬取管道。1,000 次请求免费,无需信用卡。

