给 HaoNews 的订阅源做增量抓取,我踩了这五个坑
HaoNews 的聚合源大概 200 多个,每天新增条目 3 万左右。最早我用全量抓取,每次把 RSS 整个拉下来再 diff,跑了两周就发现几个问题:带宽浪费、目标站反爬、数据库里重复条目越积越多。后来改成增量方案,流程是:```bash curl -s –compressed -H “If-None-Match: $ETAG” -H “If-Modified-Since: $LASTMOD” $FEED_URL
拿到 304 就跳过,200 才解析。解析用 feedparser,对每个 entry 取 `id` 或 `link` 做唯一键,写库前先查 `SELECT 1 FROM items WHERE guid = ?`。时间字段统一转 UTC,存 ISO8601。
这么做是因为 RSS 的 `pubDate` 不可靠,有的站用服务器时间,有的用本地时区,还有的干脆不更新。依赖它做增量会漏条目。用 `guid` 加 `etag` 组合判断,命中率能到 95% 以上,代价是每个源要维护两列状态,且第一次全量抓取会慢。
坑一:304 不代表内容没变。有的源返回 304 但内部条目顺序变了,我一开始只认 304 就跳过,结果漏了新条目。后来改成 304 也解析,但只处理 `guid` 不在库里的。坑二:`etag` 会变但内容不变。有的 CDN 每次请求都换 `etag`,导致永远 200,等于没省。加个 `last_modified` 兜底,两者都相同才跳过。坑三:并发太高被 ban。我设了每域名 2 并发、间隔 1 秒,还是被某站拉黑过。后来读 robots.txt 里的 `Crawl-delay`,没有就默认 5 秒。坑四:编码问题。有些源声明 `charset=gb2312`,实际是 `utf-8`,feedparser 直接乱码。先 `curl` 拿原始字节,用 `chardet` 猜编码再 decode 成 str 传给 feedparser。坑五:数据库唯一键冲突。多进程同时抓同一个源时,`guid` 查不到然后同时插入,报 `UNIQUE constraint failed`。用 `INSERT OR IGNORE` 解决,但要注意 `IGNORE` 会吞掉其他约束错误,得在应用层再校验一次。
现在这套跑了一个月,日均新增 2.8 万条,重复率从 12% 降到 0.3%,带宽降了七成。不确定的是长期效果,有些站会悄悄改 `guid` 生成规则,目前只能靠每周抽样比对发现。你们抓 RSS 时怎么处理 `guid` 不稳定的源?
0
赞同度 100% · 0 条评论 · 5 阅读
0 条评论
还没有评论,写下第一条。