如果你在 Shopify 上开店,你的大多数竞争对手很可能也在用 Shopify,而他们的价格、折扣和库存,任何打开店铺的人都看得到。监控应用会把这些数据做成仪表盘,但你也可以自己采集同样的数据,只针对你关心的店铺和商品,并保留历史记录。这是单个店主规模的价格情报,而 Shopify 让第一步比大多数平台都更容易。
本指南介绍数据在哪里、每个商品要记录什么、如何按国家比较市场,以及如何稳定地运行。
为什么要自己搭建
应用上手快,但也有局限。它们通常限制竞争对手或商品的数量,按自己的节奏更新,并把原始历史数据留在应用里。一个自己的小型采集程序可以带来:
- 你自己的竞争对手名单, 包括任何应用都不追踪的小店铺。
- 你自己的时间表, 例如促销期间每隔几小时一次,其余时间每天一次。
- 你自己的数据, 存在表格或数据库里,可以和你自己的销量和利润率关联起来。
代价是需要一点配置,并让请求保持礼貌和稳定,这正是代理发挥作用的地方。
数据在哪里:公开的商品 JSON
大多数 Shopify 店铺会以机器可读的形式公开商品目录:
/products.json按页列出商品及其变体。加上?limit=250&page=2等参数即可逐页遍历大型目录。/products/<handle>.json返回单个商品,handle 是商品 URL 的最后一段。/collections/<handle>/products.json列出某个系列中的商品,只关注一个品类时很有用。
每个变体都包含你需要的字段:price、compare_at_price(划线的”原价”)、available、sku 以及时间戳。这比加载带有图片和脚本的渲染后商品页面轻得多,而且店铺更换主题时也不会变化。
并不是每个店铺都开放这个接口。有的会返回错误或密码页面,无头(headless)店铺可能根本不提供。这种情况下,可以改为读取嵌入在商品页面中的结构化数据;具体方法见提取 JSON-LD,而不是解析 HTML。
每个商品要记录什么
追踪变体,而不是商品。一件有五个尺码的 T 恤就是五个变体,竞争对手往往只给卖不动的尺码打折。
每个变体、每次检查记录:
- 店铺、商品 handle、变体 ID、SKU 和变体名称(尺码、颜色)。
price和compare_at_price。available(是否有货)。- 检查时间、检查所在国家以及显示的货币。
需要计算的信号:
- 折扣力度:
compare_at_price与price之间的差额,以及折扣开始和结束的时间。 - 价格变动: 每次变体价格变化时,记录旧值和新值。
- 缺货: 变为无货的变体,通常意味着需求旺盛或供应出了问题。
- 新上架和下架的商品: 竞争对手推出了什么,又悄悄下架了什么。
只保存变化加上每天一次的快照,即使追踪几十家店铺,历史数据也不会太大。
市场:同一家店铺,不同国家不同价格
Shopify Markets 让一家店铺可以用当地货币在许多国家销售,而且价格常常不同。访客看到哪个市场通常取决于他们的所在地,有时还会使用 /en-ca/ 这样的国家子目录或货币选择器。
这对监控很重要。如果你从一个国家的一台服务器采集所有数据,就只能看到那一个市场。要比较美国、英国和德国的买家支付的价格:
- 从你销售的每个国家的 IP 访问店铺, 让店铺选择当地买家看到的市场。
- 记录收到的货币和价格, 而不是换算后的数值。
- 第一次时,每个市场手动核对一个商品, 与渲染后的页面对比,确认你采集的 JSON 显示的是该店铺的当地价格。
对于大多数 Shopify 比较,国家级定位就足够了。只有当店铺按地区改变配送选项或库存时,城市级定位才有意义。
一个最简采集程序
下面的脚本通过代理读取一家店铺的商品目录,并输出每个变体的价格和库存。按店铺和国家定时运行,并把结果写入你的数据库。
import time
import requests
PROXY = "http://customer-USERNAME-country-us:PASSWORD@p.shifter.io:443"
STORE = "https://competitor-store.example"
def fetch_catalogue(store):
page = 1
while True:
r = requests.get(
f"{store}/products.json",
params={"limit": 250, "page": page},
proxies={"http": PROXY, "https": PROXY},
timeout=30,
)
r.raise_for_status()
products = r.json().get("products", [])
if not products:
break
yield from products
page += 1
time.sleep(2) # stay polite between pages
for product in fetch_catalogue(STORE):
for v in product["variants"]:
print(product["handle"], v["id"], v["title"],
v["price"], v["compare_at_price"], v["available"])
修改用户名中的 country-us,就能以另一个市场买家的视角采集同一家店铺。
代理配置
| 任务 | 轮换方式 | 定位 |
|---|---|---|
| 每日商品目录快照 | 每次请求 | 市场所在国家 |
| 促销期间频繁检查重点商品 | 每次请求 | 市场所在国家 |
| 检查购物车或结账总额 | 粘性会话 | 市场所在国家 |
Shopify 店铺会限制单个地址请求页面的速度,每天访问同样几家店铺的监控服务器很快就会被注意到。每次请求使用新 IP 的住宅代理会把检查分散到目标国家的真实家庭宽带上,店铺会像对待当地买家一样响应。
几个让采集保持稳定的习惯:
- 同一家店铺的页面之间停顿一两秒,并把不同店铺分散到一天中的不同时间。
- 重点商品勤检查,完整目录每天检查一次;大多数价格不会每小时变化。我们关于线上价格变化有多快的研究可以帮你选择合理的频率。
- 把 HTML 响应或验证页面当作失败而不是数据,稍后再重试。
如何融入更大的体系
Shopify 店铺通常只是全局的一部分。如果你还在追踪供应商和电商平台,我们的代发货代理指南介绍了在监控竞争店铺的同时,如何做选品研究和供应商监控。
总结
监控竞争对手的 Shopify 店铺不需要应用。读取公开的商品 JSON,为每个变体记录价格、“原价”和库存,以及检查的时间和国家,只保存变化。每个市场都从该国的 IP 采集,并使用轮换的住宅代理,让每天的采集计划不被封锁。