返回介绍

15.4 Scrapy 爬虫去重

发布于 2025-04-21 19:15:31 字数 1706 浏览 0 评论 0 收藏

15.4.1 Scrapy 去重方案

前面多次提到过 Scrapy 的 URL 去重。使用 scrapy.Request 方法时,可以设置 dont_filter 参数来开启或者关闭 Scrapy 对 request 的 URL 去重,执行如下命令即可。

yield scrapy.Request(url, callback=self.parse, dont_filter=False)

这是 Scrapy 框架默认使用的 URL 去重方式,它实质上是通过 Python 的 set() 这种数据结构在内存中实现去重。当服务器宕机或强制关闭爬虫时,这样的去重方式无法保存 request 状态,另外,这种内存去重方式有一个明显的缺点:随着 URL 的增多,占用的内存会越来越多,当长时间执行大型爬虫任务时,服务器内存很有可能被占满。

上一节介绍 scrapy_redis 时提到过,它可以帮助用户使用 Redis 中的队列去重,这也是一种内存去重方案,但通过 Redis 实现了去重的持久化。这种方式既能保证服务器重启或宕机后重新继续去重,又能保证较快的去重速度。这种方案基本上能满足大多数爬虫需要,是一种相对理想的去重方式。

还可使用关系型数据库去重,这种去重方式把已经爬取的 URL 存入数据库,每次在新的请求之前启动数据库查询。这种去重方式在数据量非常庞大后,查询效率很低,对服务器资源占用较大。

其实,Redis 缓存数据库去重是一种不错的去重方式,但是当爬虫数据量达到亿(甚至十亿、百亿)数量级时,内存有限,Redis 缓存数据库去重方案就不能满足要求了。这时可以考虑用“位”来去重,Bloom Filter 过滤就是将去重对象映射到几个内存“位”,通过几个位的 0/1 值来判断某个对象是否已经存在。

15.4.2 Bloom Filter 过滤

Bloom Filter 是一种空间效率很高的随机数据结构,它利用位数组很简洁地表示一个集合,能判断一个元素是否属于这个集合。Bloom Filter 的这种高效是有一定代价的:在判断一个元素是否属于某个集合时,不属于这个集合的元素很可能被误认为属于这个集合。因此,Bloom Filter 不适合那些“零错误”的应用场合。而在能容忍低错误率的应用场合下,Bloom Filter 通过极少的错误,换取了存储空间的极大节省。

Bloom Filter 运行在一台机器的内存上,不方便持久化,也不方便分布式爬虫的统一去重。在部署大型爬虫时,可以使用 scrapy_redis 配合 Bloom Filter 过滤,这样就能满足既占用较小内存又能持久化去重的目标,并且执行速度也足够快。因此,如果希望减少内存的占用,对去重的要求又不是那么高,对大型分布式爬虫,可以考虑使用 scrapy_redis 和 Bloom Filter 过滤这样的组合。

可以在 Python 官网搜索,看看有没有已经实现 Bloom Filter 的包。输入 Bloomfilter,搜索结果如图 15-10 所示。

图 15-10 Python 官网搜索 Bloomfilter

可以看到已经有现成的改造 scrapy_redis 实现 Bloom Filter 的包 scrapy-redisbloomfilter 0.7.0,这应该是国人编写的一个使用布隆过滤去重的 scrapy_redis 包。可以直接使用 pip 安装这个包,然后就像前面讲过的使用 scrapy_redis 包那样部署分布式爬虫。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。