分布式爬虫

一、简介

什么是分布式爬虫?
分布式爬虫就是把一个爬虫任务放到多台机器上去运行,提高爬取效率
但是每台机器运行同一套代码,都在各自的任务和去重队列,等于各爬各的,最终爬的数据是相同的
因此需要提供一个公共的去重队列和公共的任务队列,多台机器都在共用的队列中去调度和去重,然后分别爬取

原来scrapy的Scheduler维护的是本机的任务队列(存放Request对象及其回调函数等信息)+本机的去重队列(存放访问过的url地址)

实现分布式的关键就是三点:
1、共享队列
2、重写Scheduler(调度器),让其无论去重还是任务都访问共享队列
3、为Scheduler定制去重规则(利用redis的集合类型)
以上三点便是scrapy-redis组件的核心功能

二、scrapy-redis实现分布式爬虫

1 scrapy-redis架构

scrapy-redis整体运行流程如下:核心就是把Scheduler(调度器)放到redis当中去

源码位置

2 scrapy-redis共享队列

3 使用scrapy-redis组件

1 pip3 install scrapy-redis 安装

2 原来继承Spider,现在继承RedisSpider
源码spiders.py中,RedisSpider(RedisMixin, Spider)类,继承了原来的Spider,并继承了扩展类RedisMixin

3 不能写start_urls = ["https:/www.cnblogs.com/"]  
需要写redis_key = "myspider:start_urls"  统一管理起始的爬取地址,redis的name对应的是一个列表
放一个起始url,启动爬虫后,返回来的url也是丢到这个列表中,每台机器都是从这个列表中取地址爬取,共享一个队列

class ChoutiSpider(RedisSpider):
    name = "cnblog"
    allowed_domains = ["cnblogs.com"]
    redis_key = "myspider:start_urls"

4 setting中配置

redis连接
# redis的连接, 默认配置本地+6379
REDIS_HOST = "localhost"     # 主机名
REDIS_PORT = 6379            # 端口
REDIS_USER =                 # 用户名
REDIS_PASSWORD =             # 密码
REDIS_URL = "redis://user:pass@hostname:port"       # 支持直接链接
REDIS_PARAMS  = {}                                  # Redis连接参数
REDIS_PARAMS["redis_cls"] = "myproject.RedisClient" # 指定连接Redis的Python模块
REDIS_ENCODING = "utf-8"                            # redis编码类型 
REDIS_ITEMS_KEY = "%(spider)s:items"                # 将item持久化到redis时,指定的name
REDIS_ITEMS_SERIALIZER = "json.dumps"               # 将item持久化到redis时,指定序列化函数
重点配置
1、DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"   # 使用scrapy-redis的去重
   源码dupefilter.py中,RFPDupeFilter类重写了request_seen()方法
    def request_seen(self, request):
        fp = self.request_fingerprint(request)
        # self.server是redis连接,sadd表示向集合中add数据
        added = self.server.sadd(self.key, fp)
        return added == 0


2、SCHEDULER = "scrapy_redis.scheduler.Scheduler"    # 使用scrapy-redis的Scheduler, 分布式爬虫的配置

3、持久化配置,配了都走公共的,存在redis中,如果不配,各自存各自的库,当然Mysql也是共用的一个库
ITEM_PIPELINES = {"scrapy_redis.pipelines.RedisPipeline": 299} 

源码pipelines.py中,RedisPipeline类,_process_item()方法,就是把item对象转成pickle,再存入redis
    def _process_item(self, item, spider):
        key = self.item_key(item, spider)
        data = self.serialize(item)
        self.server.rpush(key, data)
        return item
其他配置
# 调度器将不重复的任务用pickle序列化后放入共享任务队列,默认使用优先级队列,其他PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表)               
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.PriorityQueue" 

# 对保存到redis中的request对象进行序列化,默认使用pickle
SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"   

# 调度器中请求任务序列化后存放在redis中的name             
SCHEDULER_QUEUE_KEY = "%(spider)s:requests" 

# 去重队列(用的指纹去重,放在集合中),在redis中保存时对应的name                        
SCHEDULER_DUPEFILTER_KEY = "%(spider)s:dupefilter"

# 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。如果没有则立刻返回会造成空循环次数过多,cpu占用率飙升                                
SCHEDULER_IDLE_BEFORE_CLOSE = 10           

# 是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空                     
SCHEDULER_PERSIST = True       

# 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空                                     
SCHEDULER_FLUSH_ON_START = False    

5 启动scrapy-redis

分布式爬虫部署在三台机器上,等于每台机器启一个爬虫进程,跟在一台机器上启动3个进程本质上一样的
1 进程启动爬虫,启动后要等待从redis中拿出起始url
scrapy crawl cnblog_redis

现在要让爬虫运行起来,需要去redis中以myspider:start_urls为key,插入一个起始地址
cmd命令窗口输入:
2 redis-cil  # 启动redis
3 lpush myspider:start_urls https://www.cnblogs.com/   # 插入起始地址

···
hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » 分布式爬虫