Bloom Filter替换Scrapy-Redis集合去重
Scrapy-Redis源码解析传送门
Scrapy-Redis在dupefilter.py文件中主要使用Redis集合来保存Request的指纹,提供重复过滤。
dupefilter.py文件修改
修改其中的request_seen()方法。
def request_seen(self, request):
fp = self.request_fingerprint(request)
added = self.server.sadd(self.key, fp)
return added == 0
fp:获取Request的指纹。
added:通过Redis的set来保存fp,added返回添加的结果成功返回1,然后和0进行判断,返回Flase就是成功。
修改后的request_seen()方法。
def request_seen(self, request):
fp = self.request_fingerprint(request)
if self.bf.exists(fp):
return True
self.bf.insert(fp)
return False
fp:获取Request的指纹
再通过BloomFilter的exists方法来判断是否存在,返回True就是存在,不存在的话就调用insert来插入fp返回Flase。
初始化函数
修改之前。
def __init__(self, server, key, debug=False):
self.server = server
self.key = key
self.debug = debug
self.logdupes = True
我们首先创建一个bloomfilter.py文件将我们实现的BloomFilter和HashMap导入进去。
from .bloomfilter import BloomFilter
def __init__(self, server, key, debug, bit, hash_number):
self.server = server
self.key = key
self.debug = debug
self.bit = bit
self.hash_number = hash_number
self.logdupes = True
self.bf = BloomFilter(server, self.key, bit, hash_number)
主要添加了bit移动的位数和hash_number散列函数的个数,然后就是调用BloomFilter类进行实例化。
from_setting()传递参数
其中bit和hash_number的参数需要使用from_setting()方法来传递。
@classmethod
def from_settings(cls, settings):
server = get_redis_from_settings(settings)
key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
debug = settings.getbool('DUPEFILTER_DEBUG')
return cls(server, key=key, debug=debug)
首先在defaults.py文件中添加变量。
BLOOMFILTER_HASH_NUMBER = 6
BLOOMFILTER_BIT = 30
DUPEFILTER_DEBUG = False
修改之后的方法的内容。
@classmethod
def from_settings(cls, settings):
server = get_redis_from_settings(settings)
key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
debug = settings.getbool('DUPEFILTER_DEBUG', DUPEFILTER_DEBUG)
bit = settings.getint('BLOOMFILTER_BIT', BLOOMFILTER_BIT)
hash_number = settings.getint('BLOOMFILTER_HASH_NUMBER', BLOOMFILTER_HASH_NUMBER)
return cls(server, key=key, debug=debug, bit=bit, hash_number=hash_number)
然后返回一个类实例。
这样就实现了Bloom Filter和Scrapy-Redis的对接。
使用
我们只修改了存常量参数的文件,修改都是在dupefilter文件中,修改了request_seen方法,还有初始化函数以及from_settings方法。添加了bloomfilter.py文件。
我们在使用的时候和Scrapy-Redis的方法一样都是在Scrapy的setting.py文件中添加配置,以上的修改是在源码中进行的,通过运行可以发现存储的格式是String类型,不是set类型类。