zoukankan      html  css  js  c++  java
  • 19.基于scrapy-redis两种形式的分布式爬虫

    redis分布式部署

      1.scrapy框架是否可以自己实现分布式?

        - 不可以。原因有二。

          其一:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。(多台机器无法共享同一个调度器)

          其二:多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。(多台机器无法共享同一个管道)

     2.基于scrapy-redis组件的分布式爬虫

            - scrapy-redis组件中为我们封装好了可以被多台机器共享的调度器和管道,我们可以直接使用并实现分布式数据爬取。

            - 实现方式:

                1.基于该组件的RedisSpider类

                2.基于该组件的RedisCrawlSpider类

     3.分布式实现流程:上述两种不同方式的分布式实现流程是统一的

            - 3.1 下载scrapy-redis组件:pip3 install scrapy-redis

            - 3.2 redis配置文件的配置:

        — 注释该行 :bind 127.0.0.1  或  将 ip 更改为 0.0.0.0 ,表示可以让其他ip访问redis
    
        — 在这一行 将yes改为no : protected-mode no,表示可以让其他ip操作redis

       -3.3 修改爬虫文件相关代码

         - 1.导入scrapy-redis模块:   from scrapy_redis.spiders import RedisSpider/RedisCrawlSpider

         - 2.将当前爬虫类的父类修改成RedisSpider/RedisCrawlSpider

         - 3.将allowed_domains和start_urls进行删除

         - 4.添加一个新的属性redis_key = 'xxx',该属性值表示的就是可以被共享的调度器队列的名称

       总结:将爬虫类的父类修改成基于RedisSpider或者RedisCrawlSpider。

          注意:如果原始爬虫文件是基于Spider的,则应该将父类修改成RedisSpider,

               如果原始爬虫文件是基于CrawlSpider的,则应该将其父类修改成RedisCrawlSpider。

       -3.4 在配置文件中进行相关配置

          1.开启使用scrapy-redis组件中封装好的管道,保证爬虫文件提交的item会被封装到共享管道中 

            ITEM_PIPELINES = {
               'scrapy_redis.pipelines.RedisPipeline': 400
            }

          2.开启使用scrapy-redis组件中封装好的调度器 

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

          3.在配置文件中进行爬虫程序链接redis的配置:

          REDIS_HOST = 'redis服务的ip地址'
          REDIS_PORT = 6379
          REDIS_ENCODING = ‘utf-8’
          REDIS_PARAMS = {‘password’:’123456’}  #如果没有设置密码,可以不写

        -3.5  开启redis服务器:redis-server 配置文件

        -3.6  开启redis客户端:redis-cli

        -3.7  运行爬虫文件:scrapy runspider SpiderFile

       -3.8  向调度器队列中扔入一个起始url(在redis客户端中操作):lpush redis_key属性值 起始url

     示例一:

       基于Spider的,spider-redis分布式爬虫

       爬取医疗器械每个网页中,医疗器械的注册编码,注册名称,生产地址

       http://db.pharmcube.com/database/cfda/detail/cfda_cn_instrument/1

       爬虫文件:

      # -*- coding: utf-8 -*-
      import scrapy
      from scrapy_redis.spiders import RedisSpider
      from scrapy_redis_Pro.items import ScrapyRedisProItem
    
      class RedisdemoSpider(RedisSpider):
          name = 'redisDemo'
          url = 'http://db.pharmcube.com/database/cfda/detail/cfda_cn_instrument/%d'
          page = 1
          # allowed_domains = ['www.xxx.com']
          # start_urls = ['http://www.xxx.com/']
    
          redis_key = "mwh"
    
          def parse(self, response):
              # 获取解析到数据
              register_num = response.xpath('/html/body/div/table/tbody/tr[1]/td[2]/text()').extract_first()
              register_name = response.xpath('/html/body/div/table/tbody/tr[2]/td[2]/text()').extract_first()
              production_address = response.xpath('/html/body/div/table/tbody/tr[4]/td[2]/text()').extract_first()
    
              # 实例化一个item类,并将解析到数据封装该类中
              item = ScrapyRedisProItem()
              item["register_num"] = register_num
              item["register_name"] = register_name
              item["production_address"] = production_address
    
              # 将解析到数据传递给管道文件中
              yield  item
    
              if self.page <130000:
                  self.page += 1
                  new_url = format(self.url%self.page)
                  yield scrapy.Request(url=new_url,callback=self.parse)

        item.py 文件

      import scrapy
    
      class ScrapyRedisProItem(scrapy.Item):
          # define the fields for your item here like:
          register_num = scrapy.Field()  # 注册编号
          register_name = scrapy.Field() # 注册名称
          production_address = scrapy.Field() # 生产地址

       pipelines.py  管道文件

      class ScrapyRedisProPipeline(object):
          def process_item(self, item, spider):
              print(item)
              return item

       setting.py 配置文件

    BOT_NAME = 'scrapy_redis_Pro'

    SPIDER_MODULES = ['scrapy_redis_Pro.spiders']
    NEWSPIDER_MODULE = 'scrapy_redis_Pro.spiders'
    USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    ROBOTSTXT_OBEY = False
    # 使用scrapy-redis中封装好的可以被共享的管道
    ITEM_PIPELINES = {
        'scrapy_redis.pipelines.RedisPipeline': 400
    }
    
    # 开启使用scrapy-redis组件中封装好的 可以被共享调度器
    # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
    # 使用scrapy-redis组件自己的调度器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据
    SCHEDULER_PERSIST = True
    
    #配置redis
    REDIS_HOST = '192.168.12.29'
    REDIS_PORT = 6380
    REDIS_ENCODING = 'utf-8'

    示例二:

      基于CrawlSpider的,spider-redis分布式爬虫

      爬取抽屉网站网页中每一新闻的标题和作者

      https://dig.chouti.com/all/hot/recent/1

      爬虫文件

      import scrapy
      from scrapy.linkextractors import LinkExtractor
      from scrapy.spiders import CrawlSpider, Rule
      from scrapy_redis.spiders import RedisCrawlSpider
      from scrapy_Crawl_Redis_Pro.items import ScrapyCrawlRedisProItem
    
      class CrawlRedisSpider(RedisCrawlSpider):
          name = 'crawl_redis'
          # allowed_domains = ['www.xxx.com']
          # start_urls = ['http://www.xxx.com/']
          redis_key = "drawer"
    
          rules = (
              Rule(LinkExtractor(allow=r'/r/scoff/hot/d+'), callback='parse_item', follow=True),
          )
      
          def parse_item(self, response):
              div_list = response.xpath('//div[@id="content-list"]/div')
              for div in div_list:
                  item = ScrapyCrawlRedisProItem()
                  item['title'] = div.xpath('.//div[@class="part1"]/a/text()').extract_first()
                  item['author'] = div.xpath('.//div[@class="part2"]/a[4]/b/text()').extract_first()
      
                  yield item

      item.py 文件

      import scrapy

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

      pipelines.py管道文件

      class ScrapyCrawlRedisProPipeline(object):
          def process_item(self, item, spider):
             print(item)
              return item

      setting.py配置文件

      BOT_NAME = 'scrapy_redis_Pro'
    
      SPIDER_MODULES = ['scrapy_redis_Pro.spiders']
      NEWSPIDER_MODULE = 'scrapy_redis_Pro.spiders'
      USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
      ROBOTSTXT_OBEY = False
      # 使用scrapy-redis中封装好的可以被共享的管道
      ITEM_PIPELINES = {
          'scrapy_redis.pipelines.RedisPipeline': 400
      }
    
      # 开启使用scrapy-redis组件中封装好的 可以被共享调度器
      # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化
      DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      # 使用scrapy-redis组件自己的调度器
      SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据
      SCHEDULER_PERSIST = True
    
      #配置redis
      REDIS_HOST = '192.168.12.29'
      REDIS_PORT = 6380
      REDIS_ENCODING = 'utf-8'
  • 相关阅读:
    Windows下MongoDB安装与PHP扩展
    仿Smarty替换模板标签时遇到的问题
    class ha_innobase: public handler
    类handler
    类Item_field
    函数buf_pool_init_instance
    函数buf_pool_init
    安装php,nginx 带debug
    gdb调试SAPI方式的php
    重启php-fpm
  • 原文地址:https://www.cnblogs.com/mwhylj/p/10277247.html
Copyright © 2011-2022 走看看