Shopify 的 /products.json 接口可以说是电商数据圈里公开的“秘密武器”。只要把它追加到任意 Shopify 店铺网址后面,就能直接拿到结构化 JSON 数据——不需要 API 密钥,不需要身份验证,也不用钻进层层嵌套的 HTML 里慢慢扒。
我在 团队工作,平时花很多时间思考大家是如何从网页中提取数据的。Shopify 抓取这个话题更是经常被提起:销售团队想追踪竞品价格,电商运营想对比商品目录,采购人员想寻找新供应商。Shopify 目前有 ,并占据美国电商市场大约 ,因此可抓取的商品数据规模非常可观。
这篇指南会完整讲清楚整个流程:接口会返回什么、如何分页抓取上千个商品、如何在不被封的前提下处理速率限制,以及如何用 pandas 把 Shopify 的嵌套 JSON 整理成干净的 CSV 或 Excel 文件。我还会补充其他很少有人提到的接口(/collections.json、/meta.json),并给出一个不写代码也能用的替代方案,适合那些想直接跳过 Python 的人。
Shopify 的 /products.json 接口是什么?为什么它让抓取变得这么简单?
每个 Shopify 店铺都有一个公开接口:{store-url}/products.json,它会返回结构化的商品数据。没有 API key,没有 OAuth,也不需要任何身份认证。你只要在店铺网址后面加上 /products.json,就能拿到整个商品目录的 JSON 数组。
你现在就可以自己试试:在浏览器里打开 或 。你会看到整洁、结构清晰的 JSON,里面包含商品标题、价格、规格、图片、标签等所有信息。
再对比一下另一种做法:解析 Shopify 的 HTML 主题页面。这些页面通常嵌套很深,不同店铺结构也不一致,而且商家一旦更新主题,你的解析逻辑就可能失效。你要面对的大概会是下面这种情况:
HTML 方式(很折腾):
1<div class="product-card__info">
2 <h3 class="product-card__title">
3 <a href="/products/classic-blue-jeans">Classic Blue Jeans</a>
4 </h3>
5 <span class="price price--on-sale" data-product-price>$149.00</span>
6</div>
JSON 方式(清爽直接):
1{
2 "title": "Classic Blue Jeans",
3 "handle": "classic-blue-jeans",
4 "vendor": "Hiut Denim",
5 "variants": [{"price": "149.00", "sku": "HD-BLU-32", "available": true}]
6}
在一致性、稳定性和解析难度上,JSON 都明显更占优势。这个接口还支持两个关键参数——?limit=(每页最多 250 个商品,默认 30)和用于分页的 ?page=——后面的代码会频繁用到它们。
这里要特别区分一下:这属于公开的店铺前台接口,不是 。Admin API 需要店主访问令牌,可以返回订单数据、库存水平和客户信息。而公开的 /products.json 只能读取商品数据,任何人都能访问。后面我会详细说明这两者的区别,因为网上很多人会把它们混为一谈。
需要注意的一点:并不是所有 Shopify 店铺都会开放这个接口。根据我的测试,大约 71% 的店铺会返回有效 JSON(例如 allbirds.com、gymshark.com、colourpop.com、kyliecosmetics.com 都可以),但有些自定义配置的店铺会返回 404(比如 hiutdenim.co.uk、bombas.com)。最简单的检查方式就是:直接在浏览器里访问 {store-url}/products.json 看看结果。
为什么要用 Python 抓取 Shopify?最常见的业务场景有哪些?
为什么值得做?因为 ROI 很高。 现在都在用自动化价格抓取做竞品分析,而 2020 年这个比例还只有 34%。研究还显示,价格策略只要提升 。这些数据是真的值钱。
下面是我最常见到的使用场景:
| 使用场景 | 受益对象 | 可获得的数据 |
|---|---|---|
| 竞品价格监控 | 电商运营团队 | 跟踪竞品目录中的价格变化、折扣和原价对比 |
| 商品研究与采购 | 采购 / 商品团队 | 对比商品特性、规格、材质和可售情况 |
| 线索挖掘 | 销售团队 | 从店铺目录中提取供应商名称、品牌信息和联系方式 |
| 市场与品类分析 | 营销团队 | 分析商品组合、标签、集合结构和定位方式 |
| 库存与可售状态追踪 | 供应链团队 | 持续监控规格层级的库存状态(available: true/false) |
| 新品识别 | 产品团队 | 跟踪 created_at 时间戳,发现竞品新品上架 |
Python 是这类工作的天然选择。 把 Python 作为主力语言,而它的生态也非常成熟——requests 负责 HTTP 请求,pandas 负责数据处理,httpx 适合异步调用——让你可以在不到 80 行代码里,从“我有一个网址”快速走到“我有一个表格”。
完整的 products.json 字段说明:每个字段都讲清楚
很多教程只会展示 title、id 和 handle,然后就草草结束。但 Shopify 的 JSON 响应里,商品、规格、图片和选项加起来其实有 40 多个字段。写抓取代码前先知道有哪些字段,能帮你避免后面返工重抓。
这份参考表来自我在 2026 年 4 月 16 日抓取的真实 /products.json 响应。只要店铺开放了这个接口,结构基本都是一致的。
商品层级字段
| 字段 | 数据类型 | 示例值 | 业务用途 |
|---|---|---|---|
id | 整数 | 123456789 | 商品唯一 ID,用于去重 |
title | 字符串 | "Classic Blue Jeans" | 商品名称,用于目录和对比 |
handle | 字符串 | "classic-blue-jeans" | URL 标识,可拼出商品页链接:{store}/products/{handle} |
body_html | 字符串(HTML)或 null | Our best-selling... | 商品描述,用于内容分析和 SEO 研究 |
vendor | 字符串 | "Hiut Denim" | 品牌/供应商名称,用于线索挖掘或采购 |
product_type | 字符串 | "Jeans" | 品类分类,用于市场分析 |
created_at | ISO 日期时间 | "2024-01-15T10:30:00-05:00" | 跟踪商品何时上架(识别新品) |
updated_at | ISO 日期时间 | "2025-03-01T08:00:00-05:00" | 发现目录最近是否有变动 |
published_at | ISO 日期时间 | "2024-01-16T00:00:00-05:00" | 判断商品何时在前台正式展示 |
tags | 字符串数组 | ["organic", "women", "straight-leg"] | 关键词 / 标签分析,用于 SEO、分类和趋势判断 |
variants | 对象数组 | (见下方规格字段) | 每个规格对应的价格、SKU 和可售状态 |
images | 对象数组 | (见下方图片字段) | 商品图片链接,用于目录和视觉分析 |
options | 对象数组 | [{"name": "Size", "values": ["S","M","L"]}] | 了解商品配置方式(尺码、颜色、材质) |
规格层级字段(嵌套在每个商品下)
| 字段 | 数据类型 | 示例 | 用途 |
|---|---|---|---|
id | 整数 | 987654321 | 规格唯一 ID |
title | 字符串 | "32 / Blue" | 规格显示名称 |
sku | 字符串 | "HD-BLU-32" | 用于库存系统匹配 SKU |
price | 字符串 | "185.00" | 价格监控(注意:这是字符串,做计算前要转成浮点数) |
compare_at_price | 字符串或 null | "200.00" | 原价——做折扣追踪时很重要 |
available | 布尔值 | true | 库存可售状态(公开接口里唯一能看到的库存指标) |
weight | 浮点数 | 1.2 | 物流 / 运费分析 |
option1, option2, option3 | 字符串 | "32", "Blue", null | 各个选项值 |
created_at, updated_at | ISO 日期时间 | — | 规格层级的变动追踪 |
图片层级字段
| 字段 | 数据类型 | 示例 | 用途 |
|---|---|---|---|
id | 整数 | 111222333 | 图片唯一 ID |
src | 字符串(URL) | "https://cdn.shopify.com/..." | 直接下载图片的链接 |
alt | 字符串或 null | "Front view of jeans" | 图片替代文本,可用于无障碍分析 |
position | 整数 | 1 | 图片排序 |
width, height | 整数 | 2048, 2048 | 图片尺寸 |
公开接口里没有什么字段?
有一个非常重要的坑:公开的 /products.json 响应里没有 inventory_quantity。 这个字段早在 2017 年 12 月就从对外公开的 JSON 接口里移除了,原因是安全考虑。你能拿到的唯一库存指示就是每个规格上的布尔字段 available(true 或 false)。如果你想获取真实库存数量,就必须使用带认证的 Admin API,并且要有店主凭证。
在开始写抓取代码前,先看这张表,确定哪些字段对你的场景最重要。如果你是做价格监控,就需要 variants[].price、variants[].compare_at_price 和 variants[].available。如果你是做线索挖掘,那就重点关注 vendor、product_type 和 tags。按需过滤,你导出的 CSV 会干净很多。
不止 products.json:Collections、Meta 和其他 Shopify 接口
很多教程都不会讲这些接口,但如果你要做更严肃的竞品分析,它们其实非常关键。
/collections.json —— 店铺全部分类
它会返回店铺里的所有集合(分类),包含标题、handle、描述和商品数量。我在 zoologistperfumes.com、allbirds.com 和 gymshark.com 上都验证过,它们都能返回有效 JSON。
1{
2 "collections": [
3 {
4 "id": 308387348539,
5 "title": "Attars",
6 "handle": "attars",
7 "published_at": "2026-03-29T12:20:32-04:00",
8 "products_count": 1,
9 "image": { "src": "https://cdn.shopify.com/..." }
10 }
11 ]
12}
想了解竞品是怎么组织商品目录的?这个接口最直接。
/collections/{handle}/products.json —— 按分类获取商品
这个接口会返回某个具体集合下的商品,JSON 结构和 /products.json 一样,但范围只限于一个分类。它非常适合做分类级抓取——比如你只想监控竞品的“Sale”或“New Arrivals”分类。
/meta.json —— 店铺级元数据
它会返回店铺名称、描述、货币、国家,以及最有用的 published_products_count。这个数量可以让你提前算出需要多少分页:ceil(published_products_count / 250)。不用再盲目翻页,直到碰到空响应为止。
应该用哪个接口?
| 你想要什么 | 接口 | 需要认证吗? |
|---|---|---|
| 所有商品(公开) | /products.json | 否 |
| 某个分类下的商品 | /collections/{handle}/products.json | 否 |
| 店铺元数据 + 商品数量 | /meta.json | 否 |
| 所有分类(集合) | /collections.json | 否 |
| 订单 / 销售数据(仅限自有店铺) | Admin API /orders.json | 是(API key) |
| 库存数量(仅限自有店铺) | Admin API /inventory_levels.json | 是 |
论坛里反复出现的问题——“我能抓取竞品卖了多少件吗?”——答案很短:不能。至少不能从公开接口拿到。销售数据和库存数量都需要认证后的 Admin API,也就是你必须拥有店主访问权限。公开接口只提供商品目录数据。

如何用 Python 抓取 Shopify:一步一步搭建
- 难度:初级
- 预计时间:约 15 分钟(环境安装 + 完成第一次抓取)
- 你需要准备:Python 3.11+、
pip、终端,以及一个要抓取的 Shopify 店铺网址
第 1 步:安装 Python 和所需库
先确认你已经安装了 Python 3.11 或更高版本(pandas 3.0.x 需要它)。然后安装我们要用的两个库:
1pip install requests pandas
如果还要导出 Excel,再装一个:
1pip install openpyxl
在脚本开头添加这些导入:
1import requests
2import pandas as pd
3import time
4import random
5import json
运行脚本时不应该出现任何导入错误。如果 pandas 报版本问题,升级到 Python 3.12。
第 2 步:从 /products.json 获取商品数据
下面是一个基础函数:传入店铺网址,调用接口,并返回解析后的 JSON 数据。
1def fetch_products_page(store_url, page=1, limit=250):
2 """从 Shopify 店铺抓取某一页商品数据。"""
3 url = f"{store_url.rstrip('/')}/products.json"
4 params = {"limit": limit, "page": page}
5 headers = {
6 "User-Agent": "Mozilla/5.0 (compatible; ProductResearch/1.0)"
7 }
8 response = requests.get(url, params=params, headers=headers, timeout=30)
9 response.raise_for_status()
10 return response.json().get("products", [])
几个关键点:
limit=250是 Shopify 允许的每页最大值。默认是 30,所以显式设置后,所需请求次数最多能减少 8 倍。User-Agent头:一定要设置成看起来真实的值。没有 User-Agent 的请求更容易触发 Shopify 的反爬系统。timeout=30:别让单个请求无限卡住。
用一个已知店铺测试一下:
1products = fetch_products_page("https://allbirds.com")
2print(f"Fetched {len(products)} products")
3print(f"First product: {products[0]['title']}")
你应该会看到类似这样的结果:Fetched 250 products,以及第一个商品标题。
第 3 步:处理分页,抓取全部商品
一次请求最多只能拿到 250 个商品。大多数店铺都不止这个数量(Allbirds 就有 1,420+)。所以你需要循环翻页,直到返回空结果为止。
1def scrape_all_products(store_url, delay=1.0):
2 """抓取 Shopify 店铺的全部商品,自动处理分页。"""
3 all_products = []
4 page = 1
5 while True:
6 print(f"Fetching page {page}...")
7 products = fetch_products_page(store_url, page=page, limit=250)
8 if not products:
9 print(f"No more products. Total: {len(all_products)}")
10 break
11 all_products.extend(products)
12 print(f" Got {len(products)} products (total so far: {len(all_products)})")
13 page += 1
14 # 温和一点:每次请求之间稍微停一下
15 time.sleep(delay + random.uniform(0, 0.5))
16 return all_products
当 products 变成空列表时,就说明已经到最后一页了。
time.sleep() 再加一点随机抖动,可以帮助你把请求频率控制在 Shopify 非正式的速率限制范围内(大约每秒 2 次请求)。
进阶提示:如果你先调用 /meta.json,就已经知道总商品数了,可以直接算出需要多少页:pages = ceil(product_count / 250)。这样就不用在最后多发一次“空请求”了。
第 4 步:解析并筛选你需要的字段
拿到所有商品的 Python 字典列表后,就可以提取你真正关心的字段了。下面这个示例会提取做价格监控最常用的一组字段:
1def extract_product_data(products):
2 """提取商品关键字段,并把 variants 展平。"""
3 rows = []
4 for product in products:
5 for variant in product.get("variants", []):
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "handle": product["handle"],
10 "vendor": product.get("vendor", ""),
11 "product_type": product.get("product_type", ""),
12 "tags": ", ".join(product.get("tags", [])),
13 "created_at": product.get("created_at", ""),
14 "variant_id": variant["id"],
15 "variant_title": variant.get("title", ""),
16 "sku": variant.get("sku", ""),
17 "price": variant.get("price", ""),
18 "compare_at_price": variant.get("compare_at_price", ""),
19 "available": variant.get("available", ""),
20 "image_url": product["images"][0]["src"] if product.get("images") else ""
21 })
22 return rows
这会生成“一行对应一个规格”的数据结构,这种格式最适合做价格比较,因为像 “Classic Blue Jeans” 这种商品,可能会有 12 个规格(6 个尺码 × 2 种颜色),每个规格都有自己的价格和可售状态。
使用 pandas 把抓取到的 Shopify 数据导出为 CSV 和 Excel
其他很多 Shopify 抓取教程都会把原始 JSON 直接丢进文件里,然后就算完事了。对开发者来说还行,但对周五就要交表的电商分析师来说,这几乎没用。
问题在于:Shopify 的 JSON 是嵌套结构。一个商品里可能有十几个规格,每个规格都有自己的价格、SKU 和可售状态。要把它整理成标准的行列数据,就需要一些 pandas 处理。
把嵌套 JSON 展平成干净的表格
根据你的需求,通常有两种做法:
方案 A:每个规格一行(最适合价格监控和库存追踪)
1# 使用第 4 步中的 extract_product_data 函数
2products = scrape_all_products("https://allbirds.com")
3rows = extract_product_data(products)
4df = pd.DataFrame(rows)
5print(f"DataFrame shape: {df.shape}")
6print(df.head())
这样你会得到一个平坦的表格,每一行代表一个唯一的商品-规格组合。一个有 500 个商品、每个商品平均 4 个规格的店铺,最后大概会得到 2,000 行左右的 DataFrame。
方案 B:每个商品一行摘要(最适合做目录总览)
1def summarize_products(products):
2 """每个商品一行,统计各规格的最低 / 最高价。"""
3 rows = []
4 for product in products:
5 prices = [float(v["price"]) for v in product.get("variants", []) if v.get("price")]
6 rows.append({
7 "product_id": product["id"],
8 "title": product["title"],
9 "vendor": product.get("vendor", ""),
10 "product_type": product.get("product_type", ""),
11 "variant_count": len(product.get("variants", [])),
12 "min_price": min(prices) if prices else None,
13 "max_price": max(prices) if prices else None,
14 "any_available": any(v.get("available", False) for v in product.get("variants", [])),
15 "tags": ", ".join(product.get("tags", []))
16 })
17 return rows
导出为 CSV、Excel 和 Google Sheets
1# 导出 CSV(使用 utf-8-sig,方便 Excel 识别特殊字符)
2df.to_csv("shopify_products.csv", index=False, encoding="utf-8-sig")
3# 导出 Excel(需要 openpyxl)
4df.to_excel("shopify_products.xlsx", index=False, engine="openpyxl")
5print("Exported to shopify_products.csv and shopify_products.xlsx")
如果是 Google Sheets,可以用 gspread 加服务账号来写入。不过说实话,对大多数场景来说,先导出 CSV 再上传到 Google Drive,通常更快也更简单。
面向生产环境的 Python 抓取:速率限制、重试和防封策略
基础脚本抓小店铺问题不大。但如果你要抓 5,000+ 商品的店铺,或者连续抓多个店铺,就会开始出问题。
了解 Shopify 的速率限制和封禁机制
Shopify 的公开 JSON 接口没有像 Admin API 那样明确公开速率限制文档,但根据实际测试,可以观察到:
- 安全速度:每个店铺大约每秒 2 个请求
- 软上限:每分钟大约 40 个请求后,可能开始触发限流
- HTTP 429:"Too Many Requests",标准的限流响应
- HTTP 430:Shopify 特有的代码,表示安全级别封禁(不只是限流)
- HTTP 403 或 CAPTCHA 跳转:部分店铺叠加了 Cloudflare 防护
来自共享云环境的请求(例如 AWS Lambda、Google Cloud Run)尤其容易触发封禁,因为这些 IP 段的滥用率通常更高。
更可靠地抓取 Shopify 的方法
下面是从“我电脑上能跑”进化到“可以上生产”的路线:
| 级别 | 技术 | 稳定性 |
|---|---|---|
| 基础 | requests.get() + ?page= | 大目录容易失效,也可能被封 |
| 中级 | requests.Session() + ?limit=250 + time.sleep(1) + 429 重试 | 适合大多数店铺 |
| 高级 | 异步 httpx + 轮换 User-Agent + 指数退避 | 可用于生产,支持 1 万+ 商品规模 |
中级方案(适合大多数用户,推荐):
1import requests
2from requests.adapters import HTTPAdapter
3from urllib3.util.retry import Retry
4def create_session():
5 """创建带自动重试逻辑的 requests 会话。"""
6 session = requests.Session()
7 retries = Retry(
8 total=5,
9 backoff_factor=1, # 休眠:0.5s、1s、2s、4s、8s
10 status_forcelist=[429, 430, 500, 502, 503, 504],
11 respect_retry_after_header=True
12 )
13 session.mount("https://", HTTPAdapter(max_retries=retries))
14 session.headers.update({
15 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
16 })
17 return session
这里的 Retry 配置会在遇到 429 时自动进行指数退避重试。backoff_factor=1 的意思是:每次重试之间的等待时间按 0.5 秒 → 1 秒 → 2 秒 → 4 秒 → 8 秒递增。复用 requests.Session() 还能启用连接池,在同一个域名上连续请求时更省开销。
User-Agent 轮换:如果你要抓多个店铺,建议在 3–5 个真实浏览器的 User-Agent 之间轮换。这不是为了“伪装”,而是为了避免每次请求都带着一模一样的请求头,看起来像机器人。
完整可运行的 Python 脚本:抓取 Shopify 并导出 CSV
下面是一份可以直接复制运行的完整脚本,把上面的所有内容都整合在了一起。实际有效代码大约 75 行左右(加上注释),我已经用它测试过 Allbirds(1,420 个商品)、ColourPop(2,000+ 个商品)和 Zoologist Perfumes(小型目录)。
1import requests
2import pandas as pd
3import time
4import random
5from requests.adapters import HTTPAdapter
6from urllib3.util.retry import Retry
7def create_session():
8 """创建一个带速率限制重试逻辑的会话。"""
9 session = requests.Session()
10 retries = Retry(
11 total=5,
12 backoff_factor=1,
13 status_forcelist=[429, 430, 500, 502, 503, 504],
14 respect_retry_after_header=True
15 )
16 session.mount("https://", HTTPAdapter(max_retries=retries))
17 session.headers.update({
18 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
19 "AppleWebKit/537.36 (KHTML, like Gecko) "
20 "Chrome/125.0.0.0 Safari/537.36"
21 })
22 return session
23def scrape_shopify(store_url, delay=1.0):
24 """通过 /products.json 抓取 Shopify 店铺的全部商品。"""
25 session = create_session()
26 all_products = []
27 page = 1
28 base_url = f"{store_url.rstrip('/')}/products.json"
29 while True:
30 print(f" Page {page}...", end=" ")
31 resp = session.get(base_url, params={"limit": 250, "page": page}, timeout=30)
32 resp.raise_for_status()
33 products = resp.json().get("products", [])
34 if not products:
35 break
36 all_products.extend(products)
37 print(f"{len(products)} products (total: {len(all_products)})")
38 page += 1
39 time.sleep(delay + random.uniform(0, 0.5))
40 return all_products
41def flatten_to_variants(products):
42 """把嵌套的商品 JSON 展平成每个规格一行。"""
43 rows = []
44 for p in products:
45 base = {
46 "product_id": p["id"],
47 "title": p["title"],
48 "handle": p["handle"],
49 "vendor": p.get("vendor", ""),
50 "product_type": p.get("product_type", ""),
51 "tags": ", ".join(p.get("tags", [])),
52 "created_at": p.get("created_at", ""),
53 "updated_at": p.get("updated_at", ""),
54 "image_url": p["images"][0]["src"] if p.get("images") else "",
55 }
56 for v in p.get("variants", []):
57 row = {**base}
58 row["variant_id"] = v["id"]
59 row["variant_title"] = v.get("title", "")
60 row["sku"] = v.get("sku", "")
61 row["price"] = v.get("price", "")
62 row["compare_at_price"] = v.get("compare_at_price", "")
63 row["available"] = v.get("available", "")
64 rows.append(row)
65 return rows
66if __name__ == "__main__":
67 STORE_URL = "https://allbirds.com" # 改成你要抓取的店铺
68 OUTPUT_CSV = "shopify_products.csv"
69 OUTPUT_EXCEL = "shopify_products.xlsx"
70 print(f"Scraping {STORE_URL}...")
71 products = scrape_shopify(STORE_URL)
72 print(f"\nTotal products scraped: {len(products)}")
73 print("Flattening to variant-level rows...")
74 rows = flatten_to_variants(products)
75 df = pd.DataFrame(rows)
76 print(f"DataFrame: {df.shape[0]} rows x {df.shape[1]} columns")
77 df.to_csv(OUTPUT_CSV, index=False, encoding="utf-8-sig")
78 df.to_excel(OUTPUT_EXCEL, index=False, engine="openpyxl")
79 print(f"\nExported to {OUTPUT_CSV} and {OUTPUT_EXCEL}")
运行方式:python scrape_shopify.py。以 Allbirds 为例,整个过程大约需要 45 秒,并会生成一个包含 5,000+ 行(每个规格一行)的 CSV。终端输出大概会像这样:
1Scraping https://allbirds.com...
2 Page 1... 250 products (total: 250)
3 Page 2... 250 products (total: 500)
4 ...
5 Page 6... 170 products (total: 1420)
6Total products scraped: 1420
7Flattening to variant-level rows...
8DataFrame: 5680 rows x 14 columns
9Exported to shopify_products.csv and shopify_products.xlsx
不写 Python:用 Thunderbit 两步抓取 Shopify(无代码方案)
不是每个人都想安装 Python、调试导入错误,或者长期维护一份抓取脚本。对于那种明天早上就要竞品价格的人来说,Python 的成本其实有点高。
所以我们做了 ——一个作为 Chrome 扩展运行的 AI 网页爬虫。无需代码,无需 API key,也不用配置运行环境。
Thunderbit 是怎么抓取 Shopify 店铺的?
Thunderbit 内置了一个专门的 Shopify Scraper 模板,已经为 Shopify 商品页预先做好了配置。你只需要安装 ,进入一个 Shopify 店铺,然后点击“Scrape”。模板会自动提取商品名称、描述、价格、规格详情、图片和供应商信息。
如果模板和页面结构不是完全匹配(比如自定义主题、特别的布局),Thunderbit 的 AI Suggest Fields 功能会读取页面并自动生成列名。你还可以继续自定义:重命名列、添加字段,或者直接下达指令,比如“只提取 compare_at_price 有值的商品”。
下面这些功能和 Python 脚本能做到的事情几乎一一对应:
- 子页面抓取:自动访问每个商品详情页,并补充完整描述、评论或规格详情——这和 Python 通过循环翻页实现的效果类似,但不需要写代码。
- 自动分页:自动处理点击翻页和无限滚动,无需额外配置。
- 定时抓取:可以设置周期任务(例如“每周一上午 9 点”)持续监控价格变化,不需要 cron job 或服务器。
- 免费导出:所有方案都可导出到 CSV、Excel、Google Sheets、Airtable 或 Notion。
Python 脚本 vs. Thunderbit:诚实对比
| 维度 | Python 脚本 | Thunderbit(无代码) |
|---|---|---|
| 上手时间 | 15–60 分钟(环境 + 代码) | 约 2 分钟(安装 Chrome 扩展) |
| 是否需要编程 | 需要(Python) | 不需要 |
| 可定制性 | 几乎无限 | AI 推荐字段 + 自定义提示词 |
| 分页处理 | 需要手写 | 自动完成 |
| 导出格式 | 需自行实现(CSV/Excel) | CSV、Excel、Google Sheets、Airtable、Notion(免费) |
| 定时执行 | 需要 cron + 托管环境 | 内置调度器 |
| 速率限制处理 | 需要自己写重试/退避 | 自动处理 |
| 最适合谁 | 开发者、大规模数据管道 | 商业用户、快速提取、周期性监控 |
如果你需要完全控制流程,或者要把数据接入更大的数据管道,那就用 Python。如果你要的是“快、方便、别维护代码”,那就用 Thunderbit。想更深入了解 ,我们也写过专门的文章。

抓取 Shopify 店铺的技巧与最佳实践
无论你最终用什么工具,这些建议都适用:
- 始终使用
?limit=250,把请求次数降到最低。默认每页 30 个商品,意味着同样的数据要多发 8 倍请求。 - 尊重目标站点:每次请求之间留 1–2 秒。对服务器高频连发请求不仅不礼貌,也更容易被封。
- 先检查
robots.txt:Shopify 默认的robots.txt并不会屏蔽/products.json,但有些店铺会加入自定义规则,批量抓取前最好先确认。 - 先把原始 JSON 存到本地,再做后处理。这样以后如果解析逻辑变了,不用重新抓取。像
json.dump(all_products, open("raw_data.json", "w"))这种简单操作,后面能省很多麻烦。 - 按
product.id去重:分页边界有时会出现重复商品。用df.drop_duplicates(subset=["product_id", "variant_id"])可以快速清理。 - 计算前先把
price转成 float。Shopify 返回的是字符串("185.00"),不是数字。 - 关注接口变化:虽然
/products.json多年来一直很稳定,但理论上 Shopify 仍可能限制它。如果你的抓取器突然返回 404,先手动打开店铺看看。
如果你想进一步学习如何构建更稳健的抓取器,可以看看我们关于 的指南。
抓取 Shopify 时的法律与伦理注意事项
这一段不长,但很重要。
/products.json 接口提供的是公开商品数据——也就是任何访客在浏览商店时都能看到的信息。Shopify 的服务条款里确实有关于不能用“自动化方式”访问“服务”的表述,但这里指的是平台本身(如后台、结账流程),不是公开前台商品数据。到 2026 年 4 月为止,还没有针对 Shopify 公开数据抓取的相关诉讼案例。
已有的法律先例也支持对公开数据进行抓取:hiQ v. LinkedIn 案确认了抓取公开可访问数据并不违反 CFAA,而 Meta v. Bright Data(2024)则裁定,只有在用户登录后,服务条款里的限制才会生效。
最佳实践:
- 只抓取公开可访问的商品数据
- 不要抓取个人或客户数据
- 遵守
robots.txt和速率限制 - 如果涉及任何个人数据,需符合 GDPR/CCPA(商品目录数据不属于个人数据)
- 使用清晰的 User-Agent 标识自己
- 抓取你自己店铺的数据时,使用 Admin API 永远是没问题的
想更深入了解的话,可以看我们关于 的文章。
结论与核心要点
Shopify 公开的 /products.json 接口,让电商数据提取变得尽可能简单。整个流程就是:追加 /products.json → 用 Python 抓取 → 用 ?limit=250&page= 分页 → 用 pandas 展平 → 导出成 CSV 或 Excel。
这篇指南相比其他教程,补充了这些内容:
- 完整字段参考:在写第一行代码之前,就能知道具体能拿到哪些数据(商品、规格、图片共 40+ 个字段)
- 额外接口:
/collections.json和/meta.json能提供分类级情报和店铺元数据,而这些通常没人讲 - 可用于生产环境的技巧:会话复用、指数退避、User-Agent 头和
?limit=250,应对真实世界的速率限制 - 正确的 CSV/Excel 导出:使用 pandas 将规格层级数据展平,而不是只保存原始 JSON
- 无代码替代方案:适合想要速度而不是代码灵活性的用户,可直接用
如果你想在不写代码的情况下做一次性或周期性的 Shopify 数据提取,可以试试 ——Shopify Scraper 模板会自动处理从分页到导出的所有事情。如果你需要自定义数据管道,或者要跨多个店铺大规模抓取,那么这篇指南里的 Python 脚本会给你完整控制权。
也欢迎关注我们的 ,观看视频教程;或者浏览我们关于 和 的相关指南,了解更多类似技巧。
常见问题
所有 Shopify 店铺都能通过 products.json 抓取吗?
大多数 Shopify 店铺默认都会开放这个接口——在测试中,大约 71% 返回了有效 JSON。有些使用自定义配置或额外安全层(例如 Cloudflare、无头架构)的店铺,可能会返回 404 或直接拦截请求。最简单的检查方式是:在浏览器里打开 {store-url}/products.json。如果你看到了 JSON,就说明可以用。
抓取 Shopify 店铺合法吗?
公开商品数据(价格、标题、图片、描述)通常是可访问的,而且像 hiQ v. LinkedIn 这样的法律先例也支持抓取公开信息。不过,还是应该查看具体店铺的服务条款以及你所在地区的法律。不要抓取个人或客户数据,并且要遵守速率限制。
一个 Shopify 店铺最多能抓取多少商品?
总量没有硬性上限。通过 ?limit=250&page= 分页,你可以把整个目录都抓下来。对于非常大的店铺(25,000+ 商品),建议配合会话复用和延时,避免触发速率限制。/meta.json 接口还可以提前告诉你准确的商品总数,这样你就能知道大概需要多少页。
products.json 和 Shopify Admin API 有什么区别?
/products.json 是公开接口——不需要认证,任何人都能访问,只能读取商品数据。Admin API 则需要店主访问令牌,可以读取订单、库存数量、客户数据,也能写入数据。如果你需要销售数据或真实库存数量,就必须有 Admin API 访问权限(也就是你必须是店主,或者得到店主授权)。
不用 Python 也能抓取 Shopify 吗?
当然可以。 这类工具可以通过 Chrome 扩展直接抓取 Shopify 店铺,无需编程。它会自动处理分页,并直接导出到 CSV、Excel、Google Sheets、Airtable 或 Notion。对于喜欢其他语言的开发者来说,同样的 /products.json 接口也可以用 JavaScript、Ruby、Go 等任何能发 HTTP 请求并解析 JSON 的语言来访问。
了解更多
