Scrapy框架-去重原理讲解、数据收集以及信号量知识
scrapy的去重原理
【知其然且知其所以然,才能够更好的理解这个框架,而且在使用和改动的时候也能够想出更合理的方法。】
(开始测试前,到settings.py中注释掉下载中间件的设置,这里用jobbole爬虫来测试,所以之前写的调用chrome的两个方法init和spider_closed都要注释掉。)
这里你们可以用自己的爬虫来测试,不一定要按我的来测试。
到scrapy源码包
[项目\Lib\site-packages\scrapy\dupefilters.py]
里面找去重的代码,RFPDupeFilter类就是去重器,里面有个方法叫做request_seen,它在scheduler(发起请求的第一时间)的时候被调用。它代码里面调用了request_fingerprint方法(就是给request生成一个指纹),连续两次跟进代码就进入到了request.py文件的request_fingerprint方法中,方法中有一句代码:
fp = hashlib.sha1() … … cache[include_headers] = fp.hexdigest()
就是给每一个传递过来的url生成一个固定长度的唯一的哈希值。这种量级千万到亿的级别内存是可以应付的。
然后看到init方法:
def __init__(self, path=None, debug=False): self.file = None self.fingerprints = set() self.logdupes = True self.debug = debug self.logger = logging.getLogger(__name__) if path: self.file = open(os.path.join(path, 'requests.seen'), 'a+') self.file.seek(0) self.fingerprints.update(x.rstrip() for x in self.file)
里面有一句代码 self.fingerprints = set(),就是通过set集合的特点(set不允许有重复值)进行去重。
可以用断点调试的方法进行跟踪查看。
Telnet
Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式。它为用户提供了在本地计算机上完成远程主机工作的能力。在终端使用者的电脑上使用telnet程序,用它连接到服务器。终端使用者可以在telnet程序中输入命令,这些命令会在服务器上运行,就像直接在服务器的控制台上输入一样。可以在本地就能控制服务器。要开始一个telnet会话,必须输入用户名和密码来登录服务器。Telnet是常用的远程控制Web服务器的方法。
可以用这个在本地操控远程的scrapy,telnet是默认开启的,当scrapy运行的时候,会自动开启端口,运行框会有显示:
[scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023
我们可以通过cmd连接测试。
要测试,就要开启windows电脑的telnet功能。在控制面板-程序与功能-启用或关闭windows功能,找到Telnet服务和客户端,打上勾即可。
linux系统也是默认没有Telnet的,需要安装,比如我的Deepin系统就需要用命令安装:
sudo apt-get install telnet
先运行scrap有,然后在cmd(linux在终端输入)中输入:
telnet localhost 6023
连接成功后会显示:
>>>
符号,我们输入est()可以查看当前scrapy的运行状态等属性。官方文档有Telnet的相关介绍,里面包括有一些可用的变量/查看引擎状态/暂停,恢复和停止scrapy/终端信号/设置等内容。
Telnet的源码在site-package/scrapy/extensions目录下的telnet.py文件中。
数据收集器
官方文档中有对数据收集器的介绍.
数据收集器可以应用在很多地方,举例子:如果你想知道scrapy总共发出了多少个request请求;或者你想记录总共发起了多少次yeild,都可以用数据收集器记录,它不用打开,默认可以直接使用。
在jobbole爬虫的JobboleSpider类里面新增代码:
# 收集jobbole.com所有的500、404页面及页面数量 handle_httpstatus_list = [500,404] def __init__(self): self.fail_urls = []
然后到parse方法中新增代码:
if response.status == 500 or response.status == 404: self.fail_urls.append(response.url) self.crawler.stats.inc_value("failed_url")
就可以实现对页面数量和页面url的收集,可以自定义保存.
信号
scrapy的中间件与通信都是通过信号来传递的,官网有文档
可以在您的Scrapy项目中捕捉一些信号(使用 extension)来完成额外的工作或添加额外的功能,扩展Scrapy。
信号提供了一些参数,不过处理函数不用接收所有的参数 - 信号分发机制(singal dispatching mechanism)仅仅提供处理器(handler)接受的参数。
代码演示:
from scrapy.xlib.pydispatch import dispatcher from scrapy import signals def parse(self, response): """ 正式进入爬取区域 """ dispatcher.connect(self.handler_spider_closed, signals.spider_closed) def handler_spider_closed(self, spider, reason): print("这个名为:" + spider.name + "的爬虫已经关闭了,原因是:" + reason)
得到的输出结果是在爬虫关闭后:
'start_time': datetime.datetime(2018, 1, 20, 3, 5, 49, 791339)} 2018-01-20 11:05:51 [scrapy.core.engine] INFO: Spider closed (finished) 这个名为:dongmeng的爬虫已经关闭了,原因是:finished
dispatcher.connect监听爬虫signals(信号),当收到爬虫关闭(signals.spider_closed)的信号时,调用handler_spider_closed方法。而handler_spider_closed我只是简单的编写了一个关闭的原因而已,还可以做更深入的操作。
由此可以看出,爬虫的信号监听和状态操作可以做很多的事情,比如打开爬虫时、爬虫空闲时可以收集当前request请求队列、记录404页面数量或者200状态的页面有那些、多少条等。
扩展
官方文档对扩展有介绍:
扩展框架提供一个机制,使得你能将自定义功能绑定到Scrapy。
扩展只是正常的类,它们在Scrapy启动时被实例化、初始化。
scrapy里面的中间件都是一种扩展。
为了更好的理解扩展,这里用源码跟踪的形式来理解,到[项目/Lib/site-packages/scrapy/extensions]目录下找到corestats.py文件。
from_crawler方法里面记录了很多的信号量:
@classmethod def from_crawler(cls, crawler): o = cls(crawler.stats) crawler.signals.connect(o.spider_opened, signal=signals.spider_opened) crawler.signals.connect(o.spider_closed, signal=signals.spider_closed) crawler.signals.connect(o.item_scraped, signal=signals.item_scraped) crawler.signals.connect(o.item_dropped, signal=signals.item_dropped) crawler.signals.connect(o.response_received, signal=signals.response_received) return o
下面对应都写着具体的执行方法。比如spider_opened爬虫启动的时候就会:
def spider_opened(self, spider): self.stats.set_value('start_time', datetime.datetime.utcnow(), spider=spider)
记录爬虫启动的时间。
还有spider_closed关闭爬虫的时候就会:
def spider_closed(self, spider, reason): self.stats.set_value('finish_time', datetime.datetime.utcnow(), spider=spider) self.stats.set_value('finish_reason', reason, spider=spider)
记录下关闭时间和关闭的原因等。
到[项目/Lib/site-packages/scrapy/extensions]memusage.py文件是监控内存使用的。里面有一串代码:
crawler.signals.connect(self.engine_started, signal=signals.engine_started) crawler.signals.connect(self.engine_stopped, signal=signals.engine_stopped)
是主要的绑定项
比如这个engine_started方法开始就记录内存使用信息。
self.crawler = crawler self.warned = False self.notify_mails = crawler.settings.getlist('MEMUSAGE_NOTIFY_MAIL') self.limit = crawler.settings.getint('MEMUSAGE_LIMIT_MB')*1024*1024 self.warning = crawler.settings.getint('MEMUSAGE_WARNING_MB')*1024*1024 self.check_interval = crawler.settings.getfloat('MEMUSAGE_CHECK_INTERVAL_SECONDS') self.mail = MailSender.from_settings(crawler.settings)
里面的大概意思就是设置了监控内存的定时时间/不同状态的操作等,可以在engine_started里面加逻辑,想对内存干什么就干什么。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
主流分布式架构的风流韵事...
一、前言 上篇文章,我们聊到了分布式架构的演进过程,那本文我们就来聊一聊目前主流的分布式架构以及分布式架构中常见理论以及如何才能设计出高可用的分布式架构好了。分布式架构中,SOA和微服务架构是最常见两种分布式架构,而且目前服务网格的概念也越来越火了。那我们本文就先从这些常见架构开始。 二、SOA架构解析 SOA 全称是: Service Oriented Architecture,中文释义为 “面向服务的架构”,它是一种设计理念,其中包含多个服务, 服务之间通过相互依赖最终提供一系列完整的功能。各个服务通常以独立的形式部署运行,服务之间 通过网络进行调用。架构图如下: 跟 SOA 相提并论的还有一个 ESB(企业服务总线),简单来说 ESB 就是一根管道,用来连接各个服务节点。ESB的存在是为了集成基于不同协议的不同服务,ESB 做了消息的转化、解释以及路由的工作,以此来让不同的服务互联互通; 随着我们业务的越来越复杂,会发现服务越来越多,SOA架构下,它们的调用关系会变成如下形式: 很显然,这样不是我们所想要的,那这时候如果我们引入ESB的概念,项目调用就又会很清晰,如下: SOA所...
- 下一篇
流式架构与反应式编程总述
TODO
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Hadoop3单机部署,实现最简伪集群
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Docker使用Oracle官方镜像安装(12C,18C,19C)