scrapy能否实现分布式爬虫?    

  不可以.
  •  因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。(多台机器无法共享同一个调度器) 
  •  多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。(多台机器无法共享同一个管道) 

 

二.实现分布式爬虫的方式

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

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

实现方式:

  1.基于该组件的RedisSpider类

  2.基于该组件的RedisCrawlSpider类

 

三.实现分布式爬虫的步骤

  上述两种不同方式的分布式实现流程是一样的

  1. 安装模块

pip install scrapy-redis

  2.配置数据库(redis.windows.conf)

- 注释该行:
  bind 127.0.0.1  #表示可以让其他ip访问redis 

- 将yes该为no:
  protected-mode no   #表示可以让其他ip操作redis

  3.修改爬虫文件中的代码

 #修改之前要记得导包from scrapy_redis.Spiders import RedisSpider
    #把爬虫文件中父类修改成RedisSpider或者RedisCrawlSpider--看原爬虫基于的父类是什么,
    #如果原来是基于Spider则更改为RedisSpider
    #如果原爬虫是基于CrawlSpider,则更改为RedisCrawlspider 

  爬虫文件ct.py

# -*- coding: utf-8 -*-
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from Chouti.items import ChoutiItem

class CtSpider(RedisCrawlSpider):
    name = 'ct'
    # allowed_domains = ['www.xxx.com']
    # start_urls = ['http://www.xxx.com/']
    redis_key='chouti'
  
   #注释或者删除start_urls列表,加入redis_key属性,属性值为scrpy-redis组件中调度器队列的名称  
   #(这样我们要进行爬取就得往调度器的队列丢一个起始的url)
   '''
     分布式爬虫,代码编写好后可以放到分布式集群中,集群中运行的程序时同一个,如果程序中有起始
      的url,就表示所有的机器都url,要去请求这个url进行解析-->会导致更多的重复数据
      做分布式就是要其中的某台电脑有url,从url中解析出子url,扔到调度器的队列中
      因为在调度器中,经过去重的url才会放到队列中.
      但是起始url还不能没有,就把起始url当成全局的,让集群中的机器其抢,谁抢到谁请求解析
      保证起始url只被请求一次
      https://dig.chouti.com/
   '''
    rules = (
        Rule(LinkExtractor(allow=r'/all/hot/recent/\d+'), callback='parse_item', follow=True),
    )

    def parse_item(self, response):
        div_list = response.xpath('//div[@class="item"]')
        for div in div_list:
            title = div.xpath('./div[4]/div[1]/a/text()').extract_first()
            author = div.xpath('/div[4]/div[2]/a[4]/b/text()').extract_first()
            # 实例化item对象进行封装
            item = ChoutiItem()

            item['title'] = title
            item['author'] = author

            yield item

  item.py

import scrapy


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

  4. 在配置文件中进行相关配置,开启使用scrapy-redis组件封装好的管道

 #同时要注释掉原生的管道,使用redis封装好的共享的管道
  ITEM_PIPELINES = { 
        'scrapy_redis.pipelines.RedisPipeline': 400 
                      }

  5.在settings文件中进行相关配置,开启使用scrapy-redis组件中封装好的调度器

#使用scrapy-redis组件的去重队列,使用redis集合来保存请求对象的指纹 ,从而实现去重的持久化
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" 
  #使用scrapy-redis组件自己的调度器 
    SCHEDULER = "scrapy_redis.scheduler.Scheduler" 
  #配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据
  #当这个参数为False的时候,就是没有持久化保存数据,就会再下次启动爬虫文件的时候从新爬取,从0 开始

     SCHEDULER_PERSIST = True

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

  REDIS_HOST = 'redis服务的ip地址' #数据库所在机器上IP地址
  REDIS_PORT = 6379 
  REDIS_ENCODING = ‘utf-8’ 
  #REDIS_PARAMS = {‘password’:’123456’}
  

  #这么配置也可以
  REDIS_URL='redis://127.0.0.1:6379'

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

redis-server 配置文件

  8.开启redis客户端

redis-cli

  9. 运行爬虫文件:scrapy runspider 爬虫文件名.py

#这个命令要到爬虫项目里面才能运行
scrapy runspider ct.py


#爬虫文件就可以监听端口,等待我们往调度器管道里丢一个起始url
#这个时候爬虫的状态应该是夯筑了,等待我们给他一个reidis_key

  基于scrapy-redis的分布式爬虫

  基于scrapy-redis的分布式爬虫

  10. 向调度器队列中扔入一个起始url(在redis客户端中操作):

#lpush redis_key属性值 起始url
#插入的人key就是爬虫文件redis_key的值
lpush chouti https://dig.chouti.com/  

  11.查看数据库

基于scrapy-redis的分布式爬虫

三.深度优先和的广度优先 

  在scrapy-redis中,默认的是 深度优先

  如果想变成 广度优先,在配置文件中写入

- DEPTH_PRIORITY = 1\n,
- SCHEDULER_DISK_QUEUE = 'scrapy.squeues.PickleFifoDiskQueue'\n,
- SCHEDULER_MEMORY_QUEUE = 'scrapy.squeues.FifoMemoryQueue'\n,

 深度优先和广度优先的对比

    - 广度优先:不全部保留结点,占用空间少;运行速度慢\n,
    - 深度优先:保留全部结点,占用空间大;运行速度快