使用 Python 自动化市场调研:抓取 Shopify 数据

最后更新于 April 16, 2026

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 字段说明:每个字段都讲清楚

很多教程只会展示 titleidhandle,然后就草草结束。但 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_atISO 日期时间"2024-01-15T10:30:00-05:00"跟踪商品何时上架(识别新品)
updated_atISO 日期时间"2025-03-01T08:00:00-05:00"发现目录最近是否有变动
published_atISO 日期时间"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_atISO 日期时间规格层级的变动追踪

图片层级字段

字段数据类型示例用途
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[].pricevariants[].compare_at_pricevariants[].available。如果你是做线索挖掘,那就重点关注 vendorproduct_typetags。按需过滤,你导出的 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,也就是你必须拥有店主访问权限。公开接口只提供商品目录数据。

shopify-data-access-methods.webp

如何用 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。想更深入了解 ,我们也写过专门的文章。

python-vs-thunderbit-comparison.webp

抓取 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 脚本会给你完整控制权。

也欢迎关注我们的 ,观看视频教程;或者浏览我们关于 的相关指南,了解更多类似技巧。

使用 Thunderbit 抓取 Shopify

常见问题

所有 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 的语言来访问。

了解更多

Ke
Ke
CTO @ Thunderbit. Ke is the person everyone pings when data gets messy. He's spent his career turning tedious, repetitive work into quiet little automations that just run. If you've ever wished a spreadsheet could fill itself in, Ke has probably already built the thing that does it.
目录

试试 Thunderbit

只需 2 次点击即可抓取线索和其他数据。AI 驱动。

获取 Thunderbit 免费使用
使用 AI 提取数据
轻松将数据传输到 Google Sheets、Airtable 或 Notion
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week