基于scrapy_redis爬虫框架实现布隆过滤器

概述:

  • scrapy_redis去重使用的是redis集合,是将请求数据以sha1加密之后的加密值存入redis集合,通过redis集合来实现去重,去重数据量可以在千万级别以上,至于具体的数值就看硬件了。但是对现在的各家大数据公司而言,数据需求往往不是1两个G能解决的,在数据量太大之后,redis的去重压力会很大,甚至会挂掉。为了提高去重上限,满足我们爬虫的需求实现基于scrapy_redis构建以布隆过滤器为核心的去重。

下面先来段科普(关于布隆过滤器):

《基于scrapy_redis爬虫框架实现布隆过滤器》 image

  • 布隆过滤器[1](Bloom Filter)是由布隆(Burton Howard Bloom)在1970年提出的。它实际上是由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率(假正例False positives,即Bloom Filter报告某一元素存在于某集合中,但是实际上该元素并不在集合中)和删除困难,但是没有识别错误的情形(即假反例False negatives,如果某个元素确实没有在该集合中,那么Bloom Filter 是不会报告该元素存在于集合中的,所以不会漏报)。

  • 在日常生活中,包括在设计计算机软件时,我们经常要判断一个元素是否在一个集合中。比如在字处理软件中,需要检查一个英语单词是否拼写正确(也就是要判断 它是否在已知的字典中);在 FBI,一个嫌疑人的名字是否已经在嫌疑名单上;在网络爬虫里,一个网址是否被访问过等等。最直接的方法就是将集合中全部的元素存在计算机中,遇到一个新 元素时,将它和集合中的元素直接比较即可。一般来讲,计算机中的集合是用哈希表(hash table)来存储的。它的好处是快速准确,缺点是费存储空间。当集合比较小时,这个问题不显著,但是当集合巨大时,哈希表存储效率低的问题就显现出来 了。比如说,一个象 Yahoo,Hotmail 和 Gmai 那样的公众电子邮件(email)提供商,总是需要过滤来自发送垃圾邮件的人(spamer)的垃圾邮件。一个办法就是记录下那些发垃圾邮件的 email 地址。由于那些发送者不停地在注册新的地址,全世界少说也有几十亿个发垃圾邮件的地址,将他们都存起来则需要大量的网络服务器。如果用哈希表,每存储一亿 个 email 地址, 就需要 1.6GB 的内存(用哈希表实现的具体办法是将每一个 email 地址对应成一个八字节的信息指纹(详见:googlechinablog.com/2006/08/blog-post.html), 然后将这些信息指纹存入哈希表,由于哈希表的存储效率一般只有 50%,因此一个 email 地址需要占用十六个字节。一亿个地址大约要 1.6GB, 即十六亿字节的内存)。因此存贮几十亿个邮件地址可能需要上百 GB 的内存。除非是超级计算机,一般服务器是无法存储的[2]。(该段引用谷歌数学之美:http://www.google.com.hk/ggblog/googlechinablog/2007/07/bloom-filter_7469.html

我的认识跟理解

  • 算法:
    1. 首先需要k个hash函数,每个函数可以把key散列成为1个整数
    2. 初始化时,需要一个长度为n比特的数组,每个比特位初始化为0
    3. 某个key加入集合时,用k个hash函数计算出k个散列值,并把数组中对应的比特位置为1
    4. 判断某个key是否在集合时,用k个hash函数计算出k个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

  • 优点:不需要存储key,节省空间

  • 缺点:
    1. 算法判断key在集合中时,有一定的概率key其实不在集合中
    2. 无法删除

  • 误报:
    布隆过滤器会:这个url肯定存在,或者这个url肯定不存在,或者这个url可能存在。会出现误报,但是不会报错,针对不同的应用场景,这有可能会是一个巨大的缺陷,亦或是无关紧要的问题。如果在检索元素是否存在时不介意引入误报情况,那么你就应当考虑用布隆过滤器。

  • 简单实现(在我的github的bloomfilter_demo.py):

    《基于scrapy_redis爬虫框架实现布隆过滤器》 image2.png

在scrapy_redis的布隆过滤基本实现流程介绍

  • 布隆过滤器封装在py_bloomfilter.py中,基于redis.第三方依赖:mmh3–下载命令: pip install mmh3(用来实现hash的函数类库).
  • bloom_dupefilter.py 来重写scrapy_redis的去重策略.
  • settings.py配置修改,如下图,跟scrapy_redis的配置格式基本相同,不过需要把去重的类改成我们自己重写的DUPEFILTER_CLASS.

《基于scrapy_redis爬虫框架实现布隆过滤器》 image.png

  • 使用爬虫流程跟scrapy_redis的操作相同,去重数据会在我们的布隆过滤器交互的redis里。
  • 我的py_bloomfilter.py跟bloom_dupefilter.py路径放置如下图:

《基于scrapy_redis爬虫框架实现布隆过滤器》 image1.png

github地址:https://github.com/NewPersonNew/BigWarter

    原文作者:不完整的蛋_47b6
    原文地址: https://www.jianshu.com/p/4400446ac2f3
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞