• Day 45 爬虫_scrapy框架_CrawlSpider的全站数据


    CrawlSpider的全站数据

    CrawlSpider:类,Spider的一个子类

    全站数据爬去的方式

    1、基于Spider:手动请求

    2、基于CrawlSpider

    CrawlSpider的使用:

    1、创建工程:scrapy startproject XXX

    2、cd XXX

    3、创建爬虫文件(CrawlSpider)

      创建项目:scrapy genspider -t crawl xxx www.xxx.com

      链接提取器:根据指定的规则(allow)进行指定连接的提取

      规则解析器:将谅解提取到的链接进行指定规则(callback)的解析

    需求:爬取 sun 网站中的编号,新闻标题,新闻内容,编号

    分析:爬取的数据没有在同一张页面中

    1、可以使用链接提取器提取所有的页码链接

    2、让联机提取器提取所有的新闻详情页的链接

    代码示例:

    baiduPro.py

    from scrapy.linkextractors import LinkExtractor
    from scrapy.spiders import CrawlSpider, Rule
    from baidu.items import BaiduItem,BaiduItem_detail
    
    class BaiduproSpider(CrawlSpider):
        name = 'baiduPro'
        # allowed_domains = ['https://www.baidu.com/s?wd=wangyi']
        start_urls = ['http://wz.sun0769.com/political/index/politicsNewest']
    
        # 连接提取器:根据指定的(allow=“正则”)进行指定连接的提取
        Link = LinkExtractor(allow=r'id=d+&page=d+')
        Link_detail = LinkExtractor(allow=r'/political/politics/index?id=d+')
        rules = (
            # 规则解析器:将连接提取器提取到的链接进行指定规则(callback)的解析操作
            # follow=True:可以将链接提取器 继续作用到 连接提取器提取到的链接 所对应的页面中
            Rule(Link, callback='parse_item', follow=False),
            Rule(Link_detail, callback='detail_item')
        )
    
        # 以下两个解析方法无法实现请求传参,因为没有使用手动化请求
        # 也就是说以下两部分内容无法存储到同一个 item 中,可以存储到两个 item 中
        def parse_item(self, response):
            li_title = response.xpath('/html/body/div[2]/div[3]/ul[2]/li')
    
            for li in li_title:
                title_num = li.xpath('./span[@class="state1"]/text()').extract_first()
                title = li.xpath('.//a[@class="color-hover"]/text()').extract_first()
    
    
                item = BaiduItem()
                item['title_num'] = title_num
                item['title'] = title
                yield item
    
        def detail_item(self, response):
            print(response)
            detail_num = response.xpath('/html/body/div[3]/div[2]/div[2]/div[1]/span[4]/text()').extract_first()
            detail = response.xpath('/html/body/div[3]/div[2]/div[2]/div[2]/pre/text()').extract_first()
            detail_num = detail_num.split('')[1]
            detail = ''.join(detail)
    
            item = BaiduItem_detail()
            item['detail_num'] = detail_num
            item['detail'] = detail
            yield item

    items.py

    import scrapy
    
    
    class BaiduItem(scrapy.Item):
        # define the fields for your item here like:
        title_num = scrapy.Field()
        title= scrapy.Field()
    
    
    class BaiduItem_detail(scrapy.Item):
        detail_num = scrapy.Field()
        detail = scrapy.Field()

    pipelines.py

    import pymysql
    
    
    class BaiduPipeline(object):
        def open_spider(self, spider):
            print('写入数据库。。。')
            self.conn = pymysql.Connect(host='192.168.214.23', port=3306, user='root', password='123456', db='srcapy',
                                        charset='utf8')
    
        def process_item(self, item, spider):
            # 如何判断 item 类型
            # 将数据写入数据库时,如何保证数据的一致性
            self.cursor = self.conn.cursor()
            if item.__class__.__name__ == 'BaiduItem':
                try:
                    self.cursor.execute(
                        'insert into scr_sum(title_num,title) value ("%s","%s")' % (item['title_num'], item['title']))
                    self.conn.commit()
                except Exception as e:
                    print(e)
                    self.conn.rollback()
                pass
            elif item.__class__.__name__ == 'BaiduItem_detail':
                try:
                    self.cursor.execute(
                        'update scr_sum set detail_num = "%s",detail = "%s" where title_num = "%s"' % (
                            item['detail_num'], item['detail'], item['detail_num']))
                    self.conn.commit()
                except Exception as e:
                    print(e)
                    self.conn.rollback()
                # print(type(item['detail']),item['detail'])
            return item
    
        def close_spider(self, spider):
            print('入库完成')
            self.cursor.close()
            self.conn.close()

    settings.py

    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 OPR/67.0.3575.137 (Edition B2)'
    
    ROBOTSTXT_OBEY = False
    
    LOG_LEVEL = 'ERROR'
    
    ITEM_PIPELINES = {
       'baidu.pipelines.BaiduPipeline': 300,
    }

    分布式爬虫

    概念:我们需要搭建一个分布式集群,让其对一组资源进行分布联合爬取

    作用:提升爬取数据的效率

    如何实现分布式

    1、安装一个 scrapy-redis 的组件

    2、原生的 scrapy 是不可以实现分布式爬虫,必须要让 scrapy 结合着scrapy-redis组件一起实现分布式爬虫

    3、为什么原生的 scrapy 不可以实现分布式?

      1、调度器不可以被分布式集群共享

      2、管道你可以被分布式集群共享

    scrapy-redis组件作用:可以给原生的 scrapy 框架提供可以被共享的管道和调度器

    实现流程

    1、创建一个工程:scrapy startproject fbs

    2、创建一个基于 CrawlSpider 的爬虫文件:scrapy genspider -t crawl fbsPro www.xxx.com

    3、修改当前爬虫文件

      1、导包:from scrapy_redis.spiders import RedisCrawlSpider

      2、将当前爬虫文件的父类修改为:RedisCrawlSpider

      3、将 allowed_domains 与 start_urls 两行注释掉

      4、添加一个新属性:redis_key = 'fbs'  可以被共享的调度器队列的名称

      5、编写数据解析操作

    4、修改配置文件 settins

    # 指定使用可以被共享的管道
    ITEM_PIPELINES = {
        'scrapy_redis.pipelines.RedisPipeline': 400
    }
    # 指定调度器
    # 增加了一个去重容器类的配置, 作用使用Redis 的 set 集合来存储请求的指纹数据, 从而实现请求去重的持久化
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    # 使用 scrapy-redis 组件自己的调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis 中请求队列和去重指纹的 set。如果是True, 就表示要持久化存储, 就不清空数据,否则清空数据
    SCHEDULER_PERSIST = True

    5、redis相关操作配置:

      1、配置redis的配置文件:
        linux或者mac:redis.conf
        windows:redis.windows.conf
      2、代开配置文件修改:
        将bind 127.0.0.1进行删除
        关闭保护模式:protected-mode yes改为no
      3、结合着配置文件开启redis服务
        redis-server 配置文件
      4、启动客户端:redis-cli

    6、执行工程:scrapy runspider xxx.py

    7、向调度器的队列中放入一个起始的url:
       调度器的队列在redis的客户端中:lpush xxx www.xxx.com
        
    最后,爬取到的数据存储在了 redis 的 proName:items 这个数据结构中

    增量式爬虫

    概念:监测网站数据更新的情况,只会爬取网站最新更新出来的数据。
    分析:
      1、指定一个起始url
      2、基于CrawlSpider获取其他页码链接
      3、基于Rule将其他页码链接进行请求
      4、从每一个页码对应的页面源码中解析出每一个电影详情页的URL

      5、核心:检测电影详情页的url之前有没有请求过
        将爬取过的电影详情页的url存储,存储到redis的set数据结构
        

      6、对详情页的url发起请求,然后解析出电影的名称和简介
      7、进行持久化存储

  • 相关阅读:
    繁星
    [转] android 中 任务、进程和线程的区别
    Android read-only file system解决方法
    [转] 用管道获得shell 命令的输出
    [转] Bound Service的三种方式(Binder、 Messenger、 AIDL)
    [转] Android LocalService与RemoteService理解
    Android 中的 Service 全面总结
    [转] 英语连接词~很全的版本!!!
    Questioning
    大数据笔记
  • 原文地址:https://www.cnblogs.com/ysging/p/12722265.html
Copyright © 2020-2023  润新知