Walmart 有些商品的价格会在 。如果你曾经试着用程序去追踪这些变化,就会知道有多折磨:脚本跑了 20 分钟,结果开始悄悄把 CAPTCHA 页面当成正常的 200 OK 返回给你。
在 Thunderbit 的数据提取工作里,我花了大量时间研究 Walmart 的反爬机制,也想把这些经验完整分享出来——哪些方法在 2025 年真的还管用,哪些“静默失败”会悄悄污染你的数据,以及在自己写爬虫、付费用抓取 API、还是直接上无代码工具之间,到底该怎么权衡。这篇指南会覆盖三种提取方式(HTML 解析、__NEXT_DATA__ JSON、内部 API 拦截)、很多教程完全不会讲的生产级错误处理,以及一个务实的选择框架,帮你判断哪条路最适合你。不管你是在写 Python,还是只想在午饭前拿到一份装满价格的表格,这里都能找到答案。
为什么要用 Python 抓取 Walmart?
Walmart 是全球营收最高的零售商——在 2025 财年营收达到 ,并且 。网站上大约有 ,而 Walmart CFO 还提到平台上有 。其中大约 ,这意味着目录变化非常快——卖家更替、变体变化、库存每天都在波动。

正因为这种波动,抓取数据才有价值。季度报表看不到夜间爬取能抓到的变化。以下是我最常见的应用场景:
| 应用场景 | 使用人群 | 提取内容 |
|---|---|---|
| 竞品价格监控 | 电商运营、调价工具 | 价格、促销、MAP 合规 |
| 商品目录补全 | 销售与商品团队 | 描述、图片、规格、变体 |
| 库存可用性跟踪 | 供应链、Dropship 卖家 | 库存状态、卖家信息 |
| 市场调研与趋势分析 | 市场、产品经理 | 评分、评论、类目结构 |
| 潜客开发 | 销售团队 | 卖家名称、商品数量、类目 |
仅竞品价格监控软件市场在 2025 年就达到 ,并预计到 2033 年增长到 50.9 亿美元。消费者行为也在推动这个需求: ,而且 83% 的人会跨多个网站比较价格。
Python 是这类工作的默认语言。Apify 的 2026 基础设施报告显示, ,而核心库 requests 每周下载量达到 。如果你在做任何规模的抓取,基本上用的都是 Python。
为什么 Walmart 是最难抓取的网站之一
Walmart 难抓,主要是因为它把 两套商业反爬产品串联在一起: 负责边缘 WAF 和 TLS 指纹识别,接着是 负责 JavaScript 行为挑战层。Scrape.do 把这种组合称为“极其罕见,而且非常难绕过”。

,仅 Akamai 一项就是 9/10。按我的经验,这个评分很准确。
你实际面对的是这些东西:
Akamai Bot Manager 会检查你的 TLS 指纹(JA3/JA4 hash)、HTTP/2 帧顺序、请求头顺序和大小写,以及会话 cookie(_abck、ak_bmsc)。普通 Python requests 发出的 TLS 指纹,和真实浏览器完全不是一个样子——Akamai 在请求到达 Walmart 服务器之前就会把它识别出来。
PerimeterX/HUMAN 则在 Akamai 之后运行,它会执行 JavaScript 指纹识别(px.js),检查 navigator 属性、canvas 渲染、WebGL、音频上下文,以及行为生物特征(鼠标移动、滚动速度、按键节奏)。最典型的失败表现,就是那个臭名昭著的 ——你要按住按钮大约 10 秒,同时系统采集你的行为信号。Oxylabs 的说法很直接:“Walmart 使用的是 PerimeterX 提供的 ‘Press & Hold’ CAPTCHA 模式,几乎不可能靠代码来解决。”
真正危险的是 静默封锁。Walmart 不是返回 403,而是直接返回 HTTP 200,但内容是 CAPTCHA 页面。:“Walmart 即使返回 CAPTCHA 页面,也会给你 200 OK 状态码。你不能只靠状态码判断请求是否成功。” 你的脚本会心安理得地把 CAPTCHA HTML 当成“商品不存在”,然后继续跑。最后一半数据都是脏的,而你根本不知道。
还有一个问题是 门店范围数据。Walmart 的价格和库存是跟地区相关的,受 locDataV3 和 assortmentStoreId 这类 cookie 控制。如果 cookie 不对,你看到的是“默认全国数据”,它看起来很完整,但和真实用户看到的结果并不一致。缺少这些 cookie 不会弹错误页,只会给你 错误但看不出来的数据,这比直接被封更糟。
三种从 Walmart 提取数据的方法(以及它们的对比)
在进入实操之前,先看看三种主要的提取方式。大多数竞争对手的教程只讲一两种,我会把三种都讲清楚,这样你可以按自己的情况选择最合适的方案。
| 方法 | 可靠性 | 数据完整度 | 反爬难度 | 维护成本 |
|---|---|---|---|---|
| HTML + BeautifulSoup | ⚠️ 低(选择器会随着部署失效) | 中等 | 高 | 高 |
__NEXT_DATA__ JSON | ✅ 较好 | 高 | 中高 | 中等 |
| 内部 API 拦截 | ✅ 最佳 | 最高(变体、库存、评论) | 中高 | 低(结构化 JSON) |
| Thunderbit(无代码) | ✅ 较好 | 高 | 低(AI 代劳) | 无 |
对 Walmart 来说,HTML 解析是最差的选择——网站使用的是 Next.js,并且 CSS 类名带哈希,每次部署都会变。__NEXT_DATA__ JSON 方法则更务实,也是 2024–2026 年几乎所有严肃开源 Walmart 爬虫的主流方案。内部 API 拦截功能最强,但也有很多教程一笔带过的限制。至于 Thunderbit,则适合你根本不想自己搭管线的场景。
搭建 Python 环境来抓取 Walmart
你需要准备这些东西:
- 难度: 中等
- 所需时间: 环境配置约 30 分钟,再加上编码时间
- 你需要: Python 3.10+、pip、代码编辑器,以及(用于生产环境)代理服务或抓取 API
先创建项目目录和虚拟环境:
1mkdir walmart-scraper && cd walmart-scraper
2python -m venv venv
3source venv/bin/activate # On Windows: venv\Scripts\activate
安装所需库:
1pip install curl_cffi parsel beautifulsoup4 lxml
curl_cffi 是 2025 年抓取高难度站点的标准工具。它是一个 libcurl 绑定,可以精确模拟浏览器的 TLS 指纹。:“Walmart 会把 TLS 指纹识别作为反爬的一部分,就算把 User-Agent 改成真实浏览器,也绕不过去。” 单靠 requests 或 httpx,无论你怎么设置请求头,都过不了 Akamai。真正起作用的是带 impersonate="chrome124" 的 curl_cffi。
另外你还会用到内置的 json、csv,以及 time、random、logging,后面我们会讲到生产级写法。
分步实操:用 Python 抓取 Walmart 商品页
第 1 步:请求 Walmart 商品页面
你的第一步,是发出一个不会立刻被拦的 HTTP 请求。下面是 2024–2026 年 Scrapfly、Scrapingdog、Oxylabs 和 ScrapeOps 常用的一套标准请求头:
1from curl_cffi import requests
2HEADERS = {
3 "User-Agent": (
4 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
5 "AppleWebKit/537.36 (KHTML, like Gecko) "
6 "Chrome/124.0.0.0 Safari/537.36"
7 ),
8 "Accept": (
9 "text/html,application/xhtml+xml,application/xml;q=0.9,"
10 "image/avif,image/webp,*/*;q=0.8"
11 ),
12 "Accept-Language": "en-US,en;q=0.9",
13 "Accept-Encoding": "gzip, deflate, br",
14 "Upgrade-Insecure-Requests": "1",
15 "Sec-Fetch-Dest": "document",
16 "Sec-Fetch-Mode": "navigate",
17 "Sec-Fetch-Site": "none",
18 "Sec-Fetch-User": "?1",
19 "Referer": "https://www.google.com/",
20}
21session = requests.Session(impersonate="chrome124")
22url = "https://www.walmart.com/ip/Apple-AirPods-Pro-2nd-Generation/1752657021"
23response = session.get(url, headers=HEADERS)
impersonate="chrome124" 这个参数是核心。它让 curl_cffi 精确匹配 Chrome 124 的 TLS ClientHello、HTTP/2 帧顺序,以及伪头部顺序。如果没有它,Akamai 会看到一个 Python 特征的 JA3 hash,并在请求到达 Walmart 应用层之前就将其拦截。
被封后的响应长什么样: 如果你在 HTML 标题里看到 "Robot or human?",或者页面重定向到 walmart.com/blocked,说明你已经被识别出来了。麻烦之处在于,Walmart 经常会返回 200 状态码,但内容其实是 CAPTCHA 页面——所以只看 response.ok 完全不够。
如果是生产环境或重复调用,你几乎一定需要 住宅代理。数据中心 IP 会被 Akamai 的 IP 信誉系统快速封掉。后面的生产级错误处理和代理策略我会继续讲。
第 2 步:从 __NEXT_DATA__ JSON 中解析商品数据
Walmart.com 是一个 Next.js 应用,服务端渲染的 HTML 会把完整的 hydration payload 放进一个脚本标签里:<script id="__NEXT_DATA__" type="application/json">。这就是金矿。
:“到了 2026 年,Walmart 仍然使用 Next.js,并把结构化 JSON 放在 __NEXT_DATA__ script 标签里,因此提取隐藏数据比传统 CSS 选择器解析更可靠。” 几个高知名度的开源 Walmart 爬虫——包括 、、——都在用这个方法。
提取方式如下:
1import json
2from parsel import Selector
3sel = Selector(text=response.text)
4raw = sel.xpath('//script[@id="__NEXT_DATA__"]/text()').get()
5data = json.loads(raw)
6product = data["props"]["pageProps"]["initialData"]["data"]["product"]
7idml = data["props"]["pageProps"]["initialData"]["data"].get("idml", {})
大多数教程写到这里就停了。下面是一个 完整的 JSON 路径对照表,对应你真正关心的字段——已基于 2024–2026 年的 Walmart 页面验证:
| 数据字段 | JSON 路径(在 initialData 下) | 类型 | 说明 |
|---|---|---|---|
| 商品名称 | data > product > name | 字符串 | — |
| 品牌 | data > product > brand | 字符串 | — |
| 当前价格(数值) | data > product > priceInfo > currentPrice > price | 浮点数 | 可能因门店 cookie 不同而变化 |
| 当前价格(字符串) | data > product > priceInfo > currentPrice > priceString | 字符串 | 格式化结果,例如 "$9.99" |
| 简短描述 | data > product > shortDescription | HTML 字符串 | 可用 BeautifulSoup 转成纯文本 |
| 长描述 | data > idml > longDescription | HTML 字符串 | 在 idml 上,不在 product 里——很多旧教程都会写错这里 |
| 全部图片 | data > product > imageInfo > allImages | 数组 | {id, url} 对象列表 |
| 平均评分 | data > product > averageRating | 浮点数 | 键名是 averageRating,不是旧版的 rating |
| 评论数 | data > product > numberOfReviews | 整数 | — |
| 变体 | data > product > variantCriteria | 数组 | 选项组(尺寸、颜色) |
| 可用性 | data > product > availabilityStatus | 字符串 | IN_STOCK、OUT_OF_STOCK、LIMITED_STOCK |
| 卖家 | data > product > sellerDisplayName | 字符串 | — |
| 制造商 | data > product > manufacturerName | 字符串 | — |
longDescription 这条路径最容易踩坑。2023 年的 ScrapeHero 文章把它写在 product.longDescription,但 2024 年之后的资料基本都显示它在兄弟键 idml 里。务必先读 idml.longDescription,再在旧页面上回退到 product.longDescription。
下面是使用 .get() 链式写法的安全提取模式:
1def extract_product(data):
2 product = data["props"]["pageProps"]["initialData"]["data"]["product"]
3 idml = data["props"]["pageProps"]["initialData"]["data"].get("idml", {})
4 price_info = product.get("priceInfo", {})
5 current_price = price_info.get("currentPrice", {})
6 image_info = product.get("imageInfo", {})
7 return {
8 "name": product.get("name"),
9 "brand": product.get("brand"),
10 "price": current_price.get("price"),
11 "price_string": current_price.get("priceString"),
12 "short_desc": product.get("shortDescription"),
13 "long_desc": idml.get("longDescription", product.get("longDescription")),
14 "images": [img.get("url") for img in image_info.get("allImages", [])],
15 "rating": product.get("averageRating"),
16 "review_count": product.get("numberOfReviews"),
17 "variants": product.get("variantCriteria"),
18 "availability": product.get("availabilityStatus"),
19 "seller": product.get("sellerDisplayName"),
20 "manufacturer": product.get("manufacturerName"),
21 }
如果你不想自己处理 JSON 路径, 会自动识别并结构化这些字段——你不需要手工映射路径。点击“AI Suggest Fields”,它会读取页面并输出表格。但如果你是在搭建自定义管线,上面的映射表就是你的参考。
第 3 步:拦截 Walmart 的内部 API,拿到更丰富的数据
没有一篇竞品文章把这部分讲清楚。它是最强的提取方式,也是最复杂的一种。
Walmart 前端调用的是基于 Apollo Gateway 的 。接口都挂在 www.walmart.com/orchestra/* 下面:
/orchestra/pdp/graphql— 商品详情 hydration + 变体切换/orchestra/snb/graphql— 搜索与浏览分页/orchestra/reviews/graphql— 分页评论
这些接口会返回干净、结构化的 JSON,其中有些数据是 __NEXT_DATA__ 会截断的——例如变体级价格、实时库存数量、完整的评论分页。
但这里有个很多博客都绕过去的坑: Walmart 使用的是 。请求体里只发送 SHA-256 hash(persistedQuery.sha256Hash),而不是完整查询文本。如果这个 hash 服务器不认识,你就会收到 PersistedQueryNotFound。Walmart 每次部署都会轮换这些 hash。这也是为什么那些高知名度的开源 Walmart 爬虫,几乎都不会直接发布可复制粘贴的 /orchestra/ 代码。
这个方法最现实的做法,是在 DevTools 里手动抓一遍:
- 在 Chrome 中打开一个 Walmart 商品页
- 打开 DevTools → Network 标签,筛选 “Fetch/XHR”
- 像正常用户一样浏览页面——点变体、滚动到评论、切换门店
- 找到返回商品数据的
/orchestra/*请求 - 右键请求 → “Copy as cURL”
- 用
curl_cffi把 cURL 命令转换成 Python
下面是重放 API 请求的示例:
1import json
2from curl_cffi import requests
3session = requests.Session(impersonate="chrome124")
4# 先访问商品页,给会话预热
5session.get("https://www.walmart.com/ip/some-product/1234567", headers=HEADERS)
6# 然后重放内部 API 请求(从 DevTools 复制)
7api_url = "https://www.walmart.com/orchestra/pdp/graphql"
8api_headers = {
9 **HEADERS,
10 "accept": "application/json",
11 "content-type": "application/json",
12 "referer": "https://www.walmart.com/ip/some-product/1234567",
13 "wm_qos.correlation_id": "your-copied-correlation-id",
14}
15payload = {
16 # 把 DevTools 里的原始请求体粘贴进来
17 "variables": {"productId": "1234567"},
18 "extensions": {
19 "persistedQuery": {
20 "version": 1,
21 "sha256Hash": "the-hash-you-copied"
22 }
23 }
24}
25api_response = session.post(api_url, headers=api_headers, json=payload)
26api_data = api_response.json()
会话预热这一步非常关键。Walmart 的 PerimeterX cookie(_px3、_pxhd、ACID)必须先由初始 HTML 请求写入,后面的 API 才能成功调用。没有这些 cookie,你通常会收到 412 或 403。
什么时候适合用这个方法: 当你需要 __NEXT_DATA__ 里没有的数据时,比如更深层的变体价格、超过第一页的分页评论,或者实时库存数。对大多数用途来说,__NEXT_DATA__ 已经足够,而且简单得多。
抓取 Walmart 搜索结果和多页内容
搜索结果也遵循类似的 __NEXT_DATA__ 结构,只是 JSON 路径不同:
1search_url = "https://www.walmart.com/search?q=laptops&page=1"
2response = session.get(search_url, headers=HEADERS)
3sel = Selector(text=response.text)
4raw = sel.xpath('//script[@id="__NEXT_DATA__"]/text()').get()
5data = json.loads(raw)
6search_result = data["props"]["pageProps"]["initialData"]["searchResult"]
7items = search_result["itemStacks"][0]["items"]
8# 过滤掉赞助商品
9organic_items = [i for i in items if i.get("__typename") == "Product"]
10for item in organic_items:
11 print(item.get("name"), item.get("priceInfo", {}).get("currentPrice", {}).get("price"))
分页通过递增 page 参数实现:&page=1、&page=2,以此类推。但有个没有公开写明的限制:无论实际总页数是多少,Walmart 都把搜索结果最多限制为 25 页。 :“Walmart 设置了可访问结果页的最大数量为 25 页,不管总页数有多少。”
想拿到更深的覆盖范围,可以试这些办法:
- 切换排序方式:同一个查询分别加
&sort=price_low和&sort=price_high,大约能拿到 50 页覆盖 - 按价格区间切片:加上
&min_price=X&max_price=Y,把目录切成更小的窗口 - 按类目切片:在具体类目里搜索,而不是全站搜索
注意 itemStacks 是数组。Scrapfly 在仓库里直接硬编码了 [0],但类目页和浏览页有时会出现多个 stack(比如“热门推荐”“更多结果”)。更稳妥的做法是遍历所有 stack:
1for stack in search_result.get("itemStacks", []):
2 for item in stack.get("items", []):
3 if item.get("__typename") == "Product":
4 # 处理 item
5 pass
还有一点值得注意:Walmart 的 robots.txt 。商品详情页(/ip/...)和大多数类目页(/cp/...)并没有被禁止。如果你比较在意合规性,建议优先从商品页和类目树开始,而不是搜索页。
不要让静默封锁毁掉你的数据:生产级错误处理
大多数教程都会在这里翻车。它们只教你抓一页、解析一个商品、然后就结束了。但在生产环境里,你会抓成千上万的页面,而 Walmart 也一直在想办法拦你。一个 demo 爬虫和一个真正能用的爬虫,差别就在于你怎么处理失败。
在数据被污染前识别静默封锁
Walmart 爬虫里最重要的函数,就是封锁检测器。根据 、、 和 的一致经验,你需要四个独立检查:
1BLOCK_MARKERS = (
2 "Robot or human",
3 "Press & Hold",
4 "Press & Hold",
5 "px-captcha",
6 "perimeterx",
7)
8def is_walmart_blocked(response) -> bool:
9 # 1. 重定向到专门的封锁页面
10 if "/blocked" in str(response.url):
11 return True
12 # 2. 明确的状态码
13 if response.status_code in (403, 412, 428, 429, 503):
14 return True
15 # 3. 200 OK 但正文是 CAPTCHA(静默封锁)
16 body = response.text or ""
17 if any(m.lower() in body.lower() for m in BLOCK_MARKERS):
18 return True
19 # 4. 响应长度检查——真实 PDP 通常是 300–900 KB
20 if len(response.content) < 50_000 and "/ip/" in str(response.url):
21 return True
22 return False
第四个检查——响应长度——可以抓住那些没有明显 CAPTCHA 标记,但也没有任何商品数据的“简化页面”。
带指数退避和抖动的重试逻辑
请求失败时,别马上猛刷 Walmart。标准做法是指数退避加抖动,避免重试节奏完全同步:
1import time
2import random
3import logging
4from curl_cffi import requests as cffi_requests
5log = logging.getLogger("walmart")
6def fetch_with_retry(session, url, max_retries=5, base_delay=2, max_delay=60):
7 for attempt in range(max_retries):
8 try:
9 response = session.get(url, headers=HEADERS, timeout=15)
10 if response.status_code in (429, 503):
11 raise Exception(f"Throttled: {response.status_code}")
12 if is_walmart_blocked(response):
13 raise Exception("Silent block detected")
14 return response
15 except Exception as e:
16 if attempt == max_retries - 1:
17 raise
18 wait = min(max_delay, base_delay * (2 ** attempt)) + random.uniform(0, 3)
19 log.warning(f"Attempt {attempt + 1} failed: {e}. Retrying in {wait:.1f}s")
20 time.sleep(wait)
21 return None
这里的抖动(random.uniform(0, 3))不是装饰,它能让多个爬虫实例不会在同一秒同时重试,从而触发 Akamai 的速度检测。
速率限制
和 都建议 Walmart 采用 每次请求随机等待 3–6 秒:“把页面加载间隔控制在 3–6 秒之间,并且随机化延迟。”
1import time
2import random
3def rate_limited_fetch(session, url):
4 response = fetch_with_retry(session, url)
5 time.sleep(random.uniform(3.0, 6.0))
6 return response
如果规模更大,可以用 aiolimiter 做异步限速:
1from aiolimiter import AsyncLimiter
2limiter = AsyncLimiter(max_rate=10, time_period=60) # 每分钟 10 个请求
数据验证
即使响应没有被封,解析出来的数据也可能是错的(门店不对、负载被降级)。在写入输出前先做校验:
1def validate_product(product):
2 """如果商品数据看起来合理,则返回 True。"""
3 if not product.get("name"):
4 return False
5 price = (product.get("priceInfo") or {}).get("currentPrice", {}).get("price")
6 if not isinstance(price, (int, float)) or price <= 0:
7 return False
8 if product.get("availabilityStatus") not in ("IN_STOCK", "OUT_OF_STOCK", "LIMITED_STOCK"):
9 return False
10 return True
会话日志记录
跟踪每个会话的成功率。当 10 分钟内成功率跌到 80% 以下时,说明情况变了——可能是 IP 被封了、cookie 过期了,或者 Walmart 上了新的反爬规则。
1class ScrapeMetrics:
2 def __init__(self):
3 self.total = 0
4 self.success = 0
5 self.blocks = 0
6 self.errors = 0
7 def record(self, result):
8 self.total += 1
9 if result == "success":
10 self.success += 1
11 elif result == "blocked":
12 self.blocks += 1
13 else:
14 self.errors += 1
15 @property
16 def success_rate(self):
17 return (self.success / self.total * 100) if self.total > 0 else 0
18 def check_health(self):
19 if self.total > 20 and self.success_rate < 80:
20 log.critical(f"Success rate dropped to {self.success_rate:.1f}% — consider rotating proxies or pausing")
不花哨,但它能保证你的数据干净。
自己写 Python vs. 抓取 API vs. 无代码:如何选择抓取 Walmart 的方式
很多开发者一上来就想自己写爬虫,却没先判断这是不是最合适的方案。。论坛用户也常说它“基本就是 9/10”,并纠结“专门买一个网页抓取 API 会不会太重了”。答案取决于抓取量、预算和工程能力。
| 因素 | 自建 Python(requests + 代理) | 抓取 API(Oxylabs、Bright Data 等) | 无代码工具 (Thunderbit) |
|---|---|---|---|
| 初次出数据的配置时间 | 几小时 | 15–60 分钟 | 约 2 分钟 |
| 上线到可生产使用 | 40–80 小时 | 4–16 小时 | 约 30 分钟 |
| 反爬处理 | 你自己负责(很难) | 服务商负责 | 自动处理 |
| 小规模成本(<1K 页/月) | 低(代理约 $4–8/GB) | $40–$49/月起 | 免费–$15/月 |
| 大规模成本(10 万+ 页/月) | 单次成本更低 | 单次成本更高 | 视情况而定 |
| 定制能力 | 完全可控 | 受 API 参数限制 | 受 UI/字段限制 |
| 持续维护 | 每月 4–8 小时 | 几乎为零 | 无需维护(AI 自适应) |
| 最适合 | 需要自定义管线的开发者 | 中等规模生产抓取 | 商业用户、临时快速提取 |
什么时候适合自己写 Python
如果你已经有代理合同、需要严格控制请求头、邮编定位或卖家群组,或者你每月要索引数百万页面、API 单条费用累积起来很高,又或者你需要本地部署或合规保证,那么自建方案更划算。代价也很现实:一个可投入生产的 Scrapy 爬虫,支持分页、重试、代理轮换、TLS 模拟和多页面类型 schema,通常需要 ,之后每月还要花 4–8 小时维护,因为 Walmart 会不断轮换指纹。
什么时候抓取 API 更省时间
抓取 API 会帮你处理反爬层,这样你就不用自己折腾了。 显示 Walmart 上 ,而 Scrape.do 成功率 98%。像 、 和 这样的工具,入门价大概在每月 $40–$49。若你是 2–5 人的小团队,每月抓取量在 1 万到 100 万页之间,API 基本上总是更合适。你用每次请求的费用,换来几乎零维护。
什么时候无代码才是正确答案
适合完全不同的人群。如果你是 PM、分析师或电商运营,希望今天下午就把 Walmart 数据放进表格里,而不是等到下个迭代,那无代码工具就是最诚实的答案。
流程很简单:安装 ,打开 Walmart 商品页或搜索页,点击“AI Suggest Fields”,Thunderbit 的 AI 会读取页面并推荐字段列(商品名、价格、评分等)。再点“Scrape”,数据就会进入表格。然后可以免费导出到 Excel、Google Sheets、Airtable 或 Notion。
Thunderbit 把反爬处理放在云端,所以你不需要面对 CAPTCHA、代理和 TLS 指纹这些麻烦。AI 也会自动适应页面布局变化,因此几乎不需要维护。对于不想碰 JSON 路径的人来说,这基本就是阻力最小的路径。
但也要诚实地说限制:Thunderbit 不是为每天 10 万+ 页面设计的。积分预算和云端上限会让超大规模采集的成本高于原生 API。你也无法在工具不支持的情况下固定某个邮编或 ASN。对于持续、超高频的数据管道,DIY 或抓取 API 仍然更合适。
粗略价格估算: 在 Thunderbit 上抓取 1000 条 Walmart 商品数据,大约消耗 2000 积分(Starter/Pro 方案约 $0.60–$1.10)。这和 Oxylabs 的 Walmart API 差不多,在低量场景下还比大多数入门级抓取 API 更便宜。具体价格请查看 。
导出你抓取到的 Walmart 数据
拿到数据后,你得把它放到真正能用的地方。下面三种格式已经能覆盖大多数需求:
CSV —— 分析师最常打开的通用格式:
1import csv
2def export_csv(products, filename="walmart_products.csv"):
3 fieldnames = ["name", "price", "availability", "rating", "review_count", "seller", "url"]
4 with open(filename, "w", newline="", encoding="utf-8-sig") as f:
5 writer = csv.DictWriter(f, fieldnames=fieldnames, quoting=csv.QUOTE_MINIMAL)
6 writer.writeheader()
7 for p in products:
8 writer.writerow({k: p.get(k) for k in fieldnames})
这里使用 utf-8-sig 编码是为了兼容 Excel。BOM 标记可以避免 Excel 把特殊字符弄乱。
JSONL —— 适合生产级抓取管线的格式:
1import json
2import gzip
3def export_jsonl(products, filename="walmart_products.jsonl.gz"):
4 with gzip.open(filename, "at", encoding="utf-8") as f:
5 for p in products:
6 f.write(json.dumps(p, ensure_ascii=False) + "\n")
(中断写入通常只丢最后一行),可以流式写入、常量内存运行,并保留变体、评论这类嵌套数据。
Excel —— 适合一次性给分析师交接:
1from openpyxl import Workbook
2def export_excel(products, filename="walmart_products.xlsx"):
3 wb = Workbook(write_only=True)
4 ws = wb.create_sheet("Products")
5 ws.append(["Name", "Price", "Availability", "Rating", "Reviews", "Seller"])
6 for p in products:
7 ws.append([p.get("name"), p.get("price"), p.get("availability"),
8 p.get("rating"), p.get("review_count"), p.get("seller")])
9 wb.save(filename)
对于非 Python 用户,Thunderbit 也覆盖了导出:一键导出到 Google Sheets、Airtable、Notion、Excel、CSV 和 JSON——基础版全部免费。对于持续监控,Thunderbit 的定时爬虫功能还能自动执行重复抓取。
关于定时抓取还有一个注意事项:。GitHub Actions 的运行器使用的是 Azure IP 段,而 Walmart 的反爬会直接封掉这些 IP。建议在 VPS 上用 APScheduler,或者把所有流量都走住宅代理。
抓取 Walmart 的法律与伦理指南
论坛用户会很直接地表达这种担忧:“我不介意和工程团队玩猫鼠游戏,但我不想和他们的法务团队过招。”
Walmart 的使用条款 在没有“事先书面同意”的情况下,使用“任何机器人、蜘蛛……或其他手动或自动设备来检索、索引、‘scrape’、‘data mine’ 或以其他方式收集任何材料”。
Walmart 的 robots.txt /search、/account、/api/ 以及大量内部接口。但商品详情页(/ip/...)和评论页(/reviews/product/)并未被禁止。
hiQ v. LinkedIn 判例(第九巡回法院,)确立了一个原则:抓取公开可访问的数据,通常不太可能违反联邦 CFAA。不过,同一法院后来又裁定 ,并对其作出 。更近的 2024 年判决(、)进一步缩小了 CFAA 的适用范围,并带来了版权优先适用抗辩;但这些裁定依赖于特定的 ToU 文本,不能直接照搬到 Walmart 上。
实用建议: 不要压垮服务器。尊重速率限制。不要抓取个人数据或用户数据。负责任地使用数据。以适中的速率抓取公开 Walmart 商品页用于个人研究,和以商业规模抓取并违反 Walmart 条款,是两种完全不同的风险画像。如果你打算基于 Walmart 数据做产品,最好先咨询律师,并看看 Walmart 官方的 。
免责声明: 以上内容仅用于教育目的,不构成法律建议。
结论与核心要点
由于 Walmart 同时使用 Akamai + PerimeterX 双层反爬,使用 Python 抓取它是一个 。不是不可能,但你必须使用正确的工具和方法。
核心要点:
__NEXT_DATA__JSON 提取是大多数场景下最务实的方案。 这也是 2024–2026 年几乎所有严肃开源 Walmart 爬虫的做法。PDP 的基础路径是props.pageProps.initialData.data.product,搜索/浏览页则是searchResult.itemStacks。curl_cffi配合impersonate="chrome124"是必须的。 仅靠requests或httpx,无论怎么改请求头,都过不了 Akamai 的 TLS 指纹识别。- 静默封锁才是真正危险的地方。 Walmart 会返回带 CAPTCHA 内容的 200 OK。要检查响应正文,不要只看状态码。
- 生产级爬虫需要的不只是 happy path 代码。 指数退避加抖动、四信号封锁检测、每次请求 3–6 秒速率限制、数据验证和会话健康监控,都是必需的。
- 通过
/orchestra/*拦截内部 API 很强,但也很脆弱。 把它当成针对特定数据需求的 DevTools 练习,而不是主提取方式。 - Walmart 把搜索结果限制在 25 页。 想拿更多覆盖,可以通过切换排序和按价格区间切片来扩大范围。
- 诚实选择适合自己的方案: 如果你是开发者、需要定制流程、而且量大,就用 DIY Python;如果你是中等规模团队、又没有专门的抓取工程师,就用抓取 API;如果你是想今天下午就把数据放进 Google Sheets 的业务人员,就用 。
如果你想试试无代码路线, 有免费额度——你可以先抓几页 Walmart 数据,亲眼看看结果。如果你决定走 Python 路线,这篇文章里的代码模式已经在生产环境里验证过了。无论哪条路,现在你都已经掌握了 Walmart 的防线图,以及穿过它们的三种方式。
想了解更多网页抓取技巧,可以查看我们关于 、 和 的指南。你也可以在 看教程。
常见问题
用 Python 抓取 Walmart 商品数据合法吗?
Walmart 的使用条款禁止在未经书面同意的情况下进行自动抓取。第九巡回法院在 hiQ v. LinkedIn(2022)一案中判定,联邦 CFAA 很可能不适用于抓取公开页面,但同案最终还是以抓取方违反合同并被判赔 收场。以较低频率抓取公开商品页用于个人研究,和商业规模抓取,风险画像完全不同。如果你打算围绕 Walmart 数据做生意,务必先咨询律师。
为什么我的 Walmart 爬虫总是被封?
最常见的原因有:使用普通 requests 或 httpx(它们会发出 Python 特征的 TLS 指纹,Akamai 会立刻识别)、请求头缺失或错误、没有代理轮换、请求速度快于每页 3–6 秒,以及缺少会话 cookie(_px3、_abck、locDataV3)。请改用带 impersonate="chrome124" 的 curl_cffi,使用住宅代理,并按本文所述实现封锁检测和重试逻辑。
用 Python 可以从 Walmart 抓到哪些数据?
商品名称、价格(当前价和回滚价)、图片、简短和长描述、评分、评论数、库存状态、卖家名称、制造商信息、变体选项(尺寸、颜色)以及类目归属。使用 __NEXT_DATA__ 方法时,这些数据都以结构化 JSON 形式提供。内部 API 拦截还能额外拿到变体级价格、实时库存数量和分页评论数据。
抓取 Walmart 需要代理吗?
需要,凡是生产环境或重复使用都需要。——即使请求头完全正确,非住宅 IP 也会被 Akamai 的 IP 信誉系统标记。住宅代理或移动代理是必须的。数据中心 IP 几乎会立刻失效。按代理服务商和套餐不同,每 1000 页大约预算 $3–$17。
不写代码也能抓 Walmart 吗?
可以。 是一款 AI 驱动的 Chrome 扩展,只需两步就能抓 Walmart:“AI Suggest Fields” 自动识别商品数据列,然后点“Scrape”导出数据。它会在云端处理反爬挑战,并可直接导出到 Excel、Google Sheets、Airtable 或 Notion,而且全部免费。它最适合分析师、PM 和需要快速拿数据的业务人员,不需要自己搭建自定义管线。若是高频或高度定制化抓取,Python 或抓取 API 仍然更合适。
了解更多