之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,制止重复抓取,以节流资源和时间。
在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。
另一种思绪:将增量判断放在调度中心,爬虫节点只负责抓取。即调度中心维护URL的状态,当需要抓取时(新URL或需要更新),才将URL分发给爬虫节点。
所以说,实现分布式爬虫的增量爬取,关键在于高效去重、状态同步和更新检测。以下就是我整理的核心方案和技能要点:
一、增量爬取核心思绪
- 只抓取新内容/更新内容
- 新URL(未爬过的页面)
- 已爬URL但内容更新(如消息更新、商品代价变动)
- 制止重复爬取
二、技能实现方案
1. URL去重(识别新页面)
- 布隆过滤器(Bloom Filter)
- 内存占用低,适合海量URL判重(存在轻微误判率)。
- 工具:RedisBloom、PyBloom。
- 分布式键值存储
- 用Redis记载已爬URL(SET 或 HyperLogLog)。
- 示例代码(Redis检查URL):
- import redis
- r = redis.Redis(host='redis-cluster', port=6379)
- def is_url_new(url):
- if r.sadd("crawled_urls", url) == 1: # 成功添加说明是新URL
- return True
- return False
复制代码
- 持久化存储
- 数据库(如MySQL)存储URL + 时间戳,适合精确去重。
2. 内容更新检测(识别页面变更)
- 哈希比对
- 对页面内容盘算哈希值(如MD5),存储哈希值与URL关联。
- 重新爬取时对比新老哈希值。
- HTTP缓存机制
- 请求头添加 If-Modified-Since(时间戳)或 ETag。
- 若服务端返回 304 Not Modified,跳过下载。
- 版本号/时间戳
- 某些网站API返回数据的更新时间(如 last_updated 字段)。
3. 分布式协同
- 中央任务队列
- 所有爬虫节点从同一队列(如RabbitMQ/Kafka)获取任务。
- 队列只推送未爬取或需更新的URL。
- 分布式锁
- 更新共享状态(如Redis中的URL记载)时用RedLock制止冲突。
- 同一状态存储
- 使用Redis/数据库存储全局爬取状态(URL、哈希值、时间戳)。
三、架构设计示例
- 调度中心
- 管理初始URL、解析新URL、检查更新。
- 向任务队列分发URL。
- 爬虫节点
- 从队列消费URL,下载页面。
- 盘算内容哈希,与存储的旧值比对。
- 若内容更新,推送新数据到存储层。
- 存储层
- Redis:存储URL集合、内容哈希、布隆过滤器。
- 数据库:持久化存储最终数据。
四、优化计谋
- 增量频率控制
- 对频仍更新的网站设置短间隔(如每10分钟检测一次)。
- 静态网站可延长检测周期(如1天)。
- 容错机制
- 失败URL重试队列(指数退避重试)。
- 分布式事务保证状态一致性。
- 去重压缩
- 对URL进行标准化(去除参数、归一化)。
- 存储URL哈希而非原始URL(节流空间)。
五、工具推荐
- 爬虫框架:Scrapy + Scrapy-Redis(分布式支持)。
- 存储:Redis(去重)、MySQL/PostgreSQL(布局化数据)。
- 消息队列:RabbitMQ、Kafka、Redis Streams。
- 布隆过滤器:RedisBloom、pybloom-live。
六、伪代码流程
- # 爬虫节点逻辑
- def crawl(url):
- # 1. 检查URL是否已爬(Redis去重)
- if not is_url_new(url):
- return
-
- # 2. 发送请求(带If-Modified-Since/ETag)
- headers = {"If-Modified-Since": last_crawled_time(url)}
- response = requests.get(url, headers=headers)
-
- # 3. 处理响应
- if response.status_code == 304:
- return # 内容未更新
- elif response.status_code == 200:
- content = response.text
- new_hash = md5(content)
-
- # 4. 比对内容哈希
- if new_hash != old_hash(url):
- save_data(content) # 存储新数据
- update_hash(url, new_hash) # 更新哈希值
-
- # 5. 解析新链接加入队列
- for new_url in extract_links(content):
- push_to_queue(new_url)
复制代码 总结:
分布式增量爬虫 = 全局去重(布隆过滤器/Redis) + 内容更新检测(哈希/HTTP缓存) + 任务协同(消息队列)。关键在于通过共享存储实现多节点状态同步,这样我们才气确保高效识别新内容与变更。
|