Python網絡爬蟲(十九)——CrawlSpider

在之前 Scrapy 的基本使用當中,spider 如果要重新發送請求的話,就需要自己解析頁面,然後發送請求。而 CrawlSpider 則可以通過設置 url 條件自動發送請求。

CrawlSpider 是 Spider 的一個派生類,相對於 Spider 來說,功能進行了更新,使用也更加方便。

CrawlSpider

創建 CrawlSpider

和之前創建 spider 一樣,雖然可以在創建 Scrapy 項目之後手動構造 spider,但是 Scrapy 也給出了在終端下創建 CrawlSpider 的指令:

scrapy genspider -t crawl spidername domainname

在終端中使用上邊的指令就能夠使用 Scrapy 中的模板創建 CrawlSpider。

LinkExtractors

CrawlSpider 與 spider 不同的是就在於下一次請求的 url 不需要自己手動解析,而這一點則是通過 LinkExtractors 實現的。LinkExtractors 原型爲:

class LxmlLinkExtractor(FilteringLinkExtractor):

    def __init__(self, allow=(), deny=(), allow_domains=(), deny_domains=(), restrict_xpaths=(),
                 tags=('a', 'area'), attrs=('href',), canonicalize=False,
                 unique=True, process_value=None, deny_extensions=None, restrict_css=(),
                 strip=True, restrict_text=None):
        tags, attrs = set(arg_to_iter(tags)), set(arg_to_iter(attrs))
        lx = LxmlParserLinkExtractor(
            tag=lambda x: x in tags,
            attr=lambda x: x in attrs,
            unique=unique,
            process=process_value,
            strip=strip,
            canonicalized=canonicalize
        )

        super(LxmlLinkExtractor, self).__init__(lx, allow=allow, deny=deny,
                                                allow_domains=allow_domains, deny_domains=deny_domains,
                                                restrict_xpaths=restrict_xpaths, restrict_css=restrict_css,
                                                canonicalize=canonicalize, deny_extensions=deny_extensions,
                                                restrict_text=restrict_text)

其中的參數爲:

  • allow:允許的 url。所有滿足這個正則表達式的 url 都會被提取
  • deny:禁止的 url。所有滿足這個正則表達式的 url 都不會被提取
  • allow_domains:允許的域名。只有在這個裏面指定的域名的 url 纔會被提取
  • deny_domains:禁止的域名。所有在這個裏面指定的域名的 url 都不會被提取
  • restrict_xpaths:嚴格的 xpath。和 allow 共同過濾鏈接

Rule

LinkExtractors 需要傳遞到 Rule 類對象中才能發揮作用。Rule 類爲:

class Rule:

    def __init__(self, link_extractor=None, callback=None, cb_kwargs=None, follow=None,
                 process_links=None, process_request=None, errback=None):
        self.link_extractor = link_extractor or _default_link_extractor
        self.callback = callback
        self.errback = errback
        self.cb_kwargs = cb_kwargs or {}
        self.process_links = process_links or _identity
        self.process_request = process_request or _identity_process_request
        self.process_request_argcount = None
        self.follow = follow if follow is not None else not callback

常見的參數爲:

  • link_extractor:LinkExtractor 對象,用於定義爬取規則
  • callback:對於滿足該規則的 url 所要執行的回掉函數,類似於之前提到的 scrapy.Request() 中的callback。而 CrawlSpider 使用了 parse 作爲回調函數,因此不要覆蓋 parse 作爲回調函數自己的回調函數
  • follow:從 response 中提取的鏈接是否需要跟進
  • process_links:從 link_extractor 中獲取到鏈接後會傳遞給這個函數,用來過濾不需要爬取的鏈接

除了上述的這些差別,Crawlspider 和 spider 基本沒有什麼差別了。

settings.py

仍舊需要設置:

  • ROBOTSTXT_OBEY:設置爲 False,否則爲 True。True 表示遵守機器協議,此時爬蟲會首先找 robots.txt 文件,如果找不到則會停止
  • DEFAULT_REQUEST_HEADERS:默認請求頭,可以在其中添加 User-Agent,表示該請求是從瀏覽器發出的,而不是爬蟲
  • DOWNLOAD_DELAY:表示下載的延遲,防止過快
  • ITEM_PIPELINES:啓用 pipelines.py

items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html

import scrapy


class StepItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    title = scrapy.Field()
    author = scrapy.Field()
    pub_time = scrapy.Field()
    content = scrapy.Field()

spider

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
from step.items import StepItem

class WechatSpider(CrawlSpider):
    name = 'wechat'
    allowed_domains = ['www.wxapp-union.com']
    start_urls = ['http://www.wxapp-union.com/portal.php?mod=list&catid=2&page=1']

    rules = (
        # 該 Rule 沒有 callback 參數,說明不需要對符合該條件的 url 執行回調操作
        Rule(LinkExtractor(allow=r'.+page=\d'), follow=True),
        # 該 Rule 存在 callback 參數,說明需要對符合該條件的 url 執行回調操作
        Rule(LinkExtractor(allow=r'.+article-.+\.html'),callback='parse_item',follow=False)
    )

    def parse_item(self, response):
        title = response.xpath("//h1[@class='ph']/text()").get()
        author =response.xpath("//p[@class='authors']/a/text()").get()
        pub_time = response.xpath("//p[@class='authors']/span/text()").get()
        content = response.xpath("//div[@class='content_middle cl']//text()").getall()
        content = ''.join(content).strip()
        item = StepItem(title=title,author=author,pub_time=pub_time,content=content)
        yield item

pipelines.py

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy.exporters import JsonLinesItemExporter

class StepPipeline:
    def __init__(self):
        self.fp = open('wechat.json','wb')
        self.export = JsonLinesItemExporter(self.fp,ensure_ascii=False,encoding='utf-8')

    def open_spider(self,spider):
        print('spider begin.')

    def process_item(self, item, spider):
        self.export.export_item(item)
        return item

    def close_spider(self,spider):
        self.fp.close()
        print('spider over.')

在 CrawlSpider 中需要注意的就是 spider 的寫法,別的和之前差不多。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章