🏢 公司C档 · NaN分

Zillow那张整齐的表,其实是两张

··约1分钟阅读

📋 总体概括

一位把Zillow爬虫当副业的开发者,用真实运行日志量出了这个数据源的三条底细:单次搜索820条硬上限、一套Schema下售卖页与租赁页两种字段填充、以及一个会告诉你'藏了多少'的诚实计数。本文拆解这三件事背后的管道设计逻辑。

📄 正文

Zillow 的页面看起来很整齐:同样的搜索框、同样的卡片、同样的字段。一位在巴厘岛做签证生意、把写爬虫当副业的开发者,把这个数据源前前后后量了个遍,结论只有一句话:外表的均匀是幻觉。41 条一页、20 页封顶、820 条硬上限;一套 Schema 底下,售卖页和租赁页填的是两组不一样的字段。所有准备给房产、电商、招聘这类平台做数据管道的团队,都该先读读这份'体检报告'。

🧱 820 不是性能问题,是产品决策

平台给的天花板,往往比文档诚实。

这位开发者在 Apify 上维护一个抓取 Zillow 的 Actor,覆盖在售、出租、已售三类房源。他自己说,这个 Actor 花在'测量'上的时间,比写代码的时间多得多——因为 Zillow 的数据从外面看,远比实际上均匀。

先看硬约束。Zillow 搜索页每页返回 41 条结果,最多翻 20 页,写死在产品逻辑里:

参数值含义
RESULTS_PER_PAGE41每页结果数
MAX_PAGES20最大翻页数
RESULT_CAP820单次搜索硬上限(41×20)
totalResultCount动态本次搜索的真实匹配总量

41 × 20 = 820。任何一个城市的单次搜索,无论匹配多少房源,最多只能拿回 820 条。对体量大的市场,一次'全城在售'的搜索必然超限——多出来的部分不是抓不到,是根本不给你翻到。

关键在于页面同时暴露了 searchPageState.cat1.searchList.totalResultCount,也就是这次搜索的真实匹配总量。这意味着'被藏起来的量'是可以被计算的:声明总量减去实际回收,就是缺口。所以管道的第一反应不应该是抱怨上限,而是把搜索空间拆小——按价格带切、按邮编切、按上市时间切,直到每个子查询都落在 820 以内,再合并去重。

据多位做平台级采集的从业者私下聊,这类上限几乎从不是技术极限,而是平台在服务成本、访问压力和前端体验之间的一种产品化平衡点。换句话说:它不会因为你的需求变大而变大,你的架构必须围着它变。 任何一条直接读平台搜索接口的管道,都必须把'检测截断'当作一等公民来设计,而不是等数据对不上账时才回头补课。

🗂️ 一套 Schema,两种填充

统一的表结构,不等于统一的数据。

这是整个测量里最有意思的发现:Zillow 对外只有一套页面结构、一套字段定义,售卖页和租赁页是两个数据集——但两边的字段填充完全是两副面孔。典型如价格字段,一边指向挂牌价,一边指向月租金;历史类信息也各说各话。Schema 一样,语义两套。

对做过数仓的人来说这不陌生:宽表里大片空列,而 NULL 的含义至少有三种——'该字段不适用''有但没抓到''有但源站没填'。下游分析师把这三者混为一谈,口径就开始漂移。湖仓时代 schema-on-read 的便利,恰恰放大了这个坑:读的人以为看见的是同一种东西。

工程上常见的三种处理方式,代价各不相同:

方案做法主要代价
单表加空列两类页面共表,不适用的列留空空列率高,字段语义靠猜
分表分管道售、租各自建表建管道需要维护两套口径与映射
分区加模式演化同表不同分区承载不同填充查询端必须感知分区语义

这位开发者的选择是把两类页面当两个数据集交付,而不是硬塞进一张表。这其实是老数仓的常识在采集侧的重演:先分域,再建模;语义不同的数据,物理上就该分开。 据接近采集生态的人士说,市面上相当比例的商业数据集交付纠纷,根源不是字段缺失,而是'字段在,但含义不对'——这句话值得每一个数据中台团队抄在工位上。

🕳️ 诚实的数据源,会告诉你它藏了多少

缺口不可怕,可怕的是你不知道缺口有多大。

测量之所以可能,靠的是那个声明总量字段。这位开发者跑了三组针对 Zillow 奥斯汀房源的搜索,把运行日期、数据集规模和声明总量一一记录在案——所有结论从真实运行里数出来,而不是从文档里抄。

这个动作看似朴素,其实是管道工程里最便宜的一份'数据质量保险':

  • 每次采集,把 totalResultCount 连同实际回收条数一起落库;
  • 完整率 = 实际回收 ÷ 声明总量,每个子查询一行,可监控、可报警;
  • 完整率突然掉下去,先怀疑切分条件变了,再怀疑源站改版。

绝大多数数据源不会这么'诚实'——很多平台的列表页根本不暴露真实总量,缺口只能靠抽样去猜。反过来说,当一个源给了你对照的可能,不用就是浪费。⚠️ 更现实的推论是:就算源不给,也应该自己建一层'声明—回收'对账,哪怕声明量来自估算。企业内部的数据平台同理,上游系统的行数、时间戳、批处理水印,就是你自己管道的 totalResultCount。缺了这层对账,所谓数据质量治理,永远只能事后救火。

📐 从文档出发的管道,都会在真实数据上翻车

别信接口文档,信你的运行日志。

这位开发者反复强调一件事:文中所有结论,包括日期和数据集规模在内,全部来自真实运行,不是来自文档。这是整个故事里最值得抄走的方法论。

数据管道的常见翻车路径是:读文档 → 设计 Schema → 上线 → 在真实数据上撞见空置率、翻页上限、口径漂移,然后返工。文档描述的是理想路径,运行日志暴露的才是真实分布。像 820 这种上限,文档里可能一笔带过,但它直接决定整个架构是'一次抓全'还是'切分回收'——这是架构级分叉,返工代价极高。

给数据团队的落地方向很具体:

1. 上线前跑一遍填充率画像:拿目标源的真实样本逐字段统计填充率,而不是只看字段定义;

2. 做上限测试:构造必然超限的查询,验证管道能检测截断并自动触发拆分;

3. 分域交付:语义不同的页面或接口,宁可两个数据集,不要一张'看起来统一'的大宽表;

4. 审计字段先行:声明总量、抓取时间、翻页深度,作为一等公民落库。

这套逻辑放到 AI 数据采集上同样成立——训练数据集的质量问题,一大半就是'填充不一致 + 截断不自知'。📊 据做数据集交付的团队反映,客户验收时的争议焦点,十有八九落在'这个字段为什么这么多空'上,而答案往往写在源站的产品逻辑里,不在任何一份文档里。谁先去测量,谁就少交一次学费。

小结

820 的上限、一张 Schema 下的两种填充、一个诚实的计数——三件小事指向同一个判断:数据工程的真相在运行日志里,不在文档和页面外观里。 平台数据源的'均匀'是做给用户看的,不是做给管道用的;谁先做测量、谁先把切分和分域做进架构,谁的下游就少一半口径事故。随着更多数据进入流通和训练环节,'测量先行'会从个人开发者的偏执,变成数据团队的基本功。

本文由本站 AI 辅助聚合生成,原始来源如下:

🔎 本文基于以下资讯(素材溯源 · 信息来源)

📰 相关阅读推荐(与本文相关的其他资讯)