scrapy自带去重策略:
scrapy通过request_fingerprint函数,对Request对象生成指纹,看注释:
# 该函数在scrapy/utils/request.py文件中 def request_fingerprint(request, include_headers=None): if include_headers: include_headers = tuple(to_bytes(h.lower()) for h in sorted(include_headers)) cache = _fingerprint_cache.setdefault(request, {}) if include_headers not in cache: fp = hashlib.sha1() """计算指纹时,请求方法(如GET、POST)被计算在内""" fp.update(to_bytes(request.method)) """下面这句有意思,canonicalize_url()将url规范化,意味着 http://www.example.com/query?id=111&cat=222 http://www.example.com/query?cat=222&id=111 这样参数位置变化,但参数值不变的网址,表示的仍是同一个网址,符合现实逻辑。 """ fp.update(to_bytes(canonicalize_url(request.url))) """request.body的属性是字符串: 一般GET方法的body为空字符串,不考虑; 而POST方法要上传一个字典data(类型是dict), 要经过urllib.parse.urlencode()函数转换后才能变成request.body """ fp.update(request.body or b'') if include_headers: for hdr in include_headers: if hdr in request.headers: fp.update(hdr) for v in request.headers.getlist(hdr): fp.update(v) cache[include_headers] = fp.hexdigest() return cache[include_headers] """我们甚至可以根据需求将request.meta的内容作为指纹计算的一部分"""
scrapy生成的唯一指纹,存在内存的一个集合里,即set。如果下一次请求产生的指纹在这个set里面,请求被判定为重复,这次请求就被忽略,也就是所谓的去重了。
示例演示自带去重
# 指纹去重,用的集合,对url地址取指纹(md5),放到集合中 from scrapy.utils.request import request_fingerprint from scrapy import Request r1=Request(url='http://www.baidu.com/?name=lqz&age=18') r2=Request(url='http://www.baidu.com/?age=18&name=lqz') ret1=request_fingerprint(r1) ret2=request_fingerprint(r2) print(ret1) print(ret2)
第三方去重:布隆过滤器
安装:
#python3.6 安装 #需要先安装bitarray pip3 install bitarray-0.8.1-cp36-cp36m-win_amd64.whl(pybloom_live依赖这个包,需要先安装) #下载地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/ pip3 install pybloom_live
使用:
在爬虫项目下新建py文件
qc.py
from scrapy.dupefilters import BaseDupeFilter from pybloom_live import ScalableBloomFilter class UrlFilter(BaseDupeFilter): def __init__(self): self.bloom = ScalableBloomFilter(initial_capacity=100, error_rate=0.001, mode=ScalableBloomFilter.LARGE_SET_GROWTH) def request_seen(self, request): if request.url in self.bloom: return True self.bloom.add(request.url)
settings.py中配置
DUPEFILTER_CLASS = 'cnblogs.qc.UrlFilter' # 使用自定义的