Scrapy详解之Spiders

网络爬虫

浏览数:244

2019-2-22

AD:资源代下载服务

作者:Zarten
知乎ID: Zarten
简介: 互联网一线工作者,尊重原创并欢迎评论留言指出不足之处,也希望多些关注和点赞是给作者最好的鼓励 !

概念

Spiders类是你可以定义自己的逻辑规则来爬一个或多个网站然后作页面解析工作。在spiders文件夹下编写。

爬虫循环的步骤一般是下面4步:

1.定义爬虫初始的URL,然后设置回调函数来接收爬取的内容,默认start_urls = [] -> parse()函数自定义是start_request() -> my_parse()

2.在回调函数中返回一个可迭代容器(包括Item对象,dict,Request,或同时几个),一般yield返回(或return[,]),并设置针对返回Request的回调函数,如next_parse()

3.回调函数中就是下载的网页数据,在这里进行解析生成 yield item,可用BeautifulSoup,xpath,css,正则,自己习惯熟悉用哪个就用哪个

4.处理得到的item,数据库(Item Pipeline)或各种文件类型(Feed exports)

scrapy.Spider类

Spider这个类源码里面是在scrapy下面spiders包里面的_init_.py文件中,也可写成scrapy.spiders.Spider,这是一个最简单基础的爬虫类,我们编写的爬虫包括scrapy中其他爬虫类(CrawlSpider、XMLFeedSpider、CSVFeedSpider、SitemapSpider)都是继承的这个类

这个基础类中提供了一些属性和方法如下:

  • name

必须定义,爬虫的名称,字符串类型,这个名称唯一标识这个爬虫,所以不能重复

命令: scrapy crawl myspider 是开启爬虫的命令,这个myspider就是name名称

  • allowed_domains

可选定义,list类型,允许爬虫的域名列表,若不定义,则不做限制。例如

allowed_domains = [‘taobao.com’, ‘tmall.com’]

  • start_urls

list类型,开始爬虫的URL列表(可以一个或多个),可以不用定义,然后用start_requests()函数代替

  • custom_settings

字典类型,可以设置settings中的值,针对不同的爬虫设置不同的值,因为settings文件只有一个。例如:

custom_settings = {
        'ROBOTSTXT_OBEY' : False,
        'DOWNLOAD_DELAY' : 5
    }

拓展:关于设置settings中的值的几种方法,优先级从高到低如下:

1.命令行选项

2.custom_settings

3.settings.py文件

4.命令行的默认设置,每一个命令行都有它自己的默认设置

5.默认的全局设置,被定义在 scrapy.settings.default_settings 中

1.命令行选项

这个优先级最高

另外:用命令行设置 ITEM_PIPELINES 时没有成功,如果知道怎么设置的欢迎在评论里面留言!不过个人认为这种写起来相对麻烦点的在第二优先级custom_settings中设置就可以了。

2.custom_settings

第二优先级,仅次于命令行选项,可以根据不同爬虫定制不同设置

custom_settings = {
        'ROBOTSTXT_OBEY' : False,
        'DOWNLOAD_DELAY' : 5,
        'ITEM_PIPELINES' : {'quotesbot.pipelines.QuotesbotPipeline': 300}
    }

3.settings.py文件

第三优先级,在这个文件中设置,适用于所有爬虫。一般就是前三种情况,第4和第5种不作介绍。

  • crawler

这个属性是在初始化spiders类之后来设置的,通过from_crawler()类方法函数来设置,设置完后会有一个Crawler对象绑定这个爬虫对象,绑定后crawler就可以使用Crawler方法。

Crawler对象包含很多组件(扩展、中间件、信号管理等),是这些组件的入口

下面是绑定方式,在pipeline中:

@classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )

Crawler类将在后面章节中详细介绍

  • settings

Settings对象的一个实例。注意:使用settings必须要Spider初始化以后使用,例如不能在__init__函数中使用

    def parse(self, response):

        print('获取ROBOTSTXT_OBEY:', self.settings.getbool('ROBOTSTXT_OBEY'))
        print('获取settings的keys: ', self.settings.attributes.keys())

        for quote in response.xpath('//div[@class="quote"]'):
            yield {
                'text': quote.xpath('./span[@class="text"]/text()').extract_first(),
                'author': quote.xpath('.//small[@class="author"]/text()').extract_first(),
                'tags': quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').extract()
            }

  • logger

python的logger通过这个Spiders的name创建的,用它来发送日志信息

import scrapy

class MySpider(scrapy.Spider):

    name = 'myspider'
    start_urls = ['https://scrapinghub.com']

    def parse(self, response):
        self.logger.info('Parse function called on %s', response.url)

  • from_crawler(crawler, *args, **kwargs)

这是一个类方法,一般不用实现它,因为它默认实现在_init_()函数中

  • start_requests()

开始爬虫URL的函数,默认写法是 start_urls=[],返回一个待爬取URL可迭代的请求

下面例子是开始请求时返回一个可迭代的post请求,用yield或return[]

class MySpider(scrapy.Spider):
    name = 'myspider'

    def start_requests(self):
        return [scrapy.FormRequest("http://www.example.com/login",
                                   formdata={'user': 'john', 'pass': 'secret'},
                                   callback=self.logged_in)]

    def logged_in(self, response):
        # here you would extract links to follow and return Requests for
        # each of them, with another callback
        pass

  • parse(response)

这是start_urls=[]的默认回调函数,参数response是返回的数据

这个函数必须返回可迭代对象(Request、dict、Item)中的一个或多个

  • log(message[, level, component])

日志处理,跟logger属性差不多

  • closed(reason)

当爬虫spider被关闭时,这个方法会被调用,可以用来释放一些资源等

参数reason为字符串类型,为关闭爬虫的原因,reason可以为这3个值:‘finished’、’shutdown’、’cancelled’

finished :爬虫正常完成结束

shutdown:爬虫引擎被关闭,一般是 Ctrl-C

cancelled:手动调用 close_spider 方法关闭时默认是cancelled,也可以自己设定原因

    def closed(self, reason):
        print('spider关闭原因:', reason)

按Ctrl-C后:

正常完成后:

手动关闭爬虫,一般可抛出CloseSpider来手动关闭爬虫:


传递给spider参数

有时候我们需要从外界手动的传递参数给爬虫,我们可以用命令行-a 选项来传递,传递的参数必须是字符串类型的,例如:

scrapy crawl myspider -a my_name=Zarten -a zhihu_id=Zarten

那怎么接收参数呢?通过 __init__函数来接收


通用的Spiders

这些Spiders在上面也提到过,有(CrawlSpider、XMLFeedSpider、CSVFeedSpider、SitemapSpider)

CrawlSpider

这个类继承于上面我们讲述的Spiders类,在 class scrapy.spiders.CrawlSpider 中,在scrapy的源码中的位置在scrapy->spiders->crawl.py中

这个类可以自定义规则来爬取所有返回页面中的链接,如果对爬取的链接有要求,可以选择使用这个类,总的来说是对返回页面中的链接(URL)的操作,这个类除了有继承于Spider之外,还有新的属性:

1.rules

是一个Rule对象的tuple,每个Rule都定义了爬虫的规则,如果有多个Rule匹配到了一个相同的链接,则第一个将被匹配

Rule类跟CrawlSpider在同一文件中,class scrapy.spiders.Rule(link_extractor, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None)

参数说明:

  • link_extractor

LinkExtractor 的对象,从爬取到的页面中自定义规则来筛选出链接

from scrapy.linkextractors import LinkExtractor

LinkExtractor跟LxmlLinkExtractor用法一样,不过LxmlLinkExtractor已经废弃了,用LinkExtractor就行,下面列出部分LinkExtractor的参数说明,完整的说明点这里查看

allow:tuple类型,正则表达式匹配链接,如果没有定义,则匹配全部的链接

deny:跟allow相反,不匹配指定的链接

allow_domains:tuple,匹配域名

  • callback

回调函数,从link_extractor每次获取符合规则的url后返回页面用这个函数处理,不要用parse作为回调函数来解析,因为parse是CrawlSpider来实现逻辑的

  • cb_kwargs

传递参数给回调函数的字典类型

  • follow

布尔类型,指定这个规则从response中提取的链接是否需要跟进,若为True则会爬取一个页面和子页面(一直深入下去)所有的链接;如果callback为None,则follow默认为True,否则默认为False

  • process_links

回调函数,从link_extractor中获取到链接列表时会调用这个函数,主要用来过滤

  • process_request

回调函数,根据规则每个请求被提取时调用此函数,必须返回一个request或None,用来过滤请求

2.parse_start_url(response)

这是另一个新的属性,start_ruls 默认回调方法

from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor


class ToScrapeSpiderXPath(CrawlSpider):
    name = 'toscrape-xpath'
    start_urls = [
        'http://quotes.toscrape.com/',
    ]

    #第一个Rule包含了第二个Rule,不会执行第二个Rule
    #follow会一直循环嵌套的爬完所有的链接,直到没有链接可爬
    rules = (
        Rule(link_extractor= LinkExtractor(deny=('page/2')), callback= 'parse_item_first', follow= True),
        Rule(link_extractor=LinkExtractor(allow=('page/3')), callback= 'parse_item_second')

    )

    def parse_item_first(self, response):
        print('parse_item_first:', response.url)

    def parse_item_second(self, response):
        print('parse_item_second:', response.url)

    def parse_start_url(self, response):
        print('parse_start_url:', response.url)

还有其他如下的几个spider类,用的比较少,这里也就不作更加详细的讲解,需要详细了解的点这里

XMLFeedSpider

这个类用来爬取XML

CSVFeedSpider

这个类用来爬取csv

SitemapSpider

通过Sitemap来发现爬取的URL