第四章——scrapy爬虫

来自Scrapy 网络爬虫实战的阅读笔记
更多细节可看官网

编写爬虫

scrapy基本类组件说明
scrapy中的Selector选择器
Scrapy通用爬虫介绍与使用

Scrapy爬虫的主要实现

Scrapy主要通过Spider类来实现爬虫的相关功能,通俗来讲,Spider类定义了爬取某个或某些网站的规则,包括爬取数据和提取数据。

Spider循环爬取步骤如下:

1.通过start_requests()以start_urls中的URL初始化Request,下载完毕后返回Response,作为参数传给回调函数parse。
2.使用parse函数分析Response,可以返回Item对象、dict、Request或一个包含三者的可迭代容器。其中,Request可以经过Scrapy继续下载内容,调用设置的回调函数。
3.在parse函数内使用Selector分析Response,提取相应的数据。

scrapy.Spider爬虫基本类

编写爬虫的脚本(spiders文件夹下)是通过继承scrapy.Spide类来实现的,每个其他的Spider必须继承自该类(包括Scrapy自带的其他Spider以及自定义编写的Spider)。Spider类没有提供什么特殊的功能,仅仅提供了start_requests()的默认实现,读取并请求Spider属性中的start_urls,并根据返回的结果(Resulting Responses)调用Spider的parse方法。

Spider类常用属性(也就是spiders文件夹下的爬虫脚本)

name
name属性是必须且唯一的,其定义了Spider的名字,而Scrapy通过Spider的名字来定位并初始化Spider
allow_domain
该属性可选,其包含允许Spider爬取的域名列表。当中间件OffsiteMiddleWare启用时,将不会跟进不再列表中的域名
start_urls
是一个URL列表列表,当没有指定特定URL时,Spider将从该列表中开始获取页面数据,后续的URL将从获取的数据中提取。
custom_settings
该属性可选,是一个dict。当Spider启动时,会覆盖项目的设置,由于设置必须在初始化前被更新,因此必须设定为class属性。(疑惑)反正这个不常用

实例spider脚本文件(现在就是弄不懂script的终端的那一堆输出)

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


class Quotes(CrawlSpider):
	# 爬虫名称
    name = "get_quotes"
    allow_domain = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']

# 设定规则
    rules = (
        # 对于quotes内容页URL,调用parse_quotes处理,
      		# 并以此规则跟进获取的链接;前面是对应url规则,后面是提取返回响应的相关数据
            # 这些爬取的都是根路由之后的规则
        Rule(LinkExtractor(allow=r'/page/\d+'), callback='parse_quotes', follow=True),
      		# 对于author内容页URL,调用parse_author处理,提取数据
        Rule(LinkExtractor(allow=r'/author/\w+'), callback='parse_author')
    )

# 提取内容页数据方法
    def parse_quotes(self, response):
        for quote in response.css(".quote"):
            # 这里使用extract_first()就是确保返回的是字符串把
            yield {'content': quote.css('.text::text').extract_first(), # 返回第一条数据内容
                   'author': quote.css('.author::text').extract_first(), # 返回第一条该作者
                   'tags': quote.css('.tag::text').extract() # 返回该标签
                   }
	# 获取作者数据方法

    def parse_author(self, response):
        name = response.css('.author-title::text').extract_first()
        author_born_date = response.css('.author-born-date::text').extract_first()
        author_bron_location = response.css('.author-born-location::text').extract_first()
        author_description = response.css('.author-description::text').extract_first()

        return ({'name': name,
                 'author_bron_date': author_born_date,
                 'author_bron_location': author_bron_location,
                 'author_description': author_description
                 })

从上面实例中我们可以提取出来的东西

parse(response)方法的基本写法;也就是上方的parse_quotes()和parse_author()等函数;这个名字可以自行取,但是去了之后一定要在rules中的callback=xxx来调用它
parse(response)方法也是Scrapy默认回调方法,若我们并没有在生成的Request之后指定回调函数,他也会默认调用框架自带的parse()函数(虽然我不知道该函数在框架中的源码位置)
该函数主要负责处理Response,返回抓取的数据,或者跟进的URL。该方法必须返回可迭代的Request、dist或Item对象
基本写法如下

def parse(self, response):
      for quote in response.css(".quote"):
          yield {'content': quote.css('.text::text').extract_first(),
                 'author': quote.css('.author::text').extract_first(),
                 'tags': quote.css('.tag::text').extract()
                 }

Selector选择器

Scrapy通过实现一套构建于lxml库上名为选择器(Selector)的机制来提取数据,主要通过特定的Xpath或者css表达式来选择html文件中的某个指定部分。
选择器列表不一定是列表,还有可能时字符串等数据格式
1.XPath:传入XPath表达式,返回表达式对应节点的选择器列表
2.css:传入CSS表达式,但会表达式对应节点的选择器列表(这里注意获取文本和属性使用的与常用的css表达式不太相同
a::text()/加了括号就必须是键值对形式的数据; a::attr())** 这种加了::的方式就是提取相应的属性**
3.extract:以列表形式返回被选择元素的Unicode字符串。通常被用来提取数据,extract_first()返回第一条数据
4.re():返回通过正则表达式提取的Unicode字符串列表。re_first('re正则表达式')返回第一条数据

通用爬虫

CrawlSpider

是抓取网站常用的Spider,他提供了一个通过指定一些规则来达到跟进链接的方便机制。
这些规则也就是rules属性,他是一个或一组Rule对象,必须写成tuple形式。
每一个Rule对象定义了对目标网站的爬取行为,如果有多个Rule对象匹配了同一个链接,就说明第一个Rule会失效。

爬行规则

classscrapy.spiders.Rule(link_extractor=None, callback=None, cb_kwargs=None, follow=None, process_links=None, process_request=None, errback=None)[源代码]¶
link_extractor 是一种 Link Extractor 对象,该对象定义如何从每个爬网页面提取链接。每个生成的链接将用于生成 Request 对象,该对象将在其 meta 词典(在 link_text 密钥)。如果省略,将使用不带参数创建的默认链接提取器,从而提取所有链接。
callback 是要为使用指定链接提取器提取的每个链接调用的可调用或字符串(在这种情况下,将使用来自具有该名称的爬行器对象的方法)。此回调接收一个 Response 作为其第一个参数,并且必须返回单个实例或 item objects 和/或 Request 对象(或其任何子类)。如上所述,收到的 Response 对象将包含生成 Request 在ITS中 meta 词典(在 link_text 密钥)

cb_kwargs 是包含要传递给回调函数的关键字参数的dict。

follow 是一个布尔值,用于指定是否从使用此规则提取的每个响应中遵循链接。如果 callback 没有 follow 默认为 True ,否则默认为 False .

process_links 是一个可调用的,或一个字符串(在这种情况下,将使用具有该名称的蜘蛛对象中的方法),对于使用指定的 link_extractor . 这主要用于过滤目的。

process_request 是一个可调用的(或字符串,在这种情况下,将使用来自具有该名称的爬行器对象的方法),它将在 Request 按此规则提取。此可调用对象应将上述请求作为第一个参数,并且 Response 作为第二个参数从其发出请求。它必须返回一个 Request 对象或 None (用过滤发出请求)。

errback 在处理规则生成的请求时引发任何异常时要调用的可调用或字符串(在这种情况下,将使用来自spider对象的具有该名称的方法)。它收到一个 Twisted Failure 实例作为第一个参数。

XMLFeedSpider

主要用于RSS源订阅内容的抓取。RSS源是基于XML的一种信息聚合技术。在XML文件中,item称为一个node节点。
迭代器可以从以下选项中选择: iternodes , xml 和 html . 建议使用 iternodes 由于性能原因,迭代器 xml 和 html 迭代器一次生成整个DOM以便解析它。然而,使用 html 因为迭代器在分析带有错误标记的XML时可能很有用。
要设置迭代器和标记名,必须定义以下类属性:

XMLFeedSpider中的一些属性

iterator:指定迭代器,迭代器主要用于分析数据RSS订阅源。
可用的迭代器有:
iternodes:性能高,基于正则表达式,是默认的迭代器,在属性中不指定的话就默认是他
html:使用Selector加载所有DOM结构进行分析,当数据量大是就会产生性能问题,有点事处理不合理标签是比较有用。
xml:同html一样使用Selector进行分析,同样有性能问题
itertag:指定需要迭代的节点
namespaces:以元组形式组成的列表,定义了Spider处理文档时可用的命名空间。(这个属性有啥用)

XMLFeedspider同样具有可复写的方法

adapt_response(response):此方法在处理分析Response之前被调用,可用于修改Response的内容。此方法返回类型为Response。
parse_node(response,selector):当匹配到节点时,调用此方法进行数据处理。很重要的一点就是此方法必须复写,否则爬虫不会正常工作。该方法必须返回一个Item、Request,或者一个包含Item或Request的迭代器。
process_result(response,result):当爬虫返回抓取结果时调用此方法。多用于在抓取结果传递给框架核心处理前做最好的修改。该方法必须接收一个结果列表和产生这些结果的Response,返回一个包含Item或Request的就跟列表。

实例

1.使用XMLFeedSpider模板创建爬虫(这是创建爬虫文件,之间爬虫项目已经创建)

scrapy genspider -t xmlfeed jobbole jobbole.com

2.使用Item收集数据,修改items.py文件

import scrapy
class JobboleItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # 文章标题
    title = scrapy.Field()
    # 发表日期
    public_date = scrapy.Field()
    # 文章链接
    link = scrapy.Field()

3.jobbole.py文件编写(具体爬虫文件)

# -*- coding: utf-8 -*-
from scrapy.spiders import XMLFeedSpider
# 导入item
from xmlfeedspider.items import JobboleItem


class JobboleSpider(XMLFeedSpider):
    name = 'jobbole'
    allowed_domains = ['jobbole.com']
    start_urls = ['http://top.jobbole.com/feed/']
    iterator = 'iternodes'  # 迭代器,不指定的话默认是iternodes
    itertag = 'item'  # 抓取item节点

    def parse_node(self, response, selector):
        item = JobboleItem() # items.py中的类实例化
        # 字典的值均在JobboleItem()类中定义,大部分类型为scrapy.Field()
        item['title'] = selector.css('title::text').extract_first()
        item['public_date'] = selector.css('pubDate::text').extract_first()
        item['link'] = selector.css('link::text').extract_first()
        return item

4.修改settings.py的配置

ROBOTSTXT_OBEY = False 

CSVFeedSpider

他是每行迭代,而XMLfeedSpider是根据节点来迭代数据。类似的,每行迭代调用的是parse_row()方法。

常用的属性方法如下

delimiter:字段分隔符,默认是英文逗号','
quotechar:CSV字段中如果包含回车、引号、逗号,那么此字段必须用双引号引起来,默认是半角双引号。
headers:CSV文件的标题头,该属性是一个列表
parse_row(response,row):对每一行数据进行处理,接收一个由Response、一个文件标题头组成的字典。

实例

使用Item收集数据,修改items.py文件

import scrapy


class CsvspiderItem(scrapy.Item):
    # define the fields for your item here like:
    # 姓名
    name = scrapy.Field()
    # 研究领域
    SearchField = scrapy.Field()
    # 服务分类
    Service = scrapy.Field()
    # 专业特长
    Specialty = scrapy.Field()

具体爬虫文件
在控制台中yield输出之前都有[scrapy.core.scraper]

# -*- coding: utf-8 -*-
from scrapy.spiders import CSVFeedSpider
from csvfeedspider.items import CsvspiderItem


class CsvparseSpider(CSVFeedSpider):
    name = 'csvdata'
    allowed_domains = ['gzdata.gov.cn']
    start_urls = ['http://gzopen.oss-cn-guizhou-a.aliyuncs.com/科技特派员.csv']
    headers = ['name', 'SearchField', 'Service', 'Specialty']
    delimiter = ','
    quotechar = "\n"

    # Do any adaptations you need here
    def adapt_response(self, response): # 特定的编码处理的函数
        print('我也没看过return怎么返回的', response.body.decode('gb18030'))
        return response.body.decode('gb18030') # 编码处理

    def parse_row(self, response, row):

        i = CsvspiderItem()
        try:
            i['name'] = row['name']
            i['SearchField'] = row['SearchField']
            i['Service'] = row['Service']
            i['Specialty'] = row['Specialty']

        except:
            pass
        # 在控制台中yield输出之前都有[scrapy.core.scraper]
        yield i # yield是输出,return我没看出打印在了控制台


SitemapSpider

允许通过Sitemap发现URL链接来爬取一个网站。
而Sitemap是包含网站所有网址以及每个网址的其他元数据,包括上次更新的时间、更改的频率以及相对于网站上其他网址的重要程度为何等。

常用属性

sitemap_urls:一个包含待爬取url的sitemap列表,也可以指定rebots.txt,表示从rebots.txt中提取url.
sitemap_rules:一个元组列表,形如(regex,callback),其中:
reqex:表示需要从sitemap中提取的url的正则表达式,可以是一个字符串或者正则表达式对象
callback:式处理对应的url的回调方法,提取到对应链接时调用parse函数处理。需要注意的是,相同的链接只会调用第一个方法处理,并且如果此属性并未指定,那所有的链接默认使用parse方法处理。
sitemap_follow:一个指定需要跟进的sitemap的正则表达式列表。当使用Sitemap index files来指向其他sitemap文件的站点时此属性有效。默认情况下,所有的sitemap都会被根进。
sitemap_alternate_links:指定当一个url有可选的链接时是否跟进,有些网站url块内会提供备用网址。

实例

使用Item收集数据,修改items.py文件

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

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

import scrapy


class CnblogsItem(scrapy.Item):
    # define the fields for your item here like:
    # 文章标题
    title = scrapy.Field()
    # 文章url
    url = scrapy.Field()
    # 文章作者
    author = scrapy.Field()

编写爬虫脚本文件

from scrapy.spiders import SitemapSpider
from cnblogs.items import CnblogsItem

class MySpider(SitemapSpider):
    name = 'articles'
    # Sitemap 地址
    sitemap_urls = ['http://www.cnblogs.com/sitemap.xml']
    # 从Sitemap中提取url的规则,并指定回调方法
    sitemap_rules = [
        # 抓取 ***/cate/python/**的url,调用parse_python处理
        ('/cate/python/','parse_python')
    ]

    # 回调方法
    def parse_python(self,response):
        articles = response.css('.post_item')

        for article in articles:
            item = CnblogsItem()
            # 文章标题
            item['title'] = article.css('.titlelnk::text').extract_first()
            # 文章url
            item['url'] = article.css('.titlelnk::attr(href)').extract_first()
            # 文章作者
            item['author'] = article.css('.lightblue::text').extract_first()
            yield item

来自2021/12/13都此篇感受

这书上的没点基础可以说是完全会看不懂的,实例的举例太少了,还不如官网,虽然翻译成中文很撇脚。

posted @ 2021-10-16 17:36  索匣  阅读(111)  评论(0编辑  收藏  举报