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算是介紹完了,有興趣的小夥伴能夠對照一個好的實例來看這個文章,或許幫助更大。若是有什麼疑問,你們能夠在評論區討論,共同進步。

相關文章
相關標籤/搜索