caimouse
在IT行业有20多年的经验。拥有20多年的C和C++开发经验,5年以上Python开发经验,资深数据库开发、上百G数据库优化经验。曾经任职嵌入式工程师、P2P开发工程师、银行信用卡交易系统工程师、全自动化电池测试部门经理。
展开
-
爬虫日记(108):Twisted:使用后悔药
有时候有一些操作发送出去了,但是不再需要做,这样就需要使用后悔药。比如前面的诗歌代理服务器,当一个客户端连接过来获取诗歌内容,但是由于服务器下载很慢,但是客户端等不起了,决定关闭连接,这时候连接服务器的异步代码调用还没有返回,所以阻塞在那里。这种情况下,代理服务器就要取消从服务器下载任何内容了,因为客户端已经不存在,即使下载也没有什么用了。此时此刻就是使用后悔药的好时候,在Twisted里就是使用Deferred的取消操作。对于同步的代码,要取消比较困难,因为它是阻塞在那里,需要使用别的线程来触发。原创 2021-08-07 11:16:40 · 271 阅读 · 0 评论 -
爬虫日记(107):Twisted:使用生成器构造回调函数
之前我们学习关于装饰器@inlineCallbacks的使用,它可以把生成器函数处理成回调函数,它是根据生成器函数的异步特性来设计的,如下图:所以把生成器变成异步回调函数,就非常简单了。我们来看第一个例子:def my_generator(): print('starting up') yield 1 print("workin'") yield 2 print("still workin'") yield 3 print...原创 2021-08-06 18:36:02 · 251 阅读 · 0 评论 -
爬虫日记(106):Twisted:单元测试怎么样编写
前面学习了很多Twisted框架的代码,也能够实现了比较多功能,但是这些代码都没有编写单元测试的,因此这些代码的正确性并不能保证,同时由于没有单元测试,当项目比较大时,无法保证软件按时测试完成,所以就不能按时发布了。由此可见,单元测试是必须的,并且能够自动化地测试。由于Twisted里使用是异步的框架,如果直接使用同步代码的测试框架是不行的,也就是使用python里自带的测试框架是不行的,而是需要使用Twisted的测试框架trial。Trial测试框架的调用过程如下:根据上面的框架的设原创 2021-08-06 17:16:13 · 237 阅读 · 0 评论 -
爬虫日记(105):Twisted:怎么样处理一个函数同步代码返回和异步对象返回
在开发的过程中,会碰到这样一种情况,比如开发一个代理软件,要实现这样一个功能,当代理软件的内存里有对应的诗歌内容时,就可以直接返回给客户端,如果没有对应的诗歌内容,就需要向服务器去下载。在使用Twisted来实现这样一个函数时,就会发现有一个问题,就是当诗歌存在时,它是立即返回内容,这是同步代码的形式,而当没有诗歌时,它需要向别的服务器请求下载,这是不可能立即得到内容返回,因此是异步调用的过程。由此来看,要实现这个函数,必须把同步调用和异步调用合并到一起,那么采用Twisted又是怎么样实现的呢?要原创 2021-08-06 11:16:59 · 233 阅读 · 0 评论 -
爬虫日记(104):Twisted:客户端实现双向传送协议
前面实现了一个转换服务器的功能,它就是把客户端的发送过来的诗歌内容进行小写转换,然后再把转换之后的内容发送回去给客户端,这是一种RPC的调用过程。也是目前比较热门的微服务的变种。虽然这个例子比较简单,但是它实现了服务器的双向传送的功能,也演示了Twisted开发服务器的便捷性。有了服务器,那么我们就需要开发一个客户端才可以访问这个服务器了。在开发的过程中,我们面临着两个问题,第一个问题就是需要向多个服务器进行通讯,第二个问题是两个服务器之间进行的处理需要进行协调,比如下载诗歌服务器要先进行连接并进行下载,并原创 2021-08-05 18:46:25 · 334 阅读 · 0 评论 -
爬虫日记(103):Twisted:服务器实现双向传送协议
前面实现的诗歌服务器,主要实现下载的功能,这样比较简单,但是一般服务器要求实现双向传送的功能,这样才可让服务器实现客户端需要的功能。比如像简单的远程调用,通过协议让服务器进行诗歌转换之后再传送给客户端。为了实现这样的服务器,需要引入一个双向传送的协议,把前面的服务器更进一步改造。在这里采用了Netstring,这个协议是一个简单的文本协议,它有用下面的格式:[长度]:[内容]前面是冒号后面的字符串的长度。例如,表示一个字符串"hello world!",它会被转换成这样:<31 3原创 2021-08-04 18:33:53 · 242 阅读 · 0 评论 -
爬虫日记(102):Twisted:使用Deferred重构服务器代码
前面实现了一个诗歌下载的服务器,采用socket底层来实现的,这样比较关注底层的细节,并且还是一个阻塞的服务器,这样服务器的性能肯定不会太好。接着下来,重构这个服务器的代码。原来服务器的代码:# This is the blocking version of the Slow Poetry Server.import optparse, os, socket, timedef parse_args(): usage = """usage: %prog [options] poet原创 2021-08-04 10:57:39 · 233 阅读 · 0 评论 -
爬虫日记(101):Twisted:使用Deferred重构异常代码
我们经常会写同步的代码,并且喜欢使用异常来处理结果,这样的习惯是训练出来的。什么东西都需要等有确定的结果再做下一步,比如下面的异常处理代码: def try_to_cummingsify(poem): try: return cummingsify(poem) except GibberishError: raise except: print('Cummingsif...原创 2021-07-22 18:31:57 · 225 阅读 · 0 评论 -
爬虫日记(100):Twisted:使用Deferred重构回调函数管理
前面的例子可以看到下载诗歌的例子里,使用回调函数来进行实现客户端的代码,这样需要传送两上回调函数进去,接着下来我们使用已经学习的Deferred类来管理回调函数,就不必要传送回调函数了,这样让代码更加简单,并且容易管理。例子如下:# This is the Twisted Get Poetry Now! client, version 4.0import optparse, sysfrom twisted.internet import deferfrom twisted.interne原创 2021-07-22 16:56:19 · 228 阅读 · 0 评论 -
爬虫日记(99):Twisted的Deferred重新审视
在前面的例子可以看到,回调函数是事件循环框架异步编程的基本方式,只有使用回调函数才能把用户的代码,插入到框架的事件循环里运行,这是所有事件循环框架的基本要求,也是它的基本内容,因此Twisted框架也不例外,它的基本开发方式就是编写一串又一串的回调函数链,让整个回调管理更加方便。由前面的例子来看,最简单的回调处理,就有两个回调函数:一个是正常的回调,一个是错误的回调。我们要成为Twisted的开发人员,就要思考怎么样让这些回调函数更加容易管理,避免一些陷阱。Twisted为了管理回调函数方便原创 2021-07-22 11:47:22 · 231 阅读 · 0 评论 -
爬虫日记(98):Twisted的使用回调更简单
在前面已经学习了使用一个下载诗歌的客户端,而这个客户端使用了传送层、协议、协议工厂类的抽象,这样更加方便框架的抽象能力,适用更多类型的应用。由于前面的例子实现还是有点复杂,可以对它进一步修改,可以改为这样:# This is the Twisted Get Poetry Now! client, version 2.1.# NOTE: This should not be used as the basis for production code.import optparsefrom t原创 2021-07-22 09:11:45 · 218 阅读 · 0 评论 -
爬虫日记(97):Twisted的更高级的抽象层
前面使用学习了下载诗歌的客户端程序,不过使用的是底层的网络socket来实现,这是一个可行的方案,不过使用此方案需要自己注意更多的细节,还需要适应不同的平台,这些都是麻烦人的事情。为了解决这个问题,我们应该尽量使用twisted的更高级的抽象层,这样才可以让代码写得更少,让代码写得更稳定,让代码更加复用,让代码更加明白。今天就来研究一下怎么样来解决这个问题。前面也使用了对象来进行回调,这时引入了接口,只要实现相应的接口,就可以让twisted调用你的对象。因此接口是twisted的抽象层表现,后面会原创 2021-07-17 11:57:20 · 253 阅读 · 0 评论 -
爬虫日记(96):Twisted的通过对象进行回调
前面通过例子来演示怎么样通过函数的方式来进行回调,这样的方式是比较简单的,如果函数比较少,或者函数之间的状态比较少,就可以使用这种方式来进行。如果函数之间比较密切,还有一些状态共享的,就需要使用对象来实现回调。而对象的代码是在独立在twisted框架之外,又是怎么样被框架认识的呢?在这里提前说明一下,显然通过接口的方式。也就是说框架会指定一系列接口,只要那个对象实现这些接口,就可以满足框架的调用要求了。至于具体是什么接口,就需要查看框架的定义。先来运行一下这个使用twisted实现下载诗歌的客户端,原创 2021-07-16 18:04:21 · 230 阅读 · 0 评论 -
爬虫日记(95):Twisted开发异步程序基础
前面测试过多台服务器的情况下,如果使用同步客户端程序来下载,就会比较慢,要等一个服务器完成了才能下载另外一个文件,后面采用异步的客户端就比较快,可以与三台服务器同步进行下载。由于是客户端程序里自己使用select函数来实现的,只能专注于网络socket的事件,如果要使用到别的应用程序就不行了,所以twisted把这种方式进行抽象,进行封装,就可以应用到别的应用程序。接着下来将学会使用twisted来编写异步的下载诗歌的应用程序,在这之前先来学会最简单的twisted的写法,如下:from twisted原创 2021-07-16 15:30:54 · 277 阅读 · 0 评论 -
爬虫日记(94):Twisted的reactor设计来源
前面已经学习过twisted使用单线程异步模型来设计整个框架,接着下来比较一下同步模型的网络程序和reactor设计的异步网络程序。首先来创建一个阻塞的服务器,让服务器有一些延时间,并且可以按我们要求来发送字节大小,这样就方便来测试同步模型和异步模型。因此先来创建一个服务器的程序slowpoetry.py,这个程序主要提供一些诗歌下载:# This is the blocking version of the Slow Poetry Server.import optparse, os, so原创 2021-07-16 11:20:31 · 250 阅读 · 0 评论 -
爬虫日记(93):Twisted的设计模型
由于scrapy的代码采用twisted的框架来设计,因此需要继续来学习twisted的内容,才可以更加深入地了解scrapy的代码实现方式,以及借鉴scrapy的代码来开发自己的项目,或者在scrapy里添加新的内容。我们知道程序运行有以下几种模型:顺序执行、异步执行、多线程执行,接着下来比较一下这几个模型的优缺点:这个单线程同步执行的模型,这三个任务是按顺序执行,每一个任务完成了才执行下一个,这是python里最基本的开发模式,这种方式比较简单,只需要一个线程,在这个线程里同一个时间只会原创 2021-07-16 09:24:55 · 237 阅读 · 0 评论 -
爬虫日记(92):Scrapy的下载结果回应分析
前面分析了HTTP协议发起请求的过程,这个过程是比较复杂的,因为要处理的东西比较多,不但要处理代理的问题,还需要处理协议的数据,以及设置回调的过程。这么多东西放在一起,肯定是比较难理解的。如果一遍看不懂,就要多看几遍了。接着下来,就是当从服务器返回结果时,又是怎么样来处理的呢,我们现在还不清楚是怎么样的一个过程,我们需要带着这个问题来去看代码,就可以找到这个结果。为了理解返回结果的回调过程,需要先来看一下下面这个例子:#爬虫日记-蔡军生(qq:9073204)#https://mysoft.原创 2021-07-15 11:59:31 · 249 阅读 · 0 评论 -
爬虫日记(91):Scrapy的ScrapyAgent类
从前面的HTTP11DownloadHandler类分析可知,它是调用ScrapyAgent类来处理具体的HTTP或HTTPS的协议来下载网页数据。如下调用过程:因此我们需要来分析ScrapyAgent类,才明白它是怎么样来下载HTTP或HTTPS协议的数据,以及整个的实现过程,同时对于想使用Twisted的HTTP的功能也是有帮助的,因为它演示了怎么样调用Twisted的功能,实现了数据成功之后处理,以及失败的处理过程。第280行保存Twisted中的Agent,这个用来实..原创 2021-07-14 22:31:37 · 268 阅读 · 0 评论 -
2021年最新 apache 2.4 + flask + python3.7 + windows的部署
由于近来开发了一个套flask的WEB服务器,需要给客户端部署安装,又由于客户是一个中小企业,他们的管理人员有限,因此不采用Linux服务器,所以必须部署在windows服务器上,这样也为他们节省管理成本,因为linux要专职的管理人员,而windows可以自己员工兼职管理一下。所以我们必须把这个问题解决了,如果在Linux上部署有很多现成的方案,但是在Windows上部署,可以选择的方案就比较少了,经过多轮的比较,最终选择了apache 2.4 + flask + python 3.7 + windows原创 2021-07-12 16:05:50 · 602 阅读 · 0 评论 -
爬虫日记(90):Scrapy的HTTP11DownloadHandler类
在爬虫里,使用最多的下载机制,还是HTTP协议,因此这个协议的实现就非常关键了,也是一个比较复杂的实现,要读懂这个类要比较费时间和精力。虽然比较复杂,我们还是一步一步地去分析这些代码实现,以便我们可以自己实现HTTP协议,或者修改HTTP协议,又或者整个这部分源码自己的工程。在scrapy引入这个类,并不是直接以这个类的名称,而是改为别名HTTPDownloadHandler,如下所示:因此下载HTTP/HTTPS协议的时候,就是调用HTTP11DownloadHandler类。接着下.原创 2021-07-11 18:31:12 · 350 阅读 · 0 评论 -
爬虫日记(89):Scrapy的DownloadHandlers类
前面分析了下载器的整个源码,理解了下载器的工作过程,在那里经常会遇到一个类,就是DownloadHandlers类,这个类主要用来对不同的下载协议进行管理的,比如文件协议和http协议不一样,那么就需要使用不同的类来表示,又比如https的下载和http的下载过程也不一样,这样也要分开处理。因此DownloadHandlers类需要实现不同的协议、不同的下载方式进行管理。我们先来看一下默认的设置参数:DOWNLOAD_HANDLERS_BASE = { 'data': 'scrapy.co...原创 2021-07-11 10:38:21 · 832 阅读 · 0 评论 -
爬虫日记(88):Scrapy的Downloader类(三)
接着下来我们来分析下载的过程以及数据返回之后的处理,在这个过程里要小心地安排处理的步骤,否则会比较容易出错。在这里按这个流程图来处理,详细的代码如下:第160行定义了下载函数,传入是slot对象、请求对象、蜘蛛类对象。第164行创建一个延时对象,这个延时对象执行的是self.handlers.download_request函数,它会把请求的种类进行分类,如果是HTTP就调用HTTP类,如果是文件,就调用文件下载协议。因此dfd就是下载返回之后处理的回调链,把所有后面处理的功能全部关原创 2021-07-08 16:08:19 · 221 阅读 · 0 评论 -
爬虫日记(88):Scrapy的Downloader类(二)
接着下来,我们来分析Downloader类的初始化过程,以及相关的数据结构,这样才能明白它具体做了些什么事情。第69行定义了类Downloader类。第71行定义保存在请求字典里的键,比如request.meta[self.DOWNLOAD_SLOT]。第73行定义构造函数,传入爬虫类的管理类对象crawler。第74行获得设置参数settings。第75行获得信号发送对象。第76行定义当前下载对象集合。第77行定义当前下载活动对象的集合。第78行保存处理下载各种文件类型原创 2021-07-07 16:55:43 · 275 阅读 · 0 评论 -
爬虫日记(88):Scrapy的Downloader类(一)
从前面的分析我们知道,当下载的连接URL去重之后,就需要把URL放到下载器里进行下载,这样才会得到网页相关的数据,比如HTML、图片、脚本等等。然后我们根据网页再来抽取相关的数据,或者获得图片。接着下来,我们更进一步地来了解下载器是怎么样把URL的内容获取回来,明白整个数据取得的过程,对于我们了解爬虫过程也是有重要意义的。从下图就可以了解整个下载器的初始化过程:先从引擎的构造函数里进行初始化,它是从缺省的配置文件里加载参数DOWNLOADER,而这个参数里保存的是scrapy.core.do原创 2021-06-29 09:32:32 · 340 阅读 · 0 评论 -
爬虫日记(87):Scrapy的RFPDupeFilter类(二)
前面函数的代码已经很清楚,就是生成请求对象的指纹信息,现在来分析每一行代码的作用:第52和53行是判断请求是否包含额外包含的头内容,如果有就把它们先排序,然后把每一项转换为小写字母表示,再生成一个元组。第54行是调用弱引用字典类对象_fingerprint_cache,它是这样创建的:_fingerprint_cache = weakref.WeakKeyDictionary()跟前学习过的例子一样,明白它是随着对象删除而删除的字典。常常用来缓存的应用,这里就是这样的使用。这里使用了原创 2021-06-18 12:41:27 · 257 阅读 · 0 评论 -
爬虫日记(87):Scrapy的RFPDupeFilter类(一)
前面已经分析了调度器的入队代码,在这里会调用RFPDupeFilter类的功能,用来判断两个下载的url请求是否相同,如果相同,并且参数设置为去重时,就会不再下载,这样避免了重复下载同样的url页面。接着下来我们来分析怎么样实现url相同的判断,是否直接采用字符串相同的判断?还是有什么方法进行判断呢?要解决这些疑问,我们需要把这些代码分析一轮,才能搞明白为什么这样设计,以及这样实现有什么优点。在开始分析之前,我们先来学习一下python怎么样方便记录一个对象已经查看过。由于一个对象有很多属性,.原创 2021-06-14 18:29:55 · 476 阅读 · 0 评论 -
爬虫日记(86):Scrapy的Scheduler类(三)
前面已经分析过入队的情况,进入队列时,会根据请求的内容来生成一个数字指纹,如果两个数字指纹一样,那么就可以丢掉这个请求,这样就可以防止重复的请求,这样可以提高效率。接着下来,我们来分析一下从队列里出队的情况,通前面的分析已经知道引擎会调用函数_next_request_from_scheduler,而这个函数就会调用调度器的函数next_request,它将返回请求对象:第103行从内存队列里弹出一个请求。这个mqs的创建过程是这样的:从上面过程来看,self.mqs就是类ScrapyPri原创 2021-06-13 16:47:54 · 322 阅读 · 0 评论 -
爬虫日记(86):Scrapy的Scheduler类(二)
上面已经准备了所有队列的对象,下一步我们就来分析怎么进入队列,以及怎么实现优先级队列管理这些请求。这些函数的调用关系如下:因此我们需要从函数enqueue_request入手,先来分析它的代码:第89行里的参数request就是要调度队列的请求对象。第90行先判断是否允许过滤,如果不允许过滤就跳过这里;允许过滤就调用去重类的成员函数request_seen,在这个函数实现是否重复的请求判断。第91行如果是重复的,就输出日志。第92行跳过重复的请求,直接返回,不进入调度队列。.原创 2021-06-11 18:16:44 · 277 阅读 · 0 评论 -
MFC应用程序中处理消息的顺序
近日看到一个MFC的程序,发现有一些开发人员,不了解MFC程序的消息处理,他们把定时器删除KillTimer放在析构函数里,这样肯定会出错,因为那时候窗口都已经删除了。因此需要把这个定时器删除放在窗口没有删除之前,否则调用此函数就会出错,因为没有窗口句柄了。因此应该在收到WM_DESTROY消息里或之前进行删除。MFC应用程序中处理消息的顺序1.AfxWndProc() 该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc2.AfxCallWndP...原创 2021-06-07 09:52:56 · 300 阅读 · 0 评论 -
爬虫日记(86):Scrapy的Scheduler类(一)
前面学习过了引擎类,明白整个引擎的工作过程,在引擎里要调用调度管理类,这样才能够把请求下载进行去重,或者优先下载等功能实现。现在我们就来分析这个类的实现,以便完全理解调度管理类的相关细节。这个类的创建过程如下图:要创建调度管理类,它需要从默认设置参数里获得类的名称:SCHEDULER = 'scrapy.core.scheduler.Scheduler'然后根据这个参数名称,就可以从目录里找到对应的python包,再找到对应的调度类Scheduler,最后就可以通过上面的语句进行构造,创原创 2021-06-05 19:54:21 · 640 阅读 · 0 评论 -
爬虫日记(85):Scrapy的ExecutionEngine类(四)
接着下来我们来分析spider_is_idle函数,这个函数用来判断蜘蛛类是否处于空闲状态:第189行判断下载回应处理器是否空闲,如果不是空闲状态直接可以判断蜘蛛类为非空闲状态;反之就不行了,因为即使下载回应是空闲的,但是正在发送请求中。第193行判断下载器是否为活动当中,如果是活动当中说明蜘蛛类也不是空闲状态。第197行判断引擎里请求生成器是否为空,如果非空说明还有请求需要下载,说明蜘蛛类也为非空闲状态。第201行调度器里的队列是否还有数据,如果有数据也是非空闲状态。这个函数根原创 2021-06-04 18:37:14 · 209 阅读 · 0 评论 -
爬虫日记(85):Scrapy的ExecutionEngine类(三)
接着下来我们来分析_next_request_from_scheduler函数,这个函数主要实现从调度器里获得下载请求,然后把请求下载再放到下载器里去下载。实现这部分的功能:也就是上图的2、3、4、5这四步的功能。因此我们需要详细地查看这个函数的每一行代码:这个函数传进来的参数spider是蜘蛛类对象。第152行代码是保存类的slot对象到临时对象,避免self.slot修改为空的状态冲突。第153行是从类class Scheduler对象获得下一个可以发送的请求下载对象。第15原创 2021-06-04 09:21:41 · 584 阅读 · 0 评论 -
爬虫日记(85):Scrapy的ExecutionEngine类(二)
前面可以看到一开始打开蜘蛛类有一次触发调度之外,还有下载数据返回之后进行一次调度。如果中间有调度没有准备好,或者队列满了,这样不会产生有新的下载,那么怎么样再次触发调度发生呢?这时候就要靠另一个备份方案,就是定时调度方案,它的建立如下图:通过两个运行链都可以最终地调用_next_request函数,进入下载请求队列,把准备好的下载请求发送出去下载。因此接着下来我们继续分析_next_request函数,它的代码如下:第115行里传入的参数spider就是代码CallLaterOnce(s原创 2021-06-02 09:44:27 · 212 阅读 · 0 评论 -
爬虫日记(85):Scrapy的ExecutionEngine类(一)
前面分析了Crawler类,这个类实现了爬虫创建和运行管理,同时也是一个爬虫的公共类,可以把这个类传送到各个类中去使用。紧接着就会把控制权交给下一个类ExecutionEngine,这个类的生命周期如下:因此我们先来分析ExecutionEngine类的构造函数,理解它是怎么创建的,以及有什么样的数据结构,最后通过算法来理解这个类的功能实现。打开目录scrapy\core,就可以找到文件engine.py,然后就可以分析这个类的代码了。ExecutionEngine类的构造函数代码如下:原创 2021-06-01 11:54:00 · 381 阅读 · 0 评论 -
爬虫日记(84):Scrapy的Crawler类(三)
前面完成Crawler类的构造函数分析,接着下来我们来分析这个类的第一个开始调用的函数,Crawler类被创建之后,就会立即调用crawl函数,代码如下:class CrawlerRunner: ... def _crawl(self, crawler, *args, **kwargs): self.crawlers.add(crawler) d = crawler.crawl(*args, **kwargs) self._act...原创 2021-05-30 11:47:54 · 399 阅读 · 0 评论 -
爬虫日记(84):Scrapy的Crawler类(二)
spidercls是一个蜘蛛类,比如这里是<class 'ItemDemo.spiders.quotes.QuotesSpider'>内容,self.settings是前面加载所有文件和命令行的参数合集。接着就来到类Crawler的构造函数,它的代码如下:第42行判断spidercls变量是否是一个Spider的派生类的实例,如果是一个对象就返回出错。第45行如果参数设置还没有转行为Settings对象,就进行转换。这两行代码都是对参数进行判断,避免出错。第48行把蜘蛛类原创 2021-05-29 18:45:09 · 324 阅读 · 0 评论 -
爬虫日记(84):Scrapy的Crawler类(一)
Crawler类是一个爬虫类,主要用来管理整个执行引擎ExecutionEngine类和蜘蛛类实例化。在分析这个类之前,我们先来看一下怎么样调用这个类的,代码如下:在调用_create_crawler函数时传送的参数spidercls是一个字符串,它的值是quotes。这时候需要把蜘蛛类中的名称转换为蜘蛛类的对象,这个过程是怎么样实现呢?显然就是使用蜘蛛类的加载类,也就是这里的spider_loader对象来实现,因此这里调用了load方法。所以传送给Crawler类的参数spidercls已经是一原创 2021-05-29 10:26:52 · 590 阅读 · 0 评论 -
爬虫日记(83):Scrapy的CrawlerProcess类(四)
当前面准备工作都已经做之后,我们就需要让爬虫转换控制权了,就是从命令里转移到引擎运行了,它的触发代码就是在下面:class Command(BaseRunSpiderCommand): ... def run(self, args, opts): ... self.crawler_process.start() ...这行代码self.crawler_process.start()是调用crawler_process对象,也就...原创 2021-05-28 18:45:07 · 371 阅读 · 0 评论 -
爬虫日记(83):Scrapy的CrawlerProcess类(三)
前面完成了CrawlerRunner类构造函数的分析,接着从哪里继续开始呢?我想应该按顺序执行的主线来进行,可以从之前运行的命令里看到执行下面的函数:class Command(BaseRunSpiderCommand): def run(self, args, opts): ... crawl_defer = self.crawler_process.crawl(spname, **opts.spargs)所以我们可以从crawl函数来入手,它们之...原创 2021-05-27 19:08:25 · 372 阅读 · 0 评论 -
爬虫日记(83):Scrapy的CrawlerProcess类(二)
因此继续来分析这两个函数的代码,才能理解蜘蛛类怎么样加载进来,怎么样设置twisted底层的工作框架。我们来查看_get_spider_loader函数的代码,它的定义如下:第131行使用了staticmethod装饰器,它是用来创建一个静态方法。静态方法类似普通方法,参数里面不用self。这些方法和类相关,但是又不需要类和实例中的任何信息、属性等等。如果把这些方法写到类外面,这样就把和类相关的代码分散到类外,使得之后对于代码的理解和维护都是巨大的障碍,而静态方法就是用来解决这一类问题的。因此可以认原创 2021-05-26 20:46:53 · 369 阅读 · 0 评论