先给结论:当查询参数可以被无限拼接时,不存在一份“完整地址清单”可以穷举;有效地址集合只能由你定义的一组规范化规则和取舍边界来圈定,而不是由爬虫抓到的数量决定。换句话说,你定义的是“哪些地址算同一个资源、哪些参数允许进入集合、哪些组合直接丢弃”,而不是等待集合自己长完。
参数组合之所以无限,是因为它由笛卡尔积生成:只要有两个以上可选参数,每个参数又有多个取值,组合数就会随参数个数相乘。排序、筛选、分页、会话、追踪这几类参数叠在一起,组合数可以轻易到天文量级。此时任何“全量枚举”的做法都只是把问题推迟。
所以第一步不是写规则,而是确定集合的用途。用于站点地图时,集合应只保留能被独立检索、且内容确实不同的地址;用于爬虫预算分配时,集合应保留所有可能被抓取且值得被抓取的地址;用于日志分析时,集合可以更宽,但要能反向归并到规范形式。用途不同,边界就不同,不能共用一份清单。
有效地址集合的核心不是枚举,而是等价类。对每个地址做一次规范化,把“指向同一资源的多种写法”折叠成一个代表地址,集合的元素就是这些代表。可执行的动作顺序如下:
做完这一步,你会得到一个可去重的集合。它的规模取决于白名单里放了多少参数和取值,而不是原始组合数。这里的关键取舍是:白名单越宽,集合越接近真实资源但越容易膨胀;越窄,越可控但可能把不同内容误判为同一个。判断依据是参数是否改变页面主体内容,而不是参数是否出现在地址里。
假设某个列表页有三个参数:sort(取值 asc、desc)、page(正整数)、ref(任意来源标记)。如果全部枚举,仅 page 一项就无上界,组合无限。
按用途取舍:ref 不影响内容,直接丢弃;sort 改变结果顺序但内容集合相同,是否保留取决于你希望搜索引擎看到哪种排序,通常只保留一个默认值;page 改变内容,需要保留,但必须设上界,例如只保留到实际存在内容的最后一页。这样集合从无限变为“1 × 页数”的有限规模。
这个例子的假设前提是:分页内容确实逐页不同,且没有其他隐藏参数影响输出。如果实际页面用前端渲染、分页由脚本生成,那么抓取到的地址可能根本不代表真实内容,此时应先解决渲染可见性,再谈集合定义,否则规范化只是把错误折叠得更整齐。
集合定义完成后,不要用“抓到了多少地址”来证明它正确。数量归零或暴涨都有多种合理解释:可能是参数被丢弃,也可能是抓取被限制,也可能是页面本身不再输出链接。更可靠的做法是抽样验证等价关系:
如果抽样中大量出现“同键不同内容”,说明白名单太窄,需要把某个参数加回;如果出现“不同键同内容”,说明白名单太宽,应继续折叠。这个动作的结果直接决定下一步:是收紧还是放宽规则,而不是继续扩大抓取。
定义好的集合最终通常写进站点地图或抓取规则。这里有两个边界必须写清:站点地图列出地址不保证被收录,它只是提交候选;robots.txt 限制抓取也不等于可靠的索引移除,被限制的地址仍可能因外部链接而被索引。因此不要把“集合已提交”当成“集合已被处理”。
另外,如果同一批地址分布在多个搜索引擎或平台,支持情况要分别核查,不能假设一套规则通用。集合的定义可以共享,但生效范围必须逐个确认。
回到最初的问题:有效地址集合不是一个等待被穷举的客观总量,而是你根据用途、规范化规则和抽样验证共同划定的一份有限代表清单;规则变,集合就变,所以真正需要维护的是规则本身,以及验证它是否仍然成立的抽样动作。