zoukankan      html  css  js  c++  java
  • 第四章——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 = "
    "
    
        # 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都此篇感受

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

    努力拼搏吧,不要害怕,不要去规划,不要迷茫。但你一定要在路上一直的走下去,尽管可能停滞不前,但也要走。
  • 相关阅读:
    动态规划:POJ2576-Tug of War(二维费用的背包问题)
    动态规划:HDU3496-Watch The Movie(二维费用的背包问题)
    动态规划:HDU1712-ACboy needs your help(分组背包问题)
    水题:HDU1303-Doubles
    动态规划:HDU2844-Coins(多重背包的二进制优化)
    动态规划:HDU1059-Dividing(多重背包问题的二进制优化)
    动态规划:HDU1224-Free DIY Tour
    动态规划:HDU1864-最大报销额(处理带小数的dp问题)
    红黑树
    二叉树
  • 原文地址:https://www.cnblogs.com/wkhzwmr/p/15414726.html
Copyright © 2011-2022 走看看