已经在采集市场数据的团队,往往会用处理 Amazon 的方式来处理 Walmart,结果数字会以一种容易被忽视的方式出错。没有报错。价格看起来也合理。它们只是和达拉斯或坦帕的顾客实际看到的不一致,而且这种不一致是系统性的,不是随机的。
原因是结构性的。Walmart 是一个门店网络,前面挂着一个网站,而不是一个全国性的商品目录。价格和库存是针对特定门店解析的,而这家门店是根据你可能无法控制的信号,替你选定的。
门店是真相的基本单位
对于很大一部分商品来说,以下三项会因门店而异:
价格。 Rollback、清仓和区域定价意味着相隔四十英里的两家门店,同一件商品可能标价不同。
库存。 门店内库存按定义是按门店计的,而某个会话可以使用的配送和自提选项,取决于该会话绑定的是哪家门店和哪个配送中心。
商品组合。 有些商品在某些门店根本不出售,这会被读取为缺失商品,而不是缺货。
如果你的采集层没有锁定门店,网站会根据请求的表观位置替你选择一家,而且明天可能会选择另一家。结果就是一个时间序列,其中价格变动一部分是真实的,一部分是门店在你不知情的情况下悄悄改变造成的。这比数据缺失更糟,因为它看起来像是一种趋势。
同样的陷阱也适用于任何有本地配送体系的零售商。这一论点的通用版本见监控产品可用性和库存。
两个信号决定你得到哪家门店
一个是你的请求表面上来自的位置,即 IP 地址及其地理定位;另一个是你在会话中明确选择的门店或邮编。这是两种不同的机制,它们需要保持一致。
一个位于弗吉尼亚州的数据中心 IP,配合一个声称是凤凰城门店的会话,是不一致的组合。它有时能用,有时会悄悄解析成别的东西,而这正是零售反爬虫系统会重点权衡的信号类型。使用你所询问的都会区内的住宅 IP,能让这对信号保持一致,这才是关键所在:你是在还原一个真实购物者,而不是在断言一个位置。
先锁定地理位置,再锁定会话
在 Shifter 网关中,定向信息放在用户名里,而不是单独的 API 调用中。指向 p.shifter.io:443,并在凭据中编码位置和会话信息:
customer-USERNAME-country-us-city-dallas-sid-store2354-ttl-600:PASSWORD这里有三个部分很重要。country-us 和 city-dallas 把出口设在正确的都会区。sid-store2354 指定了一个粘性会话,因此所有带有该标识符的请求都会从同一个 IP 发出。ttl-600 会将该 IP 保持十分钟,足够选定一家门店、浏览一个品类并读取一组商品页面,而不会在爬取过程中位置发生变化。
请注意,ttl 只有和 sid 搭配使用时才有意义。没有会话标识符,就没有需要保持存活的东西,此时会应用默认的轮换机制。
需要牢记的心智模型是:每家门店使用一个粘性会话,在检查该门店的商品时重复使用该会话,而不是每个请求使用一个会话。在每个商品页面之间轮换,是这里最常见的配置错误,因为这会不断重新触发门店解析,产生你本想消除的那种漂移。相关权衡在粘性会话与轮换会话对比中有详细说明。
城市名称使用纯小写字母,空格用下划线代替,国家使用 ISO alpha-2 代码。如果某个筛选条件过于狭窄而无法满足,网关会返回 502,而不是悄悄给你一个其他地方的出口,这正是当门店准确性是全部重点时你想要的行为。
记录门店,而不只是价格
架构设计正是大多数 Walmart 数据面板成败的关键所在。一行写着”商品 X 周二售价 14.98 美元”的数据并不是可用的观测记录,因为它遗漏了决定价格的那个因素。
至少要采集以下内容:
- 商品标识符
- 会话实际解析到的门店标识符
- 价格,以及单独记录的任何划线价或原价
- 库存状态,分为店内、自提和配送三类
- 卖家,因为第三方商品的行为与自营商品不同
- 请求出口所在的国家和城市
- UTC 时间的采集时间戳
门店标识符应该从响应中读取回来,而不是根据你的请求内容去假设。仅这一个字段,就能把一次无法解释的价格跳变,变成一次可见的门店变化,这也是一个可以站得住脚的数据面板,和一张你不得不道歉的图表之间的区别。
区分检查失败的四种方式
零售数据采集会产生多种失败模式,如果不加以区分,它们看起来都像是”没有数据”:
被拦截。 你收到了验证挑战或插页。这次观测缺失,该商品应当被重试,而不是记录为不可用。
缺货。 一个有效页面显示该商品在此门店不可用。这是真实数据,应纳入序列。
未上架。 该商品不在这家门店的商品组合中。这也是真实数据,和缺货不同。
门店错误。 页面渲染出来了,但对应的门店不是你要求的那家。这是最危险的一种,因为它会产生一行看起来干净、但数值错误的记录。
只有第一种情况值得重试。混淆中间两种会抹平真实存在的商品组合差异,而把第四种当作有效数据处理,正是坏数字流入仪表盘的原因。在传输层面,407 表示凭据有误或定向标志格式错误,502 表示没有出口符合你的筛选条件,509 表示带宽额度已耗尽。
采集频率,以及为什么它应该平淡无奇
价格数据面板往往有很强的冲动去追求高频率。出于两个原因,应当克制这种冲动。
第一个原因是,针对零售网站的请求量,是最容易让采集模式被察觉的信号,而解决方法不是增加更多 IP,而是采用一种看起来像正常需求而非扫描的时间表。把检查分散在一天之内,保持每家门店的并发量适中,遇到错误时退避,而不是硬闯过去。具体机制见速率限制与请求节流。
第二个原因是成本。住宅流量是按带宽计费的,因此关键杠杆是每次观测消耗的字节数,而不是每小时的请求数。跳过图片,优先选择携带所需字段的最轻响应,不要在只需要三件商品时,重新抓取整个品类页面。更详细的处理方法见削减代理带宽成本。
对于大多数零售数据面板来说,每家门店每件商品每天读取一次,足以检测到重要的变动,更快的频率则应保留给一小份高价值商品的观察名单。
为 Walmart 数据面板确定规模
带宽消耗遵循一个简单的乘积关系:追踪的商品数,乘以追踪的门店数,乘以每天检查次数,乘以每次检查的字节数。门店这个乘数因子是人们最容易忽略的,也是增长最快的一个,因为给一个五千商品的数据面板增加二十个都会区,每轮就会产生十万次观测。
先从一个狭窄的门店集合开始,这个集合应反映你实际做决策所依据的市场,测量一周内每次检查的实际字节数,然后再扩展。具体方法见估算每月住宅代理带宽,当前费率见住宅代理定价页面。
常见问题
如果我已经在会话中选择了邮编,还需要住宅 IP 吗?
从一致性角度看,需要。在选择某个位置的同时,又从另一个地区的数据中心 IP 段接入,这是不一致的组合,而且会被如此对待。明确的选择告诉网站你想要什么;而 IP 则是网站相信的内容。
一个会话应该覆盖多少家门店?
一家。在单个门店的商品检查中重复使用一个粘性会话,然后为下一家门店建立一个新会话。在一个会话中混用多家门店,正是产生归属错误的原因。
Walmart 数据采集和 Amazon 有什么不同?
机制上有重叠,但门店维度是 Walmart 特有的,并且会改变数据架构。如果你正在扩展一个现有的市场数据管道,抓取 Amazon 商品数据涵盖了可以沿用的部分。
第三方市场商品怎么处理?
采集卖家字段,并将自营商品和第三方商品的数据行作为独立的序列处理。把两者混在一起,会产生与定价决策毫无关系的价格历史跳变。
结论
只有当 Walmart 的价格和库存数据与某家门店关联起来时,它才有意义,而将其与门店关联,意味着要同时控制请求的表观位置,以及解析出该位置的会话的持久性。带地理定向的住宅出口配合粘性会话,能给你这种控制权;记录已解析的门店,则赋予你证明这一点的能力。
把这两件事做对,管道的其余部分就是普通的零售数据采集。做错了,你就会得到一个自信满满、却又一贯错误的仪表盘。更广泛的零售场景见代理如何支持电子商务活动以及价格情报应用场景。