跨境选品采集的第一个误区:以为所有电商站的代理策略是通用的
跨境选品场景里,很多团队的做法是:搭一个采集脚本,挂上代理池,先跑 Shopify 站、再跑 BigCommerce 站、再跑独立站,代理策略统一——每个请求换一个 IP,并发 10,超时 15 秒。
结果往往是:Shopify 站跑得还行,BigCommerce 站成功率突然掉到 50% 以下,独立站更是各有各的表现。
原因是:不同平台的访问频率控制机制不一样,代理策略需要适配目标站的控制逻辑,不是反过来。
这篇以 Shopify 和 BigCommerce 为例,拆一下两种平台的访问频率控制特征,再讲怎么对应调整代理策略。方法本身是通用的——你可以用同样的思路分析任何目标站。
Shopify 的访问频率控制特征:Bucket 模型 + 请求头泄露
Shopify 的公开页面(产品列表、产品详情、集合页)有一套基于令牌桶(Token Bucket)的访问频率控制机制。这个机制有几个可以观察到的特征:
特征一:HTTP 响应头里会返回限流状态。 Shopify 的响应头通常会包含类似 X-Request-Id、Retry-After 这样的字段。当你触发了频率限制,会收到 429 状态码,Retry-After 告诉你等多少秒再重试。
特征二:限流粒度是 IP + 店铺。 同一个 IP 访问同一个 Shopify 店铺的频率被独立计算。你用同一个 IP 同时访问店铺 A 和店铺 B,两个店铺的限流计数器是独立的。
特征三:令牌恢复速度相对固定。 根据公开文档和社区实践,Shopify 公开页面的频率限制通常是每秒 2-4 个请求(具体值因店铺计划不同而异,且可能变化)。令牌用完后需要等恢复,不是硬性封禁。
这意味着什么?
对 Shopify 来说,代理策略的核心不是"换 IP 速度",而是控制同一个 IP 对同一个店铺的请求速率。你有 100 个 IP,每个 IP 每秒发 2 个请求,总吞吐就是 200 QPS——比用 10 个 IP 每个拼命发 20 个请求然后被限流、重试、再被限流效果好得多。
BigCommerce 的访问频率控制特征:更激进的指纹关联
BigCommerce 的公开页面访问频率控制相对不那么透明,但有几个可以通过实际测试观察到的特征:
特征一:不一定返回 429。 BigCommerce 在触发限流时,有时直接返回 403 或显示验证页面,而不是标准的 429 + Retry-After。这意味着你不能简单地靠"收到 429 就等一下"来处理。
特征二:可能做更多的请求环境关联。 除了 IP 地址,BigCommerce 可能会关联请求头中的其他信息(如 User-Agent 一致性、Accept-Language、连接特征)来综合判断。单纯换 IP 但请求头不变,效果可能打折。
特征三:限制恢复时间更长。 一旦某个 IP 被限制,冷却时间可能不是几秒,而是几分钟甚至更长。
这意味着什么?
对 BigCommerce 来说,代理策略的核心是IP 和请求指纹的联动轮换——换 IP 的同时要换请求头的组合,而且被限制的 IP 需要更长的冷却时间。
代理调度策略:怎么根据这些差异做适配
基于上面的分析,代理调度层需要对不同平台采用不同的策略参数。具体做法:
按平台类型建策略配置。 给 Shopify 类目标站和 BigCommerce 类目标站分别设一组参数:
PLATFORM_STRATEGY = {
"shopify": {
"rotation_mode": "time_based",
"rotation_interval": 30, # 30秒换一次IP
"max_qps_per_ip": 2, # 每个IP每秒最多2个请求
"cooldown_on_429": 5, # 收到429后冷却5秒
"cooldown_on_403": 60, # 收到403后冷却60秒
"rotate_headers": False, # Shopify对请求头不敏感
"session_sticky": False, # 不需要粘性会话
},
"bigcommerce": {
"rotation_mode": "per_request",
"rotation_interval": None,
"max_qps_per_ip": 1, # 保守一点
"cooldown_on_429": 30,
"cooldown_on_403": 300, # 冷却时间更长
"rotate_headers": True, # 换IP时同时换请求头
"session_sticky": False,
},
"default": {
"rotation_mode": "per_request",
"rotation_interval": None,
"max_qps_per_ip": 3,
"cooldown_on_429": 10,
"cooldown_on_403": 120,
"rotate_headers": False,
"session_sticky": False,
}
}
速率控制器实现。 在代理调度层加一个令牌桶,限制同一个 IP 对同一个域名的请求速率:
import time
import threading
class RateLimiter:
def __init__(self, max_qps):
self.max_qps = max_qps
self.tokens = {
} # {ip:domain: [timestamps]}
self.lock = threading.Lock()
def allow(self, ip, domain):
key = f"{ip}:{domain}"
now = time.time()
with self.lock:
if key not in self.tokens:
self.tokens[key] = []
# 清理1秒前的记录
self.tokens[key] = [t for t in self.tokens[key] if now - t < 1.0]
if len(self.tokens[key]) < self.max_qps:
self.tokens[key].append(now)
return True
return False
在取 IP 时,不仅要从池子里借到一个可用 IP,还要通过 RateLimiter.allow() 检查这个 IP 对当前域名是否还有请求配额。没有就跳过,试下一个 IP。
请求头轮换。 对 BigCommerce 类目标站,换 IP 时同时换一组请求头。维护一个请求头模板池:
HEADER_PROFILES = [
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...",
"Accept-Language": "en-US,en;q=0.9",
"Accept-Encoding": "gzip, deflate, br",
},
{
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 ...",
"Accept-Language": "en-GB,en;q=0.8",
"Accept-Encoding": "gzip, deflate",
},
# ... 更多组合
]
注意:请求头模板要合理,不要混搭——比如不要在 Windows 的 User-Agent 上挂 macOS 的平台标识。浏览器的指纹组合是有内在一致性的,胡乱组合比不换更容易被识别。
采集架构:怎么在一套系统里同时处理多种平台
如果你的跨境选品采集需要同时覆盖 Shopify 站、BigCommerce 站和其他独立站,架构上建议这样组织:
目标站分类层。 先对目标站做分类:Shopify、BigCommerce、WooCommerce、其他。分类可以通过检测响应头或页面特征来自动判断——比如 Shopify 站的 HTML 里通常包含 cdn.shopify.com,BigCommerce 站的响应头可能包含 X-BC- 前缀的字段。
def detect_platform(url, response_headers, html_snippet):
if "cdn.shopify.com" in html_snippet:
return "shopify"
if any(h.startswith("X-BC-") for h in response_headers):
return "bigcommerce"
# WooCommerce 检测
if "wp-content" in html_snippet and "woocommerce" in html_snippet.lower():
return "woocommerce"
return "default"
策略路由层。 根据平台类型从 PLATFORM_STRATEGY 里取对应的参数,传给代理调度模块。
代理调度层。 接收策略参数,执行相应的轮转模式、速率控制和请求头轮换。这层的代码不需要知道目标站是什么平台——它只根据参数行事。
这种分层的好处是:新增一种平台类型时,只需要加一组策略参数和一个检测规则,不用改调度层的核心逻辑。
冷却队列:被限制的 IP 不要立刻丢掉
Shopify 的 429 冷却几秒就能恢复,BigCommerce 的 403 可能要等几分钟。不管哪种,被限制的 IP 不应该直接从池子里删除——它只是暂时不能用于这个目标站,过了冷却期还能复活。
实现方式:在 Redis 里维护一个"冷却队列":
Key: proxy:cooldown:{ip:port}:{domain}
Value: resume_timestamp
TTL: 等于冷却时间
取 IP 时,除了检查评分和域名隔离,还要检查这个 IP 是否在冷却中。冷却中的跳过,TTL 到期后自动释放,IP 恢复可用。
这比直接淘汰 IP 的好处是:代理 IP 有成本,一个 IP 被某个目标站限制了 5 分钟,但它对其他目标站可能完全正常。直接删除等于浪费资源。
怎么知道你的策略参数设对了
策略参数(QPS 上限、冷却时间、轮转间隔)不是一成不变的。目标站会调整访问频率控制策略,你的参数也需要跟着调。
建议的验证方法:
小样本探测。 每次开始正式采集前,先用 5-10 个 IP 做一轮探测:逐步提高单 IP 请求速率,记录什么速率下开始收到 429/403。这个"触发阈值"就是你设 max_qps_per_ip 的依据。
成功率趋势监控。 正式采集过程中,按目标站分别统计成功率。如果某个平台的成功率突然从 90% 掉到 70%,大概率是对方调整了限流策略,你需要重新做探测并调参。
不同参数组的 A/B 测试。 把同一个目标站的采集任务分成两组,用不同的策略参数(比如 A 组 QPS=2、B 组 QPS=3),跑一天,看哪组的综合成功率和吞吐更高。
FAQ
Q:怎么判断一个 Shopify 站用的是基础版还是高级版?
从采集侧很难准确判断,因为 Shopify 不在公开页面暴露店铺计划类型。但好消息是:对于公开页面的访问频率控制,不同计划版本的差异不大——主要差异在 API 调用限额上,不在前端页面访问上。所以代理策略不需要区分店铺计划版本。
Q:BigCommerce 站的 API 和前端页面的限流是一样的吗?
不一样。BigCommerce 的 API(如果你有合规的 API Key)有独立的频率限制体系,和前端页面的访问频率控制是分开的。如果目标站提供了公开 API 且你有合规的访问权限,走 API 通常比采集前端页面更稳定,也更可控。
Q:请求头轮换的"模板"需要多少组?
10-20 组就够了。关键不是数量多,而是每组的内在一致性——User-Agent、Accept 系列、Sec-CH-UA(如果模拟 Chromium 系浏览器)这些字段要对得上。一组不自洽的请求头比不换更容易触发异常判断。