scrapy的去重规则

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'   # 使用自定义的
原文地址:https://www.cnblogs.com/baicai37/p/13449716.html