scrapy系列(三)——基础spider源码解析

前面两章介绍了scrapy的安装和项目的新建,那么这一章就讲讲spider吧。html

scrapy有个命令是runspider, 这个命令的做用就是将一个spider当作一个python文件去执行,而不用建立一个完整的项目。能够说是最简单的一个爬虫项目了,只有一个文件,这也体现出了spider对于scrapy的重要性,item和pipline无关紧要,settings等也可使用默认的,但是spider必须本身构造。而咱们写爬虫的时候大部分时间和精力也是耗费在这里,因此spider的重要性就不言而喻了。python

此次教程将结合官方文档和源码一块儿来说解,但愿你们可以喜欢。dom

首先看看官方文档对于spider的介绍:scrapy

最上面一段就不解释了,就是介绍spider的做用和功能。对于spider来讲主要经历以下几件事:ide

1.根据url生成Request并指定回调方法处理Response。第一个Request是经过start_requests()产生的,该方法下面会讲到。
post

2. 在回调方法中,解析页面的Response,返回Item实例或者Request实例,或者这两种实例的可迭代对象。网站

3.在回调方法中,一般使用Selectors(也可使用BeautifulSoup,lxml等)来提取数据。this

4.最后spider会return item给Pipline完成数据的清洗,持久化等操做。url

scrapy为咱们提供了几款基础的spider,咱们须要继承这些来实现本身的spider。咱们接下来就根据资料及源码来了解它们。spa

class scrapy.spiders.Spider 下面是它的源码:

class Spider(object_ref):
    """Base class for scrapy spiders. All spiders must inherit from this
    class.
    """

    name = None
    custom_settings = None

    def __init__(self, name=None, **kwargs):
        if name is not None:
            self.name = name
        elif not getattr(self, 'name', None):
            raise ValueError("%s must have a name" % type(self).__name__)
        self.__dict__.update(kwargs)
        if not hasattr(self, 'start_urls'):
            self.start_urls = []

    @property
    def logger(self):
        logger = logging.getLogger(self.name)
        return logging.LoggerAdapter(logger, {'spider': self})

    def log(self, message, level=logging.DEBUG, **kw):
        """Log the given message at the given log level

        This helper wraps a log call to the logger within the spider, but you
        can use it directly (e.g. Spider.logger.info('msg')) or use any other
        Python logger too.
        """
        self.logger.log(level, message, **kw)

    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = cls(*args, **kwargs)
        spider._set_crawler(crawler)
        return spider

    def set_crawler(self, crawler):
        warnings.warn("set_crawler is deprecated, instantiate and bound the "
                      "spider to this crawler with from_crawler method "
                      "instead.",
                      category=ScrapyDeprecationWarning, stacklevel=2)
        assert not hasattr(self, 'crawler'), "Spider already bounded to a " \
                                             "crawler"
        self._set_crawler(crawler)

    def _set_crawler(self, crawler):
        self.crawler = crawler
        self.settings = crawler.settings
        crawler.signals.connect(self.close, signals.spider_closed)

    def start_requests(self):
        for url in self.start_urls:
            yield self.make_requests_from_url(url)

    def make_requests_from_url(self, url):
        return Request(url, dont_filter=True)

    def parse(self, response):
        raise NotImplementedError

    @classmethod
    def update_settings(cls, settings):
        settings.setdict(cls.custom_settings or {}, priority='spider')

    @classmethod
    def handles_request(cls, request):
        return url_is_from_spider(request.url, cls)

    @staticmethod
    def close(spider, reason):
        closed = getattr(spider, 'closed', None)
        if callable(closed):
            return closed(reason)

    def __str__(self):
        return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))

    __repr__ = __str__

该类的基类是object_ref,其定义以下图所示:

从源码中能够看到这个类的子类的实例都会记录它自己的存活情况,这个做用会在之后讲解,目前用不到。

类scrapy.spiders.Spider 是最简单的spider,全部的spider包括本身定义的和scrapy提供的都会继承它。它只是提供最基本的特性,也是我最经常使用的spider类。

name:

  这个属性是字符串变量,是这个类的名称,代码会经过它来定位spider,因此它必须惟一,它是spider最重要的属性。回头看看源码中__init__的定义,能够发现这个属性是能够修改的,若是不喜欢或者有须要重命名spider的name,能够在启动的时候传参修改name属性。

allowed_domains:

  这个属性是一个列表,里面记载了容许采集的网站的域名,该值若是没定义或者为空时表示全部的域名都不进行过滤操做。若是url的域名不在这个变量中,那么这个url将不会被处理。不想使用域名过滤功能时能够在settings中注释掉OffsiteMiddleware, 我的不建议这么作。

start_urls:

  这个属性是一个列表或者元组,其做用是存放起始urls,至关于此次任务的种子。使用默认模板建立spider时,该值是个元组,建立元组而且只有一个元素时须要在元素后面添加“,”来消除歧义,否则会报错:“ValueError: Missing scheme in request url: h”。这边常常有人出错,为了不这个错误能够根据上一章内容,将模板中start_urls的值设置为列表。

custom_settings:

  这个属性值是一个字典,存放settings键值对,用于覆盖项目中的settings.py的值,能够作到在一个项目中的不一样spider能够有不一样的配置。不过这个值要慎用,有些settings的值覆盖也没有起做用,eg:“LOG_FILE”。若是想每一个spider都有本身的log文件的话就不能这么作。由于日志操做在这个方法执行以前,那么不管怎么改都改不了以前的行为。不过这个问题scrapy研发团队已经注意到了,相信不久的未来会进行处理的。

crawler:

  这个值从源码能够看出来自于方法from_crawler()。该值是一个Crawler 实例, 其做用后面的教程会讲解,这边就不细说了。

 settings:

  这个值也是来自于方法from_crawler()。是一个Settings 实例,这个后面也会细说,稍安勿躁哈。

logger:

  顾名思义,记录日志用的,也是后面讲,耐心等候哈。

from_crawler:

  这是一个类方法,scrapy建立spider的时候会调用。调用位置在crawler.py 的类Crawler中,源码能够本身去看看,就不带你们看了。这个方法的源码在上面,咱们能够看到,在实例化这个spider之后,这个实例才有的settings和crawler属性,因此在__init__方法中是无法访问这俩属性的。若是非要在__init__方法中使用相关属性,那么只能重写该方法,你们能够尝试写写。

start_requests():

  这个方法必须返回一个可迭代对象,切记!!!!上面就有源码很简单,就不细说了。若是想对属性start_urls作一些操做(增删改),并但愿结果做为种子url去采集网站的时候,能够重写这个方法来实现。有了这个方法,甚至都不用在代码中定义start_urls。好比咱们想要读取持久化的url执行采集操做,那么就不必转存进start_urls里面,能够直接请求这些urls。当种子urls须要post请求的话,也须要重写该方法。

 make_requests_from_url(url):

  这个方法顾名思义,要是还不懂就看看上面的源码。这里只说一点,由于这里的Request初始化没有回调方法,就是默认采用parse方法做为回调。另外这里的dont_filter值为True,这个值的做用是该url不会被过滤,至于具体细节请听下回分解。

 parse(self, response):

  这个方法对于有经验的同窗来讲再熟悉不过了,我就简单的说说。这个方法做为默认回调方法,Request没有指定回调方法的时候会调用它,这个回调方法和别的回调方法同样返回值只能是Request, 字典和item对象,或者它们的可迭代对象。

 log(message[, level, component]):

  这个方法是对logger的包装,看看源码就好,没什么什么可说的。

closed(reason):

  当这个spider结束时这个方法会被调用,参数是一个字符串,是结束的缘由。这种用法之后会介绍,这里只需记住,想在spider结束时作一些操做时能够写在这里。

scrapy基础spider算是介绍完了,有兴趣的小伙伴能够对照一个好的实例来看这个文章,或许帮助更大。若是有什么疑问,你们能够在评论区讨论,共同进步。

相关文章
相关标签/搜索