• middleware


    from collections import defaultdict
    import logging
    import pprint
    
    from scrapy.exceptions import NotConfigured
    from scrapy.utils.misc import load_object
    from scrapy.utils.defer import process_parallel, process_chain, process_chain_both
    
    logger = logging.getLogger(__name__)
    
    
    class MiddlewareManager(object):
        """Base class for implementing middleware managers"""
    
        component_name = 'foo middleware'
    
        def __init__(self, *middlewares):
            self.middlewares = middlewares
            self.methods = defaultdict(list)
            for mw in middlewares:
                # 遍历所有的中间件,并调用_add_middleware方法:
                # 管理器中添加中间件的'open_spider'和'close_spider'方法
                self._add_middleware(mw)
    
        @classmethod
        def _get_mwlist_from_settings(cls, settings):
            raise NotImplementedError
    
        @classmethod
        def from_settings(cls, settings, crawler=None):
            # 调用_get_mwlist_from_settings方法从配置文件中生成中间件列表,这个方法需要子类实现
            mwlist = cls._get_mwlist_from_settings(settings)
            middlewares = []
            enabled = []
            for clspath in mwlist:
                try:
                    mwcls = load_object(clspath)
                    # 依次加载中间件模块并构造对象,构造顺序是先尝试调用from_cralwer,再尝试调用from_settings,最后都没有再调用__init__
                    if crawler and hasattr(mwcls, 'from_crawler'):
                        mw = mwcls.from_crawler(crawler)
                    elif hasattr(mwcls, 'from_settings'):
                        mw = mwcls.from_settings(settings)
                    else:
                        mw = mwcls()
                    middlewares.append(mw)
                    enabled.append(clspath)
                except NotConfigured as e:
                    if e.args:
                        clsname = clspath.split('.')[-1]
                        logger.warning("Disabled %(clsname)s: %(eargs)s",
                                       {'clsname': clsname, 'eargs': e.args[0]},
                                       extra={'crawler': crawler})
    
            logger.info("Enabled %(componentname)ss:
    %(enabledlist)s",
                        {'componentname': cls.component_name,
                         'enabledlist': pprint.pformat(enabled)},
                        extra={'crawler': crawler})
            return cls(*middlewares)
    
        # 这个from_cralwer方法是基类MiddlewareManger的方法
        # 通过crawler的配置生成对象
        @classmethod
        def from_crawler(cls, crawler):
            return cls.from_settings(crawler.settings, crawler)
    
        '''
        网络蜘蛛中间件管理器通过自定义'_add_middleware'方法还添加了'process_spider_input','process_spider_output','process_spider_exception','process_start_request'方法,这些方面后面的分析中都会乃至。
        def _add_middleware(self, mw):
        super(SpiderMiddlewareManager, self)._add_middleware(mw)
        if hasattr(mw, 'process_spider_input'):
            self.methods['process_spider_input'].append(mw.process_spider_input)
        if hasattr(mw, 'process_spider_output'):
            self.methods['process_spider_output'].insert(0, mw.process_spider_output)
        if hasattr(mw, 'process_spider_exception'):
            self.methods['process_spider_exception'].insert(0, mw.process_spider_exception)
        if hasattr(mw, 'process_start_requests'):
            self.methods['process_start_requests'].insert(0, mw.process_start_requests)'''
    
        # 可以看到,就是向methods字典里依次添加中间件的'open_spider'和'close_spider'方法。
        def _add_middleware(self, mw):
            if hasattr(mw, 'open_spider'):
                self.methods['open_spider'].append(mw.open_spider)
            if hasattr(mw, 'close_spider'):
                self.methods['close_spider'].insert(0, mw.close_spider)
    
        def _process_parallel(self, methodname, obj, *args):
            return process_parallel(self.methods[methodname], obj, *args)
    
        def _process_chain(self, methodname, obj, *args):
            return process_chain(self.methods[methodname], obj, *args)
    
        def _process_chain_both(self, cb_methodname, eb_methodname, obj, *args):
            return process_chain_both(self.methods[cb_methodname], 
                                      self.methods[eb_methodname], obj, *args)
    
        def open_spider(self, spider):
            return self._process_parallel('open_spider', spider)
    
        def close_spider(self, spider):
            return self._process_parallel('close_spider', spider)
    # -*- coding: utf-8 -*-
    
    # Define here the models for your spider middleware
    #
    # See documentation in:
    # https://doc.scrapy.org/en/latest/topics/spider-middleware.html
    
    from scrapy import signals
    
    
    class ScrapySpiderMiddleware(object):
    
        def open_spider(self):
            pass
    
        def process_spider_input(self, response, spider):
            '''
            当response通过spider中间件时,该方法被调用,处理该response。
            如果其跑出一个异常(exception),Scrapy将不会调用任何其他中间件的 process_spider_input() 方法,并调用request的errback。
            '''
            return None
    
        def process_spider_output(self, response, result, spider):
            '''
            当Spider处理response返回result时,该方法被调用。处理item数据
            '''
            for i in result:
                yield i
    
        def process_spider_exception(self, response, exception, spider):
            '''
             process_spider_input()抛出异常时, Scrapy调用 process_spider_exception() 。
             None:Scrapy将继续处理该异常,调用中间件链中的其他中间件的
             可迭代对象(Response 或 Item 对象的可迭代对象(iterable)):如果其返回一个可迭代对象,则中间件链的 process_spider_output() 方法被调用
             Request 对象:则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个response的那样。
             如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。
            '''
            pass
    
        def spider_opened(self, spider):
            spider.logger.info('Spider opened: %s' % spider.name)
    
    
    '''
    SPIDER_MIDDLEWARES_BASE
    {
        过滤出所有失败(错误)的HTTP response,因此spider不需要处理这些request。
        返回值为200-300之间的值为成功的resonse。
        您可以通过 spider的 handle_httpstatus_list:404  提交处理的状态码
        HTTPERROR_ALLOWED_CODES=[201,202]
        HTTPERROR_ALLOW_ALL:Flase True(默认忽略,)
        'scrapy.contrib.spidermiddleware.httperror.HttpErrorMiddleware': 50,
        
        过滤出不属于spider负责的Request的URL
        allowed_domains (设置允许爬的域)  baidu.com
        dont_filter (设置不允许爬的域)    baidu.com/newspage
        'scrapy.contrib.spidermiddleware.offsite.OffsiteMiddleware': 500,
        
        根据生成Request的Response的URL来设置Request Referer 字段。
        REFERER_ENABLED:True False(默认开启)
        'scrapy.contrib.spidermiddleware.referer.RefererMiddleware': 700,
        
        设置URL长度
        URLLENGTH_LIMIT:2083 允许爬取URL最长的长度.
        'scrapy.contrib.spidermiddleware.urllength.UrlLengthMiddleware': 800,
        
        用于追踪每个Request在被爬取的网站的深度的中间件。 其可以用来限制爬取深度的最大深度或类似的事情。
        DEPTH_LIMIT - 爬取所允许的最大深度,如果为0,则没有限制。
        DEPTH_STATS - 是否收集爬取状态。
        DEPTH_PRIORITY - 是否根据其深度对requet安排优先级
        'scrapy.contrib.spidermiddleware.depth.DepthMiddleware': 900,
    }
    '''
    
    
    class ScrapyDownloaderMiddleware(object):
    
        def open_spider(self):
            pass
    
        def process_request(self, request, spider):
            '''
            当每个request通过下载中间件时,该方法被调用。
            None:Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。
            Response 对象:Scrapy将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该response。
            Request 对象:Scrapy则停止调用 process_request方法并重新调度返回的request。当新返回的request被执行后, 相应地中间件链将会根据下载的response被调用。
            如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。
            '''
            return None
    
        def process_response(self, request, response, spider):
            '''
            当每个response通过下载中间件时,该方法被调用。
            Response 对象:该response会被在链中的其他中间件的 process_response() 方法处理。
            Request 对象:中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request() 返回request所做的那样。
            如果其抛出一个 IgnoreRequest 异常,则调用request的errback(Request.errback)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。
            '''
            return response
    
        def process_exception(self, request, exception, spider):
            '''
            当下载处理器(下载中间件)抛出异常时, Scrapy调用 process_exception() 。
            None:Scrapy将会继续处理该异常,接着调用已安装的其他中间件的 process_exception() 方法,直到所有中间件都被调用完毕,则调用默认的异常处理。
            Response 对象:则已安装的中间件链的 process_response() 方法被调用。Scrapy将不会调用任何其他中间件的 process_exception() 方法。
            Request 对象:则返回的request将会被重新调用下载。这将停止中间件的 process_exception() 方法执行,就如返回一个response的那样。
            如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。
           '''
            pass
    
        def spider_opened(self, spider):
            # 关闭爬虫的时候会被调用
            spider.logger.info('Spider opened: %s' % spider.name)
    
    
    '''
    DOWNLOADER_MIDDLEWARES_BASE
    {
        是否遵循Robots协议
        ROBOTSTXT_OBEY:True False(默认遵循)
        scrapy.contrib.downloadermiddleware.robotstxt.RobotsTxtMiddleware': 100,
        
        完成爬取过程中在HTTP认证过程
        当一个客户端向HTTP服务器进行数据请求时,如果客户端未被认证,则HTTP服务器将通过基本认证过程对客户端的用户名及密码进行验证,以决定用户是否合法
        from scrapy.contrib.spiders import CrawlSpider
        class SomeIntranetSiteSpider(CrawlSpider):
        http_user = 'someuser'   用户名
        http_pass = 'somepass'   密码
        name = 'intranet.example.com'   域名
        'scrapy.contrib.downloadermiddleware.httpauth.HttpAuthMiddleware': 300,
        
        设置 DOWNLOAD_TIMEOUT 指定的request下载超时时间. 
        DOWNLOAD_TIMEOUT:180(下载超时时间)
        'scrapy.contrib.downloadermiddleware.downloadtimeout.DownloadTimeoutMiddleware': 350,
        
        用于覆盖spider的默认user agent的中间件
        USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36'(设置请求头)
        'scrapy.contrib.downloadermiddleware.useragent.UserAgentMiddleware': 400,
        
        爬取进程会收集失败的页面并在最后,spider爬取完所有正常(不失败)的页面后重新调度。
        RETRY_ENABLED:True False(默认开启)
        RETRY_TIMES:2(默认下载次数,包括第一次)
        'scrapy.contrib.downloadermiddleware.retry.RetryMiddleware': 500,
        
        设置 DEFAULT_REQUEST_HEADERS 指定的默认request header。
        {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en',}
        'scrapy.contrib.downloadermiddleware.defaultheaders.DefaultHeadersMiddleware': 550,
        
        根据meta-refresh html标签处理request重定向。
        METAREFRESH_ENABLED:True False(默认开启)
        REDIRECT_MAX_METAREFRESH_DELAY:100(跟进重定向的最大 meta-refresh 延迟(单位:秒)
        'scrapy.contrib.downloadermiddleware.redirect.MetaRefreshMiddleware': 580,
        
        # 提供了对压缩(gzip, deflate)数据的支持。
        COMPRESSION_ENABLED:True Flase(默认开启)
        'scrapy.contrib.downloadermiddleware.httpcompression.HttpCompressionMiddleware': 590,
        
        根据response的状态处理重定向的request。
        REDIRECT_ENABLED:True False (默认开启)
        REDIRECT_MAX_TIMES:20(重定向的最大次数。)
        'scrapy.contrib.downloadermiddleware.redirect.RedirectMiddleware': 600,
        
        添加cookie信息   
        COOKIES_ENABLED:True False
        'scrapy.contrib.downloadermiddleware.cookies.CookiesMiddleware': 700,
        
        对request设置HTTP代理的支持。您可以通过在 Request 对象中设置 proxy 元数据来开启代理。
        'scrapy.contrib.downloadermiddleware.httpproxy.HttpProxyMiddleware': 750,
        
        该中间件为所有HTTP request及response数据
        每个request及其对应的response都被缓存。 当相同的request发生时,其不发送任何数据,直接返回response。
        HTTPCACHE_ENABLED:True False  是否开启
        HTTPCACHE_EXPIRATION_SECS:0(秒)超过这个时间的缓存request将会被重新下载。如果为0,则缓存的request将永远不会超时
        HTTPCACHE_DIR:httpcache 缓存目录
        'scrapy.contrib.downloadermiddleware.httpcache.HttpCacheMiddleware': 800,
    }
    '''
  • 相关阅读:
    WPF框架MVVM简单例子
    向WPF的Grid里面增加控件
    静态资源(StaticResource)和动态资源(DynamicResource)
    WPF中INotifyPropertyChanged用法与数据绑定
    wpf 绑定数据无法更新ui控件可能存在的问题
    C#调用Resources.resx资源文件中的资源
    C# 委托的理解
    Codeforces 524E Rooks and Rectangles 线段树
    Codeforces 1000F One Occurrence 主席树|| 离线+线段树
    GYM 101673 A
  • 原文地址:https://www.cnblogs.com/yoyo1216/p/10131373.html
Copyright © 2020-2023  润新知