爬虫工作量由小到大的思维转变---<第六十四章 > Scrapy利用Bloom过滤器增强爬虫的页面去重效率

前言:

        网络爬虫系统是信息时代获取和管理网络数据的重要工具,广泛应用于搜索引擎索引、数据聚合、在线研究等领域。随着网络信息的海量增长,爬虫系统不可避免地会面临重复内容的爬取问题。这不仅浪费了计算资源和网络带宽,而且还会降低数据处理的效率,并可能引起网站服务的负载增加。因此,有效的去重策略对提升爬虫性能至关重要。

        去重的传统方法,如哈希表和数据库索引,虽然在小规模数据集上表现良好,但当处理大量数据时,对内存和计算能力的需求急副增长,这成为了一个技术挑战。为应对这一挑战,Bloom过滤器以其高效的空间和时间性能特性,成为了一个有力的替代方案。该数据结构允许误差出现,以显著降低内存使用,其通过多个哈希函数映射元素,在保持较低错误率的前提下,完成高速且节省空间的去重任务。然而,尽管Bloom过滤器的优势显著,它在实际的爬虫系统如Scrapy框架中的集成和应用则相对较为复杂,且鲜有文献陈述。

        因此,我将Bloom过滤器应用于Scrapy爬虫框架中的可行性和效果,对提升爬虫系统中的去重策略进行研究,期望为大家提供指导和参考。

正文:

1.系统设计与实现

1.1 对Scrapy的去重机制的分析

        Scrapy框架中的去重机制依靠DUPEFILTER来实现。DUPEFILTER作为Scrapy中的去重过滤器,用于判定抓取的URL是否被重复访问。它默认支持内存去重,使用Python的集合存储已访问的请求指纹,每个URL都会计算一个SHA1指纹存入集合中在大型爬虫应用中,这会导致内存使用迅速增加,严重影响性能。

2.3 Bloom过滤器在Scrapy中的实现方法

        Bloom过滤器是一个空间效率极高的概率型数据结构,用于判断一个元素是否存在于一个集合之中。其基础版本由一个大型的二进制向量和一系列随机映射函数构成,每次插入或查询时,都会通过同样的哈希函数序列计算出位数组中的若干位置,并对位数组进行相应的读写操作。尽管存在一定的误判率,Bloom过滤器以牺牲准确性为代价,换取了内存使用方面的显著优势

在Scrapy中实现Bloom过滤器作为一个新的去重组件,需要覆盖默认的DUPEFILTER。实现这一功能的步骤如下:

  1. Bloom过滤器的设计与构建:确定过滤器大小和哈希函数数量等参数,影响误差率与内存使用量。
  2. 在Scrapy项目中集成Bloom过滤器类:创建一个Bloom过滤器类,实现 request_seen 方法,用以替代原来的去重逻辑。
  3. 存储与持久化:相比于内存中纯粹的集合,需要一种方式让Bloom过滤器持久化存储,实现断点续抓功能。
  4. 性能与稳定性测试:在Scrapy项目中进行测试,评估Bloom过滤器在内存使用和去重速度上的表现。
  5. 参数调优:根据测试结果和实际需求,调整Bloom过滤器的参数,达到最佳性能与资源使用平衡。
  6. 误差处理:考虑到Bloom过滤器的误判率,设计机制处理误差产生的情况,比如通过降低误判率、或者二次检验的方法。

通过在Scrapy框架中实现Bloom过滤器,可以在不牺牲太多准确性的前提下,显著减少去重环节对资源的消耗,尤其是在内存占用方面。这改进了Scrapy爬虫在处理大规模数据时的性能,为大数据爬取、搜索引擎构建等应用场景提供了理想的解决方案。

2. 网页去重的关键问题

2.1 传统去重方法的局限性

        传统的网页去重技术,尽管在小型系统中效果良好,但在扩展至互联网规模数据时,其局限性逐渐显现。这主要表现在三个方面:

  1. 首先,依赖数据库的去重机制增加了I/O操作的时间开销,对性能造成影响;
  2. 其次,去重所需内存随着数据量增加而增加,可能超过服务器的物理内存限制;
  3. 最后,去重处理过程较慢,减缓了爬虫的爬取速度。策略如哈希表、有序数组等在处理海量数据时也面临空间与性能瓶颈。
2.2 Bloom过滤器的概率性去重及其挑战

        Bloom过滤器作为一种概率型数据结构,其在空间效率上具有明显优势。然而,概率性去重也带来了数据误判的问题,具体包括假阳性(False Positive),即非成员被错误地判断为是集合成员的情形。在实际的爬虫应用中,假阳性可能导致有效页面被错过,从而影响数据的准确性和爬虫的完整性。

2.3 解决误判和哈希函数选择的方法

        减少误判和选择适合的哈希函数对去重效果至关重要。策略包括细致调整Bloom过滤器的大小和哈希函数个数,使用多重哈希来分散元素的位置分布,选择无冲突的哈希函数以降低错误率。此外,可以预先估计数据量大小采用动态扩展策略,或者采用计数Bloom过滤器来允许删除操作,从而适应不断变化的数据集。

3. 测试与效果评估

3.1 爬取任务的设置

        为了评估并比较Bloom过滤器与传统去重策略,在实验之初应设置具有代表性的爬取任务。任务设定应尽可能模拟真实世界的网页爬取,设置爬取深度、目标网站量级和爬取频率等参数,并确保两种策略在相同的任务设置下进行。

3.2 传统去重与Bloom过滤器去重的对比实验

        对比实验是通过在同一爬取任务设置下,运行两种去重机制,并记录其性能表现。对于传统去重方法,记录数据结构的增长情况、内存使用量、去重判断所需的平均时间。对于Bloom过滤器,则关注假阳性率、内存使用效率和处理速度。

3.3 评估指标:内存使用、准确性、爬取速度

对爬取过程的评价主要基于以下模标:

  • 内存使用:量化两种方法在处理大规模数据集时的内存消耗。
  • 准确性:分析假阳性的发生率,以及如何影响爬取的质量和覆盖面。
  • 爬取速度:评价实际爬取效率,统计处理每个URL或者页面的平均时间。

这些评估指标对于优化爬虫,平衡资源消耗和数据准确性具有重要意义。通过这些指标,可以判断Bloom过滤器在实际网页去重任务中的实用性,并为未来的优化工作提供依据。

4. 案例分析

4.1 实际爬取项目中的应用

        在现实世界的爬取项目中,例如挖掘特定领域的新闻数据,去重变得至关重要。考虑一个使用Scrapy进行新闻网站爬取的项目,该项目中,我们使用Python实现了一个高效的Bloom过滤器,并将其集成到Scrapy的去重中间件中。

# Python中Bloom过滤器的一个简单实现
class BloomFilter:def __init__(self, size, hash_count):self.bit_array = bitarray(size)self.bit_array.setall(0)self.size = sizeself.hash_count = hash_countdef add(self, url):points = [self.hash_n(url, n) for n in range(self.hash_count)]for b in points:self.bit_array[b] = 1def contains(self, url):points = [self.hash_n(url, n) for n in range(self.hash_count)]return all(self.bit_array[b] for b in points)def hash_n(self, item, n):return (hash1(item) + n * hash2(item)) % self.size# Scrapy中间件利用Bloom过滤器
from scrapy.dupefilters import BaseDupeFilterclass BloomDupeFilter(BaseDupeFilter):def __init__(self, path=None, debug=False):self.bloom_filter = BloomFilter(size=100000, hash_count=3)def request_seen(self, request):if self.bloom_filter.contains(request.url):return Trueself.bloom_filter.add(request.url)return False

        首先创建了一个Bloom过滤器的类,通过使用两个哈希函数生成了多个散列表索引,并且在处理URL去重时使用这些索引。接着,我们在Scrapy框架中实现了Bloom过滤器作为一个去重的中间件组件,使Scrapy在进行网页爬取时,可以通过Bloom过滤器来检查每个请求是否唯一。

4.2 性能提升的分析

        在任何爬虫项目中,性能是一个核心考量。使用Bloom过滤器作为去重机制,能显著减少内存的占用,同时也加快了去重检查的效率。通过实施时间和空间的对比测试,我们可以量化Bloom过滤器带来的性能提升。例如,在爬取具有一百万个唯一页面的新闻网站时,相较于传统去重数据结构(如Python集合),Bloom过滤器能够降低内存用量高达90%以上,同时保持合理的误判率(一般小于1%)。

4.3 正误判数据的处理

尽管Bloom过滤器提供了卓越的性能,它天生的误判率也带来了新的挑战。在实际项目中采用后处理措施,例如:

# 如果Bloom过滤器判断URL已看到,可用二级检验如数据库查询确认
if bloom_filter.contains(request.url):if not database.contains(request.url):process_request(request)

这种二级验证策略,即使在Bloom过滤器发生误判时也能保证重要页面不会被忽略。同时,误判处理策略需要记录下所有的误判实例,并通过日志揭示模式,为将来调整Bloom过滤器的参数提供数据支持。

5. Bloom过滤器的应用案例

5.1 配置Bloom过滤器设置

        在Scrapy项目中配置Bloom过滤器,首先需要确定参数设置,包括位数组的大小和哈希函数的个数。这些参数的设定应根据预期抓取的URL数量以及可接受的误判率作出决定。举例说,如果想要爬取大约一百万个URL,而将误判率控制在1%以下,可以使用以下配置:

# 100万个元素,误判率0.01的Bloom过滤器参数
# 这些参数可以使用在线Bloom过滤器计算器获得
bloom_filter_size = 9585058  
hash_count = 7

有了这些参数,我们便可以在Scrapy项目中集成Bloom过滤器。具体实现方式如下:

from bitarray import bitarray
import mmh3class BloomFilter:# ... 前面的BloomFilter类实现def hash_n(self, item, n):return mmh3.hash(item, n) % self.sizeclass CustomDupeFilter(BaseDupeFilter):# ... 前面的BloomDupeFilter类实现# scrapy项目的设置.py
DUPEFILTER_CLASS = 'myproject.custom_filters.CustomDupeFilter'
5.2 在Scrapy Request去重

在Scrapy项目中,当调度器从爬虫发出的请求接收到一个新请求时,去重中间件首先检查这个请求是否被Bloom过滤器看到过。若已经被看到,则该请求被视为重复,否则它将被添加到过滤器中并继续正常处理。

class CustomSpider(scrapy.Spider):name = 'custom_spider'def start_requests(self):# 初始化请求for url in self.start_urls:yield scrapy.Request(url, self.parse, dont_filter=True)def parse(self, response):# 处理响应

此时,任何经过CustomDupeFilter被标记为重复的请求都不会交给parse方法处理。

5.3 在Item Pipeline去重

对于已经收集的数据,可能会出现多个请求生成相似或重复的Item。在Item Pipeline环节,Bloom过滤器同样可以进行去重处理,例如:

class ItemPipeline:def __init__(self):self.filter = BloomFilter(size=bloom_filter_size, hash_count=hash_count)def process_item(self, item, spider):item_unique_str = item['unique_attribute']if self.filter.contains(item_unique_str):raise DropItem("Duplicate item found: %s" % item)else:self.filter.add(item_unique_str)# 进行后续pipeline process...return item

在这个例子中,我们依据项的唯一属性,结合Bloom过滤器执行去重检测。如果发现重复项,将其丢弃,否则将其传递到pipeline的下一个阶段。

综上所述,Bloom过滤器在Scrapy中的应用,可以有效地实现请求级和项级的去重功能,从而提高整个爬虫项目的效率和数据质量。实践中的应用案例展示了Bloom过滤器如何在Scrapy项目的不同阶段提供去重功能,并且如何通过合理的参数配置来优化其性能和使用效果。

总结:

        网络爬虫在处理大规模数据时面临内存和性能挑战,传统的去重方法显得力不从心。Bloom过滤器凭借高空间效率和时间效率的优点,提出了一个解决方案,虽然它引入了概率性误判的可能性,但在许多应用场景中其优势仍然显著。

        从Scrapy的默认去重机制出发,深入到Bloom过滤器的实现,并将其集成至Scrapy,展现了在实际爬虫项目中的应用如何大幅提高去重效率,降低资源消耗。通过参数调优、存储策略、稳定性测试等多维度分析和实践探索,我们得出了对比传统方法时Bloom过滤器所带来的显著性能提升的结论。尤其在系统资源有限、数据量巨大的背景下,Bloom过滤器表现出巨大的应用潜力和拓展前景。

        最后,通过具体案例分析和应用示例,说明了如何在Scrapy项目中配置和运用Bloom过滤器来去重请求和项目,确保了数据的唯一性、准确性以及爬取效率!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/783576.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

24计算机考研调剂 | 中国航天科工集团第三研究所第八三五八研究所

中国航天科工集团第三研究院第八三五八研究所 2024年航天科工集团三院8358所调剂基本要求 一、8358所坐落天津,为定向招生(毕业后留所工作); 二、本年度拟调剂名额4-5人; 三、我所接收符合条件的调剂考生:…

代码第三十五天-子集Ⅱ

子集Ⅱ 题目要求 解题思路 回溯法 一般情况下,看到题目要求[所有可能的结果],而不是[结果的个数],我们就知道需要暴力搜索所有的可行解了,可以使用[回溯法] 回溯法是一种算法思想,而递归式一种编程方式,回…

Cesium实现渐变面

一、效果图 二、实现思路 使用着色器,通过纹理坐标和其他参数计算出材质的颜色和透明度。通过给定的颜色、漫反射强度和透明度,计算出最终的反射颜色和透明度,并且根据给定的中心点位置和当前像素的纹理坐标,计算出距离中心的距离…

C++未格式化的输入/输出操作,流随机访问

未格式化的输入/输出操作 到目前为止&#xff0c;我们的程序只使用过格式化IO操作。输入和输出运算符(<<和>>)根据读取或写入的数据类型来格式化它们。输入运算符忽略空白符&#xff0c;输出运算符应用补白、精度等规则。 标准库还提供了一组低层操作&#xff0c;…

(一)kafka实战——kafka源码编译启动

前言 本节内容是关于kafka消息中间键的源码编译&#xff0c;并通过idea工具实现kafka服务器的启动&#xff0c;使用的kafka源码版本是3.6.1&#xff0c;由于kafka源码是通过gradle编译的&#xff0c;以及服务器是通过scala语言实现&#xff0c;我们要预先安装好gradle编译工具…

[已解决]ModuleNotFoundError: No module named ‘triton‘

问题描述&#xff1a;ModuleNotFoundError: No module named triton window下难以编译&#xff0c;直接下载win版本已经编译的&#xff1a; https://huggingface.co/r4ziel/xformers_pre_built/blob/main/triton-2.0.0-cp310-cp310-win_amd64.wh

每日一练 找无重复字符的最长子串

我们来看下这个题目&#xff0c;我们要统计的是不重复的子串&#xff0c;我们可以使用“滑动窗口法”&#xff0c;其实我们很容易就能想到思路。 我们的左窗代表我们目前遍历的开始&#xff0c;即我们遍历的子串的开头&#xff0c;右窗从左窗开始进行遍历&#xff0c;每次遍历…

【C语言终章】预处理详解(上)

【C语言终章】预处理详解&#xff08;上&#xff09; 当你看到了这里时&#xff0c;首先要恭喜你&#xff01;因为这里就是C语言的最后一站了&#xff0c;你的编程大能旅途也将从此站开始&#xff0c;为坚持不懈的你鼓个掌吧&#xff01; &#x1f955;个人主页&#xff1a;开敲…

04-MySQL数据库-权限管理

一、查看权限 1&#xff0c;查看系统所有权限 mysql> show privileges; 权限字段介绍 privileges #权限名称 context #对象&#xff0c;表示可以对数据库&#xff0c;那些资源、进行哪些操作&#xff1b; comment #描述&#xff0c;备注解释说明&#xff1b; Grant…

Caddy之静态站点应用场景

一、背景与介绍 无意之中看到公司部门的软件介质下载站点不是使用Nginx部署&#xff0c;而是使用Caddy。就比较好奇了&#xff0c;这个Caddy是个什么东西? 为啥他们没用Nginx呢&#xff0c;带着好奇心搜索了一下相关资料。 官方解释: Caddy is a powerful, extensible platfo…

Redis 事务 与 管道

redis事务 谈到事务大家可能就会想起mysql中的事务 注意这里的事务不是指的是事务的四大特性acid 持久性 原子性 隔离性 一致性 事务的概念就是 一组命令,串行化执行而不被打断 这里redis的事务和mysql的事务就不太一样 传统关系型数据库的事务主要强调的是一个没有执行完成就…

neo4j使用详解(六、cypher常用函数语法——最全参考)

Neo4j系列导航&#xff1a; neo4j及简单实践 cypher语法基础 cypher插入语法 cypher插入语法 cypher查询语法 cypher通用语法 cypher函数语法 4.常用函数 主要包括谓词函数&#xff08;断言函数&#xff09;、标量函数、聚合函数、字符串函数以及集合函数 4.1.谓词函数&#…

数据结构--循环链表(C语言实现)

一.循环链表的设计 typedef struct CNode{ int data; struct CNode* next; }CNode ,*CList; 2.循环链表的示意图: 3.循环链表和单链表的区别: 唯一区别,没有空指针,尾节点的后继为头,为循环之意. 二.循环链表的实现 //初始化return true; }//返回key的前驱地址&#xff0c;如果…

Lazarus远控组件NukeSped分析

静态信息&#xff1a; 样本md5&#xff1a;9b656f5d7e679b94e7b91fc3c4f313e4 由此可见为假的Adobe Flash Player 的攻击样本 样本分析 通过五个函数&#xff0c;内部调用sub_40159D函数动态获取API函数 利用IDA python解密字符串。。 完整python代码 Python> idc.get_…

MongoDB副本集环境搭建(以单机Windows为例)

前言 近期有搭建MongoDB副本集的需求,简单记录一下搭建过程(以本地Windows环境为例)。 一、副本集选型 1 Primary节点、1 Secondary 节点、1 Arbiter节点模式副本集环境搭建。 二、搭建过程 1. 安装MongoDB服务 下载地址:https://www.mongodb.com,如下图所示: 选择…

android 13 相册和拍照问题

android 在13以下。拍照和从相册选取图片需要使用 存储权限&#xff0c;相机权限。 在使用时候 需要声申请 Manifest.permission.WRITE_EXTERNAL_STORAGEManifest.permission.CAMERA 这2个权限。 但是在android 13以及以上时候&#xff0c;不需要申请 Manifest.permission…

基于Springboot旅游网站管理系统设计和实现

基于Springboot旅游网站管理系统设计和实现 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞 收藏 ⭐留言 文末获取源码联系…

7.卷积神经网络与计算机视觉

计算机视觉是一门研究如何使计算机识别图片的学科&#xff0c;也是深度学习的主要应用领域之一。 在众多深度模型中&#xff0c;卷积神经网络“独领风骚”&#xff0c;已经被称为计算机视觉的主要研究根据之一。 一、卷积神经网络的基本思想 卷积神经网络最初由 Yann LeCun&a…

UE4_碰撞_自定义碰撞检测通道

效果如图&#xff1a; 1、项目设置中新建追踪检测通道weapon&#xff0c;默认值为忽略。 2、新建几个actor作为枪&#xff0c;碰撞预设全部设为自定义&#xff0c;把新建的检测响应weapon设为阻挡。 3、角色进行射线检测 运行效果如下&#xff1a; 发现有些物体碰不到&#xff…

GetSystemTimes:获取CPU占用率(WIN API)

原文链接&#xff1a;https://blog.csdn.net/qq_28742901/article/details/104960653 GetSystemTimes函数&#xff1a; BOOL WINAPI GetSystemTimes(__out_opt LPFILETIME lpIdleTime, // 空闲时间__out_opt LPFILETIME lpKernelTime, // 内核进程占用时间__out_opt LPFILETI…