Scrapy框架的执行流程解析

这里主要介绍七个大类
Command->CrawlerProcess->Crawler->ExecutionEngine->sceduler
另外还有两个类:Request和HttpRessponse

1.首先通过Command类中的run方法
(1).创建开始运行的命令
(2).将每一个spider对象的路径传入到crawl_process.crawl方法中去
(3).crawl_process.crawl方法创建一个Crawler对象,通过调用Crawler.crawl方法创建一个引擎和spider对象
(4).通过引擎的open_spider方法创建一个Scheduler对象,将每一个spider对象加入到schedler队列中去,并且通过自身的_next_request方法对下一次请求进行调度
(5).调用CrawlerProcess对象的start方法开始事件循环
2.CrawlerProcess类:
初始值:创建一个集合_active,用于存放每一个请求的socket对象
crawl方法:创建一个Crawler对象,调用Crawler.crawl方法,传入spider对象的路径(Crawler.crawl方法的作用是将传入的spider对象的路径通过调用_create_spider方法,
创建一个spider对象,通过_create_engine方法创建一个引擎,通过调用引擎中的open_spider方法将spider对象的start_reuqests请求加入到scheduler调度器中的
队列当中,然后调用引擎的中的_next_request方法对下一个请求进行调度。然后yield一个引擎的start方法,start方法返回的是一个defer.Defered对象,
不发送任何请求,需要手动停止,目的是为了夯住事件循环)并将返回的scoket的对象加入到集合中
start方法:将该socket对象的集合加到到defer.DeferedList中去,并添加回调函数进行手动停止。开始事件循环

3.Crawler类:用户封装引擎及spider对象
_create_engine方法:创建一个引擎
_create_spider:通过传入的spider对象的路径创建spider对象
crawl:调用_create_engine方法创建engine,调用_create_spider方法去打开spider对象,对spider中的start_requests请求转化为迭代器,通过调用engine.open_spider方法
调用next函数将每一个请求加入到调度器中的队列中去,并调用engine._next_request方法对下一次请求进行调度
4.ExecutionEngine类:
引擎:所有的调度
初始值:self._close = None:用于存放一个defer。defered对象, self.scheduler = None用于创建一个队列
self.max = 5设置最大并发数 self.crawlling = []创建一个正在执行请求的列表
open_spider方法:
1.创建一个调度器对象,将传入的start_requests请求通过next方法将每一个请求加入到队列当中去
2.然后开始事件循环执行_next_request方法对下一次请求的调度
注:每一个@defer.inlineCallbacks装饰的函数都必须yield一个对象,即使为None
_next_request方法:
1.对spider对象的请求进行调度
2.设置事件循环终止条件:调度器队列中请求的个数为0,正在执行的请求数为0
3.设置最大并发数,根据正在执行的请求数量满足最大并发数条件对sceduler队列中的请求进行调度执行,并将返回的请求加入到正在执行的列表中
4.包括对请求进行下载,以及对返回的数据执行callback函数
5.开始执行事件循环的下一次请求的调度
get_response_callback方法:
1.将返回数据的请求从正在执行的列表中移出
2.将返回的数据调用HttpResponse封装成一个response对象,执行请求的callback函数,并判断如果callback函数返回的结果是一个生成器对象,则将该生成器
中的每一个对 象加入到调度器中的队列中去
start方法:不发送任何请求,需要手动停止,目的是为了夯住循环
5.Scheduler类:任务调度器
1.初始化一个队列
2.next_request方法:读取队列中的下一个请求
3.enqueue_request方法:将请求加入到队列
4.size方法:返回当前队列请求的数量
5.open方法:无任何操作,返回一个空值,用于引擎中用装饰器装饰的open_spider方法返回一个yield对象

6.Resquet类:用于封装用户请求相关信息,供用户编写spider时发送请求所用,主要的两个参数:url和callback
7.HttpResponse类:
通过响应请求返回的数据和穿入的request对象封装成一个response对象
目的是为了将请求返回的数据不仅包括返回的content数据,使其拥有更多的属性,比如请求头,请求url,请求的cookies等等
更方便的被回调函数所解析有用的数据

下面是根据自己的理解写的一个小型的scrapy框架:

from twisted.internet import reactor   # 事件循环(终止条件,所有的socket都已经移除)from twisted.web.client import getPage # socket对象(如果下载完成,自动从时间循环中移除...)from twisted.internet import defer     # defer.Deferred 特殊的socket对象 (不会发请求,手动移除)from queue import Queue

class Request(object):    """    用于封装用户请求相关信息,供用户编写spider时发送请求所用    """    def __init__(self,url,callback):        self.url = url        self.callback = callback

class HttpResponse(object):    """    通过响应请求返回的数据和穿入的request对象封装成一个response对象    目的是为了将请求返回的数据不仅包括返回的content数据,使其拥有更多的属性,比如请求头,请求url,请求的cookies等等    更方便的被回调函数所解析有用的数据    """    def __init__(self,content,request):        self.content = content        self.request = request        self.url = request.url        self.text = str(content,encoding=‘utf-8‘)

class Scheduler(object):    """    任务调度器:    1.初始化一个队列    2.next_request方法:读取队列中的下一个请求    3.enqueue_request方法:将请求加入到队列    4.size方法:返回当前队列请求的数量    5.open方法:无任何操作,返回一个空值,用于引擎中用装饰器装饰的open_spider方法返回一个yield对象    """    def __init__(self):        self.q = Queue()

def open(self):        pass

def next_request(self):        try:            req = self.q.get(block=False)        except Exception as e:            req = None        return req

def enqueue_request(self,req):        self.q.put(req)

def size(self):        return self.q.qsize()

class ExecutionEngine(object):    """    引擎:所有的调度    1.通过open_spider方法将start_requests中的每一个请求加入到scdeuler中的队列当中,    2.处理每一个请求响应之后的回调函数(get_response_callback)和执行下一次请求的调度(_next_request)    """    def __init__(self):        self._close = None        self.scheduler = None        self.max = 5        self.crawlling = []

def get_response_callback(self,content,request):        self.crawlling.remove(request)        response = HttpResponse(content,request)        result = request.callback(response)        import types        if isinstance(result,types.GeneratorType):            for req in result:                self.scheduler.enqueue_request(req)

def _next_request(self):        """        1.对spider对象的请求进行调度        2.设置事件循环终止条件:调度器队列中请求的个数为0,正在执行的请求数为0        3.设置最大并发数,根据正在执行的请求数量满足最大并发数条件对sceduler队列中的请求进行调度执行        4.包括对请求进行下载,以及对返回的数据执行callback函数        5.开始执行事件循环的下一次请求的调度        """        if self.scheduler.size() == 0 and len(self.crawlling) == 0:            self._close.callback(None)            return        """设置最大并发数为5"""        while len(self.crawlling) < self.max:            req = self.scheduler.next_request()            if not req:                return            self.crawlling.append(req)            d = getPage(req.url.encode(‘utf-8‘))            d.addCallback(self.get_response_callback,req)            d.addCallback(lambda _:reactor.callLater(0,self._next_request))

@defer.inlineCallbacks    def open_spider(self,start_requests):        """        1.创建一个调度器对象        2.将start_requests中的每一个请求加入到scheduler队列中去        3.然后开始事件循环执行下一次请求的调度        注:每一个@defer.inlineCallbacks装饰的函数都必须yield一个对象,即使为None        """        self.scheduler = Scheduler()        yield self.scheduler.open()        while True:            try:                req = next(start_requests)            except StopIteration as e:                break            self.scheduler.enqueue_request(req)        reactor.callLater(0,self._next_request)

@defer.inlineCallbacks    def start(self):        """不发送任何请求,需要手动停止,目的是为了夯住循环"""        self._close = defer.Deferred()        yield self._close

class Crawler(object):    """    1.用户封装调度器以及引擎    2.通过传入的spider对象的路径创建spider对象    3.创建引擎去打开spider对象,对spider中的每一个请求加入到调度器中的队列中去,通过引擎对请求去进行调度    """    def _create_engine(self):        return ExecutionEngine()

def _create_spider(self,spider_cls_path):        """

:param spider_cls_path:  spider.chouti.ChoutiSpider        :return:        """        module_path,cls_name = spider_cls_path.rsplit(‘.‘,maxsplit=1)        import importlib        m = importlib.import_module(module_path)        cls = getattr(m,cls_name)        return cls()

@defer.inlineCallbacks    def crawl(self,spider_cls_path):        engine = self._create_engine()        spider = self._create_spider(spider_cls_path)        start_requests = iter(spider.start_requests())        yield engine.open_spider(start_requests) #将start_requests中的每一个请求加入到调度器的队列中去,并有引擎调度请求的执行        yield engine.start() #创建一个defer对象,目的是为了夯住事件循环,手动停止

class CrawlerProcess(object):    """    1.创建一个Crawler对象    2.将传入的每一个spider对象的路径传入Crawler.crawl方法    3.并将返回的socket对象加入到集合中    4.开始事件循环    """    def __init__(self):        self._active = set()

def crawl(self,spider_cls_path):        """        :param spider_cls_path:        :return:        """        crawler = Crawler()        d = crawler.crawl(spider_cls_path)        self._active.add(d)

def start(self):        dd = defer.DeferredList(self._active)        dd.addBoth(lambda _:reactor.stop())

reactor.run()

class Command(object):    """    1.创建开始运行的命令    2.将每一个spider对象的路径传入到crawl_process.crawl方法中去    3.crawl_process.crawl方法创建一个Crawler对象,通过调用Crawler.crawl方法创建一个引擎和spider对象    4.通过引擎的open_spider方法创建一个scheduler对象,将每一个spider对象加入到schedler队列中去,并且通过自身的_next_request方法对下一次请求进行调度    5.    """    def run(self):        crawl_process = CrawlerProcess()        spider_cls_path_list = [‘spider.chouti.ChoutiSpider‘,‘spider.cnblogs.CnblogsSpider‘,]        for spider_cls_path in spider_cls_path_list:            crawl_process.crawl(spider_cls_path)        crawl_process.start()

if __name__ == ‘__main__‘:    cmd = Command()    cmd.run()

原文地址:https://www.cnblogs.com/zhangyafei/p/9575768.html

时间: 2024-07-30 15:58:00

Scrapy框架的执行流程解析的相关文章

Struts2框架的执行流程

一.执行流程介绍 1.通过浏览器发送一个请求 2.会被StrutsPrepareAndExecuteFilter拦截(struts2的拦截器作用) 3.会调用strust2框架默认的拦截器(interceptor)完成部分功能 4.在执行Action中操作 5.根据Action中方法的执行结果来选择来跳转页面Result视图 一般我们将StrutsPrepareAndExecuteFilter 叫做前端控制器(核心控制器),只有在web.xml文件中配置了这个filter我们的strtus2框架

Caffe中对MNIST执行train操作执行流程解析

之前在 http://blog.csdn.net/fengbingchun/article/details/49849225 中简单介绍过使用Caffe train MNIST的文章,当时只是仿照caffe中的example实现了下,下面说一下执行流程,并精简代码到仅有10余行: 1.        先注册所有层,执行layer_factory.hpp中类LayerRegisterer的构造函数,类LayerRegistry的AddCreator和Registry静态函数:关于Caffe中Lay

使用Caffe进行手写数字识别执行流程解析

之前在 http://blog.csdn.net/fengbingchun/article/details/50987185 中仿照Caffe中的examples实现对手写数字进行识别,这里详细介绍下其执行流程并精简了实现代码,使用Caffe对MNIST数据集进行train的文章可以参考  http://blog.csdn.net/fengbingchun/article/details/68065338 : 1.   先注册所有层,执行layer_factory.hpp中类LayerRegis

Struts 2 Spring Hibernate三大框架的执行流程以及原理

转:http://www.cnblogs.com/System-out-println/p/5974113.html Struts2框架 一.简介 Struts2是一个相当强大的Java Web开源框架,是一个基于POJO的Action的MVC Web框架.它基于当年的WebWork和XWork框架,继承其优点,同时做了相当的改进. 1.Struts2基于MVC架构,框架结构清晰,开发流程一目了然,开发人员可以很好的掌控开发的过程. 2.使用OGNL进行参数传递.OGNL提供了在Struts2里

nginx学习笔记七(nginx HTTP框架的执行流程)

之前已经介绍过nginx的事件框架.那么,对于client发出的一个http的请求,nginx的http框架是如何一步步解析这个http请求?http框架又是如何和之前介绍过得epoll事件模块结合起来的,下面来简要介绍下. 注:我手头上的nginx工程是nginx-1.9.14的,与<深入理解nginx>的版本不一致,在http框架这块的代码上也有着较大的区别. 一.ngx_http_init_connection 在http框架初始化的时候(参见<深入理解nginx>第10章)

Scrapy框架中结合splash 解析js ——环境配置

环境配置: http://splash.readthedocs.io/en/stable/install.html pip install scrapy-splash docker pull scrapinghub/splash docker run -p 8050:8050 scrapinghub/splash ---- settings.py #-- SPLASH_URL = 'http://localhost:8050' #-- DOWNLOADER_MIDDLEWARES = { 'sc

Python之Django框架执行流程简介

我为大家简单阐述一下Django框架执行的大概流程. Django框架的执行流程    1.浏览器发送请求    2.服务器接收请求并将请求转发给Django框架    3.框架处理请求,如果是请求数据就去找model,如果请求时模版就去找template,然后将模板或数据读取并返回给服务器一个相应.    4.服务器再将相应转发给客户端 原文地址:https://www.cnblogs.com/chao666/p/12093912.html

scrapy框架的使用

Scrapy    框架架构 一.Scrapy框架是基于Twisted的异步框架,纯Python实现的爬虫框架,耦合程度低,可拓展性极强. 1.Engine引擎,处理整个系统的数据流.触发事物.框架的核心 2.item项目,定义爬虫爬取结果的数据结构,爬取的数据会被赋值成该item对象 3.Schedule调度器,接受engine发过来的request放入队列,然后engine再次请求时,将request发送给engine 4.Downloader下载器,下载网页内容,并将网页返回给spider

Android中图片加载框架Glide解析2----从源码的角度理解Glide的执行流程

转载地址:http://blog.csdn.net/guolin_blog/article/details/53939176 在本系列的上一篇文章中,我们学习了Glide的基本用法,体验了这个图片加载框架的强大功能,以及它非常简便的API.还没有看过上一篇文章的朋友,建议先去阅读 Android图片加载框架最全解析(一),Glide的基本用法 . 在多数情况下,我们想要在界面上加载并展示一张图片只需要一行代码就能实现,如下所示: Glide.with(this).load(url).into(i