dupefilter.py

负责执行requst的去重,实现的很有技巧性,使用的Redis的设定数据结构。但是注意调度并不使用其中用于在这个模块中实现的dupefilter键做请求的调度,而是使用queue.py模块中实现的队列。

当请求不重复时,将其存入到队列中,调度时将其弹出。

import logging
import timefrom scrapy.dupefilters import BaseDupeFilter
from scrapy.utils.request import request_fingerprintfrom .connection import get_redis_from_settingsDEFAULT_DUPEFILTER_KEY = "dupefilter:%(timestamp)s"logger = logging.getLogger(__name__)# TODO: Rename class to RedisDupeFilter.
class RFPDupeFilter(BaseDupeFilter):"""Redis-based request duplicates filter.This class can also be used with default Scrapy's scheduler."""logger = loggerdef __init__(self, server, key, debug=False):"""Initialize the duplicates filter.Parameters----------server : redis.StrictRedisThe redis server instance.key : strRedis key Where to store fingerprints.debug : bool, optionalWhether to log filtered requests."""self.server = serverself.key = keyself.debug = debugself.logdupes = True@classmethoddef from_settings(cls, settings):"""Returns an instance from given settings.This uses by default the key ``dupefilter:<timestamp>``. When using the``scrapy_redis.scheduler.Scheduler`` class, this method is not used asit needs to pass the spider name in the key.Parameters----------settings : scrapy.settings.SettingsReturns-------RFPDupeFilterA RFPDupeFilter instance."""server = get_redis_from_settings(settings)# XXX: This creates one-time key. needed to support to use this# class as standalone dupefilter with scrapy's default scheduler# if scrapy passes spider on open() method this wouldn't be needed# TODO: Use SCRAPY_JOB env as default and fallback to timestamp.key = DEFAULT_DUPEFILTER_KEY % {'timestamp': int(time.time())}debug = settings.getbool('DUPEFILTER_DEBUG')return cls(server, key=key, debug=debug)@classmethoddef from_crawler(cls, crawler):"""Returns instance from crawler.Parameters----------crawler : scrapy.crawler.CrawlerReturns-------RFPDupeFilterInstance of RFPDupeFilter."""return cls.from_settings(crawler.settings)def request_seen(self, request):"""Returns True if request was already seen.Parameters----------request : scrapy.http.RequestReturns-------bool"""fp = self.request_fingerprint(request)# This returns the number of values added, zero if already exists.added = self.server.sadd(self.key, fp)return added == 0def request_fingerprint(self, request):"""Returns a fingerprint for a given request.Parameters----------request : scrapy.http.RequestReturns-------str"""return request_fingerprint(request)def close(self, reason=''):"""Delete data on close. Called by Scrapy's scheduler.Parameters----------reason : str, optional"""self.clear()def clear(self):"""Clears fingerprints data."""self.server.delete(self.key)def log(self, request, spider):"""Logs given request.Parameters----------request : scrapy.http.Requestspider : scrapy.spiders.Spider"""if self.debug:msg = "Filtered duplicate request: %(request)s"self.logger.debug(msg, {'request': request}, extra={'spider': spider})elif self.logdupes:msg = ("Filtered duplicate request %(request)s"" - no more duplicates will be shown"" (see DUPEFILTER_DEBUG to show all duplicates)")msg = "Filtered duplicate request: %(request)s"self.logger.debug(msg, {'request': request}, extra={'spider': spider})self.logdupes = False

这个文件看起来比较复杂,重写了scrapy本身已经实现的请求判重功能。因为本身scrapy单机跑的话,只需要读取内存中的请求队列或者持久化的请求队列(scrapy默认的持久化似乎是json格式的文件,不是数据库)就能判断这次要发出的请求url是否已经请求过或者正在调度(本地读就行了)。而分布式跑的话,就需要各个主机上的scheduler都连接同一个数据库的同一个请求池来判断这次的请求是否是重复的了。

在这个文件中,通过继承BaseDupeFilter重写他的方法,实现了基于Redis的的判重。根据源代码来看,scrapy,Redis的使用了scrapy本身的一个指纹接request_fingerprint,这个接口很有趣,根据scrapy文档所说,他通过哈希来判断两个网址是否相同(相同的URL会生成相同的哈希结果),但是当两个网址的地址相同,得到型参数相同但是顺序不同时,也会生成相同的散列结果(这个真的比较神奇......)所以scrapy-redis的依旧使用URL的指纹来判断请求请求是否已经出现过。

这个类通过连接redis的,使用一个密钥来向redis的的一个设置中插入指纹(这个密钥对于同一种蜘蛛是相同的,redis的是一个键 - 值的数据库,如果密钥是相同的,访问到的值就是相同的,这里使用蜘蛛名字+ DupeFilter的关键就是为了在不同主机上的不同爬虫实例,只要属于同一种蜘蛛,就会访问到同一个组,而这个组就是他们的网址判重池),如果返回值为0,说明该设定中该指纹已经存在(因为集合是没有重复值的),则返回假,如果返回值为1,说明添加了一个指纹到集合中,则说明这个请求没有重复,于是返回真,还顺便把新指纹加入到数据库中了。DupeFilter判重在调度类中用,每一个请求在进入调度之前都要进行判重,如果重复就不需要参加调度,直接舍弃就好了,不然就是白白浪费资源。

源码分析参考:Dupefilter相关推荐

  1. 源码分析参考:Spider

    spider.py 设计的这个spider从redis中读取要爬的url,然后执行爬取,若爬取过程中返回更多的url,那么继续进行直至所有的request完成.之后继续从redis中读取url,循环这 ...

  2. 源码分析参考:Scheduler

    scheduler.py 此扩展是对scrapy中自带的scheduler的替代(在settings的SCHEDULER变量中指出),正是利用此扩展实现crawler的分布式调度.其利用的数据结构来自 ...

  3. 源码分析参考:Connection

    官方站点:https://github.com/rolando/scrapy-redis scrapy-redis的官方文档写的比较简洁,没有提及其运行原理,所以如果想全面的理解分布式爬虫的运行原理, ...

  4. 源码分析参考:Queue

    queue.py 该文件实现了几个容器类,可以看这些容器和redis交互频繁,同时使用了我们上边picklecompat中定义的序列化器.这个文件实现的几个容器大体相同,只不过一个是队列,一个是栈,一 ...

  5. 源码分析参考:Pipelines

    pipelines.py 这是是用来实现分布式处理的作用.它将Item存储在redis中以实现分布式处理.由于在这里需要读取配置,所以就用到了from_crawler()函数. from scrapy ...

  6. SpringMVC异常处理机制详解[附带源码分析]

    SpringMVC异常处理机制详解[附带源码分析] 参考文章: (1)SpringMVC异常处理机制详解[附带源码分析] (2)https://www.cnblogs.com/fangjian0423 ...

  7. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | LoadedApk 源码分析 )

    文章目录 一.LoadedApk 源码分析 二.LoadedApk 源码 makeApplication 方法分析 dex 解密时 , 需要将 代理 Application 替换为 真实 Applic ...

  8. 【Android 安全】DEX 加密 ( Application 替换 | Android 应用启动原理 | ActivityThread 源码分析 )

    文章目录 一.ActivityThread 源码分析 二.ActivityThread 部分代码示例 dex 解密时 , 需要将 代理 Application 替换为 真实 Application ; ...

  9. csi-provisioner源码分析

    本文个人博客地址:https://www.huweihuang.com/kubernetes-notes/develop/csi-provisioner.html 本文主要分析csi-provisio ...

最新文章

  1. 电子科技大学通信原理视频教程 瓦特芯收藏
  2. tensorflow 官方文档中文版 tensorflow教程 tensorflow教学
  3. 【数据结构与算法】之深入解析二叉树的算法实现和递归套路深度实践
  4. ai背景合成_智能合成AI主播很危险,应立即取消!
  5. sqlite简单介绍
  6. 三角形最佳路径问题(信息学奥赛一本通-T1288)
  7. 回顾一下Unix哲学
  8. opengl绘制的点不显示是什么原因_中考后为什么不允许复读?原因主要在以下5点,你都清楚吗?...
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的旅游景点门票售票管理系统
  10. [原创] 图片操作的类(ImageLibrary)-按比例缩放图片
  11. 返回通知异常通知环绕通知
  12. Python发邮件的小脚本
  13. python 小数乘法_《包装》——小数乘法
  14. 小票打印机 linux 驱动下载,POS58小票机驱动下载
  15. 软件设计与体系结构:设计过程
  16. swarm bzz 安装0.5.3,和节点引导
  17. centos检测不到磁盘_IBM服务器安装CentOS找不到硬盘的解决方法
  18. bzoj4816 Sdoi2017 数字表格
  19. 信息安全等级保护概述
  20. 计算机网络练习3|河工|周老师

热门文章

  1. oracel 创建视图给某个用户
  2. create-react-app教程-源码篇
  3. 深入学习SpringMVC以及学习总结
  4. EmptyPage(空白页组件)原理与使用
  5. Skype 释出新的 Linux 客户端
  6. MYSQL数据库查询删除创建企业基本知识
  7. STL --- UVA 123 Searching Quickly
  8. 苹果账号:个人,公司,企业,教育,
  9. TypeScript入门教程 之 生成器函数
  10. Docker Swarm 初步认识 及 集群搭建