TL;DR
- 亚马逊产品页面包含的不仅仅是价格的可抓取字段 — 标题、价格、星级评分、评论数量、ASIN、图片、库存状态以及当前赢得“购买框”的卖家都存在于页面的HTML中,无需登录。
- 亚马逊的robots.txt和使用条款限制自动访问,而本次会议的抓取工具在尝试直接加载amazon.com URL时被拒绝 — 将任何抓取项目视为需要合规审查,而不仅仅是技术审查。
- 亚马逊官方的产品广告API(PA-API 5.0)已被弃用。 调用现在返回HTTP 403,告知调用者迁移到新的创作者API,该API要求活跃的亚马逊联属会员注册以及在过去30天内至少有10笔合格销售 — 这是大多数非联属团队无法达到的门槛。
- 正是由于这个差距,受管控的爬取API成为了现在受限制的官方API和从头构建反机器人堆栈之间的实用中间路线 — Nstproxy Crawl处理JavaScript渲染和代理路由,因此下面的教程代码只需处理解析。
- 单个产品页面和搜索结果页面使用不同的选择器模式。 产品页面以ID为关键,如
#productTitle;搜索结果页面则以每个[data-component-type="s-search-result"]块上的data-asin属性为关键。 - 相同的抓取可以通过大约十行额外代码变成价格跟踪器 — 下方的额外提示将一次性请求转变为计划循环,而Nstproxy代理管理器则是在该循环遍历多个SKU或市场时的自然下一步。
你可以从亚马逊抓取的实际数据
亚马逊的产品和搜索结果页面展示产品标题、当前价格、星级评分、评论数量、ASIN、主图片URL、库存/可用状态,以及在产品页面上的当前赢得购买框的卖家,所有这些都在无需登录的HTML中呈现。客户评论包含额外字段(评论文本、星级评分、“已验证购买”标志),但也有评论者显示名称,这被视为个人数据,应该得到与从公共页面收集的其他个人标识符相同的最小化处理。
团队通常出于以下四个原因提取这些数据:跨目录的竞争价格监控、关于类别排名和评论情感的市场研究、品牌自己列表的最低广告价格(MAP)合规检查,以及在进入新市场之前的潜在客户或商品组合研究。这四个都是同一个基本任务的变体 — 获取页面、提取一组稳定的字段、按计划重复 — 这就是本教程所构建的模式。
快速浏览
亚马逊使用JavaScript渲染价格和库存,并在少量请求中阻止大多数未旋转的IP — Nstproxy Crawl在一个API调用中处理浏览器渲染和代理路由,因此下面的代码只需解析它返回的页面。
抓取亚马逊数据是否合法?
合法性取决于收集的内容及其方式,而不是抓取亚马逊是否可能。亚马逊的robots.txt禁止大多数路径的自动爬取 — 本文自己的研究工具在尝试直接获取amazon.com URL时被拒绝,这很好地说明了该限制的广泛适用性 — 而亚马逊的使用条款则单独禁止未经许可的数据挖掘工具。以上两个事实都无法单独解决法律问题:在hiQ Labs诉LinkedIn一案中,第九巡回法院发现抓取公开可访问的个人资料数据可能并未违反《计算机欺诈和滥用法》,而在Van Buren诉美国一案中,最高法院将CFAA的范围缩小至未经授权的访问而非不当使用其他可访问的数据。Craigslist诉3Taps一案则相反:在明确阻止或发出停止和停止通知后继续抓取会显著增加法律风险。 在实际操作中,低风险的操作方式是以合理的请求速率收集公开可见的列表、价格和可用性,重点关注市场元数据而非评论者的个人信息,并在项目符合条件时优先使用官方 API。高风险的操作方式则包括在登录后进行抓取、获取个人或支付数据、绕过 CAPTCHA 或其他显式技术障碍,并在亚马逊已经限制或阻止数据源时继续进行。本教程保持在第一类:公开可见的目录数据,无身份验证绕过,且不提供突破 CAPTCHA 挑战的指导。
官方 API 与 DIY 抓取器与托管爬虫 API
有三条路径可以获取相同的产品数据,选择主要取决于资格和团队希望拥有多少反机器人基础设施。亚马逊自己的产品广告 API (PA-API 5.0) 多年来一直是最低风险的来源,但亚马逊已经弃用它——对旧端点的调用现在返回 HTTP 403,指示开发人员迁移到新的创作者 API,该 API 需要主动加入亚马逊联盟计划 并且 在过去 30 天内至少有 10 符合条件的销售。这个资格门槛排除了大多数进行价格监控、市场调研或 MAP 合规的团队,特别是那些尚未运营活跃的联盟商店的团队。完全自制的抓取器(requests 或 Playwright 加 BeautifulSoup)是第二条路径,但这意味着在编写提取代码之前,需要自己构建和维护 JavaScript 渲染、代理轮换和重试逻辑,而亚马逊频繁更改其标记,因此维护成本会增加。Nstproxy Crawl 是第三条路径,后面的教程将以此为基础。
Nstproxy Crawl 是一个 API,通过一次请求将 URL 转换为 Markdown、清理过的 HTML 或原始页面数据,具备真实浏览器中的 JavaScript 渲染和 Nstproxy 自己的代理池处理网络层——这是自制亚马逊抓取器必须自行组装的两个部分。它特别适用于此任务,因为亚马逊的产品和搜索页面依赖于客户端渲染以显示价格和可用性,并且从单个静态 IP 访问亚马逊的抓取器在少量请求后会被限速或阻止。该 API 在成功提取时收费,而不是在每次尝试时收费,所以返回 403 或 404 的页面仍然计费(请求本身成功),但从未到达亚马逊的重试则不计费。
- 包含 JavaScript 渲染 — 依赖客户端脚本进行价格和库存状态的产品和搜索页面在 API 返回结果之前会完全渲染,而不是返回一个半加载的壳。
- 自动处理代理路由 — 请求通过 Nstproxy 的住宅或数据中心池路由,无需维护单独的代理供应商或 IP 轮换脚本。
- Markdown 或 HTML 输出 — 下面的教程直接解析返回的 HTML,但 Markdown 输出同样适用于将结果输入 LLM 基于汇总器的团队,而无需固定解析器。
前提条件
在编写任何代码之前,从 Nstproxy 仪表板 获取 API 密钥,并安装本教程所用的 Python 包:
pip install requests beautifulsoup4
requests 用于调用 Nstproxy Crawl API;beautifulsoup4 用于解析返回的 HTML。您不需要拥有亚马逊账户、登录或浏览器安装——Nstproxy Crawl 运行浏览器端。
第一步:抓取单个亚马逊产品页面
将产品 URL 发送到 Nstproxy Crawl 的抓取端点,请求 markdown 和 html 输出。附加 ?async=true 将调用设置为同步——它等待页面渲染完成并直接返回结果,而不是返回一个任务 ID 以进行轮询:
import requests API_KEY = "YOUR_API_KEY" PRODUCT_URL = "https://www.amazon.com/dp/B0BSHF7WHW" # 替换为真实的 ASIN URL response = requests.post( "https://api.nstproxy.com/api/v1/crawl/scrape?async=true", headers={"x-api-key": API_KEY, "Content-Type": "application/json"},
page_html = result["data"]["html"]
检查 result["success"] 在这里很重要——HTTP 200 只是确认 Nstproxy Crawl 收到了请求,并不能保证亚马逊返回了一个可用的产品页面。onlyMainContent 被设置为 False 是因为亚马逊产品页面上的价格和购买框小部件位于任何通用的“主要内容”启发式规则之外。
步骤 2:解析标题、价格、评分和 ASIN
亚马逊的产品页面使用稳定的元素 ID 来键入其核心字段,而不是生成的 CSS 类名称,这就是它们值得直接针对而不是抓取可见文本的原因:
from bs4 import BeautifulSoup import re soup = BeautifulSoup(page_html, "lxml") title_el = soup.select_one("#productTitle") title = title_el.get_text(strip=True) if title_el else
每个 select_one 调用都被保护以防止缺失元素引发异常——亚马逊针对 A/B 测试运行不同的页面布局,因此一个匹配大多数列表的选择器偶尔会错过一个。以防御性构建每个字段,正如 BeautifulSoup 和 lxml 通常用于 HTML 解析,能让一个缺失的小部件不会崩溃整个批处理作业。
步骤 3:抓取亚马逊搜索结果页面以获取多个 ASIN
搜索结果页面在一次请求中返回多个产品,这比单独抓取产品页面更有效,尤其是当目标是类别快照而不是单个项目的详细信息时。向 Nstproxy Crawl 的请求与步骤 1 相同,只是指向一个搜索 URL:
SEARCH_URL = "https://www.amazon.com/s?k=wireless+earbuds" response = requests.post( "https://api.nstproxy.com/api/v1/crawl/scrape?async=true", headers={"x-api-key": API_KEY, "Content-Type": "application/json"}, json={"url": SEARCH_URL,
每个结果卡片在 data-asin 属性中携带其 ASIN,这比任何视觉布局更具稳定性——过滤掉没有 data-asin 的卡片也会安静地删除赞助位和不是真正产品结果的布局小部件。
示例输出模式
无论来源是单个产品页面还是搜索结果页面,归一化到相同的模式可使下游存储和比较变得简单:
{ "asin": "B0BSHF7WHW", "title": "示例无线耳塞", "price": "$49.99", "rating": "4.3", "review_count": 2148, "availability":
将 scraped_at 与记录的其余部分一起存储,使下一部分成为可能——没有时间戳,就无法判断价格是否发生了变化,或者抓取是否在不同的时刻运行。
额外提示:将其转变为始终在线的价格跟踪器
单次抓取回答了“现在这个价格是多少”; 而定期循环回答了“这个价格有变吗”——这是对 MAP 合规性或竞争监控更有用的问题。将步骤 1 的请求封装在调度器中,并与最后存储的价格进行差异对比,可以通过小的补充来实现:
import schedule import time import json PRICE_HISTORY_FILE = "price_history.json" def check_price(asin, url): response = requests.post( "https://api.nstproxy.com/api/v1/crawl/scrape?async=true", headers={"x-api-key":
尝试: 与 open(PRICE_HISTORY_FILE) 一起: 历史记录 = json.load(f) 除了 FileNotFoundError: 历史记录 = {} 如果历史记录.get(asin) != current_price **问:如果我遇到验证码该怎么办?** 停止并撤退,而不是尝试解决或绕过它——验证码是亚马逊明确发出的信号,表明当前的请求模式看起来是自动化的,而继续这样做完全属于上述高风险类别。 **问:我可以抓取亚马逊的客户评价吗?** 评论文本和星级评分在页面上与价格和标题一样可见,但评论还包括评论者的显示名称,这属于个人数据——在收集评价数据之前决定最小化存储的数据、存储时间以及目的,是值得考虑的,而不是之后再考虑。




