实测 100 万个 URL 的去重结构:set 存完整 URL 128.0 MiB,存 64 位哈希 66.3 MiB,Bloom 过滤器 1% 误判率只要 1.1 MiB;Bloom 实测误判 1.036%(理论 1.004%),加到 3 倍容量时误判升到 43.6%;32 位哈希在 100 万个里就有 127 个撞车。
构造一个响应取决于方法、请求体、Accept-Language 和 Cookie 的本机服务器:180 个请求有 131 种不同的内容;只哈希 URL 去重只拿到 62 种、漏掉 69 种(40 个 Accept-Language 版本、10 个 Cookie 版本、19 个 POST 请求体);把方法、请求体、关键请求头都放进指纹才拿到全部 131 种。
用合成语料量 SimHash 近似去重:只对正文做时,原文与改 5% 的变体汉明距离中位 4、不相关的两篇中位 18,k=3 召回 47.6%、误报 0;把共用的站点模板一起做,不相关的两篇距离中位降到 6,k=3 误报 37005 对;改用词的 3 元组特征后距离分布整体拉开。
在一个带四类陷阱(无限日历、URL 里的随机 sid、288 种筛选参数组合、相对链接循环)的本机站点上真实抓取:无防御抓 2000 个页面浪费 1738 个;去掉 sid 把预算转给日历陷阱;每个 URL 模板最多 50 个只找到 103 / 263 真实页;放宽到 300 并配合去 sid 和路径重复检测才找到全部且结束。
在抓取过程中让数据不断新增和删除:偏移量分页(最新在前)返回 1148 条中重复 148 条,随机删除时漏掉 59 条;最旧在前仍然漏掉 46 条;游标分页和快照分页在新增、删除、新增加删除三种变化下都没有重复也没有漏掉。
实测条件请求对爬虫增量抓取的作用:200 KB 页面带正确 If-None-Match 得到 304 且响应体 0 字节;100 个页面第二遍,10 个更新,响应体从 19.5 MiB 降到 2.0 MiB;Last-Modified 不变时 304 会错过更新;同一页面重复访问 100 次,max-age 内只需要 1 个请求。
实测 sitemap.xml 解析:不写 XML 命名空间会解析出 0 条;.xml.gz 文件要自己解压而 Content-Encoding: gzip 由 requests 解开;lastmod 有多种写法,没有 lastmod 的条目不能用来增量;5 万条 URL 用 iterparse 内存 4.0 MiB 对 fromstring 38.5 MiB;lxml 恢复模式会悄悄破坏含 & 的 URL。
60 个商品各有 5 种地址加 10 个分页列表页(共 310 个 URL,70 种内容):只规范化 URL 剩 130 组;信任 canonical 61 组但把 10 个不同的分页合成一组;canonical 加内容校验和只看正文哈希都得到正好 70 组;整页字节哈希因为页脚时间戳合并不了(310 组)。
以真实 Chrome 154 解析出的 DOM 为标准答案,22 个残缺 HTML 片段:selectolax(Lexbor)和 bs4 + html5lib 22 / 22 一致,html5lib 21 / 22,lxml.html 与 bs4 + lxml 12 / 22,bs4 + html.parser 只有 6 / 22;差别包括是否补 tbody、是否拆开嵌套的 <a>、重复属性取第一个还是最后一个、</br> 是否变成 <br>。
在同一个页面上比较 XPath 与 CSS 选择器:16 个选取任务中 CSS 能写 13 个、写不了按文字选/选父元素/选祖先 3 个;XPath 里匹配 class 用 @class="item" 只选到 1 个、contains 多选到 4 个、带空格的写法才与 CSS 的 3 个一致;//a[1] 与 (//a)[1] 差 6 个对 1 个;5000 个 li 的页面上两者耗时都在 2.7–3.1 ms,无稳定差别。
实测大 HTML 的解析内存:整棵树净增约文件的 11–19 倍(100 MiB 文件 1122–1649 MiB);iterparse 不清理等同整树且更慢(22.63 秒);iterparse 加 clear() 和删前面的兄弟只净增文件的约 1.1 倍(114 MiB),耗时 3.04 秒;给没声明编码的文件要传 encoding,否则「¥」变成「Â¥」。
实测爬虫文本清洗:nbsp 和全角空格能被 strip/split/\s 处理,零宽空格、BOM、软连字符不能;NFKC 能把全角转半角,但也把 x² 变成 x2、① 变成 1;NFC 与 NFD 的 café 显示一样却不相等;不清洗时正则把「¥12,345」读成 12 而不是 12345。