scrapy源码5:middleware的源码分析

这个文件是中间件的基类了。


from collections import defaultdict
import logging
import pprint

# 这几个都是引用默认字典, 日志, 打印的,没啥问题。 

from scrapy.exceptions import NotConfigured
from scrapy.utils.misc import load_object
# 导入了notconfigure没有配置的异常, 导入了load_object去完成字符串到对应类对象的方法。前面已经提到了。 

from scrapy.utils.defer import process_parallel, process_chain, process_chain_both
# 这几个方法都在defer里面。 我们定位过去看看。
def process_parallel(callbacks, input, *a, **kw):
    """Return a Deferred with the output of all successful calls to the given
    callbacks
    """
    dfds = [defer.succeed(input).addCallback(x, *a, **kw) for x in callbacks]
    d = defer.DeferredList(dfds, fireOnOneErrback=1, consumeErrors=1)
    d.addCallbacks(lambda r: [x[1] for x in r], lambda f: f.value.subFailure)
    return d
# 这个方法完成的功能就是返回一个带有所有成功输出的defrred,通过给定的callback方法。

# 并行处理,得到dfds, 添加一个成功回调。 一个错误回调。 
def process_chain(callbacks, input, *a, **kw):
    """Return a Deferred built by chaining the given callbacks"""
    d = defer.Deferred()
    for x in callbacks:
        d.addCallback(x, *a, **kw)
    d.callback(input)
    return d  # 这个方法将所有回调方法添加给deferred对象上, 然后给input

def process_chain_both(callbacks, errbacks, input, *a, **kw):
    """Return a Deferred built by chaining the given callbacks and errbacks"""
    d = defer.Deferred()
    for cb, eb in zip(callbacks, errbacks):
        d.addCallbacks(cb, eb, callbackArgs=a, callbackKeywords=kw,
            errbackArgs=a, errbackKeywords=kw)
    if isinstance(input, failure.Failure):
        d.errback(input)
    else:
        d.callback(input)
    return d
# 这个是上面的升级版吧, 添加回调。 

logger = logging.getLogger(__name__) 全局的一个日志对象。


def __init__(self, *middlewares):
    self.middlewares = middlewares
    self.methods = defaultdict(list)
    for mw in middlewares:
        self._add_middleware(mw)
# 构造函数, 接受中间件列表, 构造方法的默认dict , 添加中间件。

@classmethod
def _get_mwlist_from_settings(cls, settings):
    raise NotImplementedError
# 这个方法什么鬼, 直接抛出异常?, 应该是写一个方法打个桩子吧, 以后可能后去完善它, 然后调用它的吧。 或者子类里面实现吧 。
# 如果子类不实现就抛出异常, 感觉应该是第二种情况, 这个其实和c++的接口是一样的。 强制子类去实现指定的方法。 

def from_settings(cls, settings, crawler=None):
    mwlist = cls._get_mwlist_from_settings(settings)
    middlewares = []
    enabled = []
    for clspath in mwlist:
        try:
            mwcls = load_object(clspath)
            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:\n%(enabledlist)s",
                {
     'componentname': cls.component_name,
                    'enabledlist': pprint.pformat(enabled)},
                extra={
     'crawler': crawler})
    return cls(*middlewares)
# 使用子类实现的方法_get_mwlist_from_settings 完成从settings里面获取中间件, 遍历中间件列表。 
# 如果中间件有from_crawler,from settings 这些方法,就调用下,去构造一个中间件对象。
# 添加到对应的中间件对象列表中去,这里mwlist只是中间件的类名字列表, middlearess存储的是中间件的对象。
# enabled 启用的中间件类列表。如果有异常, 说明配置文件给定的中间件不存在或者没法实例化。 
# 日志信息记录启动了那些中间件。返回中间件。
@classmethod
def from_crawler(cls, crawler):
    return cls.from_settings(crawler.settings, crawler)
# 调用对应的中间件方法from_settings 方法去完成类实例的创建


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)
# 添加中间件的房, 如果有open_spider,close_spider方法的话, 添加到对应方法去。 
# 我们这里可以发现, open是append的close是insert 0位置。 
# 也就是说, 如果一个中间件的open添加早那么他的close就后关闭的。

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)
# 打开爬虫, 关闭爬虫, 都是并行处理的。 

# 从这个文件可以看出来, 我们要自己写个中间件的话, 要实现open_spider,close_spider, from_crawler,from_setting这些方法。

你可能感兴趣的:(python源码,爬虫总结和详解)