zoukankan      html  css  js  c++  java
  • scrapy系列(三)——基础spider源码解析

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

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

    这次教程将结合官方文档和源码一起来讲解,希望大家能够喜欢。

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

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

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

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

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

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

    scrapy为我们提供了几款基础的spider,我们需要继承这些来实现自己的spider。我们接下来就根据资料及源码来了解它们。

    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算是介绍完了,有兴趣的小伙伴可以对照一个好的实例来看这个文章,或许帮助更大。如果有什么疑问,大家可以在评论区讨论,共同进步。

  • 相关阅读:
    Eclipse 插件安装、升级和卸载的方法
    Eclipse中Spring插件的安装
    为eclipse离线安装hibernate tools插件
    Eclipse中Hibernate插件的安装
    Nginx安装配置
    app自动更新(android)
    PhoneGap应用图标icon和启动页面SplashScreen
    highcharts图表的图例legend
    安装android的sdk
    设置全屏
  • 原文地址:https://www.cnblogs.com/3wtoucan/p/6020060.html
Copyright © 2011-2022 走看看