• scrapy-redis


    1、settings.py         配置链接Redis

    REDIS_HOST = '192.168.11.81'        # 主机名
    REDIS_PORT = 6379                   # 端口
    # REDIS_URL = 'redis://user:pass@hostname:9001'       
        # 连接URL(!!!!!!!!! 优先于以上配置)
    REDIS_PARAMS  = {}                                  
            # Redis连接参数
    # REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' 
            # 指定连接Redis的Python模块,默认redis.StrictRedis
    REDIS_ENCODING = "utf-8"                            
            # redis编码类型  
    View Code

    2、去重

    2.1、源码解析

    dupefilter.py

    # 使用scrapy-redis提供的去重功能,查看源码会发现是基于Redis的集合实现的
    # scrapy 使用has_seen()
    # 去重: 利用redis集合元素不重复 request_seen
    # 返回1 表示添加成功 否则0 失败

    def __init__(self):
        pass
        
    @classmethod
    def from_crawler(cls,crawler):
        pass
        
    @classmethod
    def from_settings(cls,settings):
        server=get_redis_from_settings(cls,settings)  
                # 连接redis数据库
            pass
        
    def request_seen(self,request):           # 利用redis集合元素不重复  request_seen
        fp=self.request_fingerprint(request)  # request的指纹,唯一性
        added=self.server.sadd(self.key,fp)   # k,v 插入redis,返回值added    
                                              # sadd 是个集合
        return added == 0          # 如果added=0,说明已经存在这个请求,就不会再加入队列
                                   # 如果added=1,添加成功
                
    def request_fingerprint(self,request):   # 获取指纹
        return request_fingerprint(request)
        
    def close(self,reason=''):
        self.clear()
    
    def clear(self):
        self.server.delete(self.key)
    
    def log(self,request,spider);
        pass
    源码

    queue.py    队列 栈 有序集合

    # FifoQueue
        #(列表,first in first out 先进后出 )
        # spiderQueue=FifoQueue
    
    # LifoQueue
        #(栈,last in first out 后进先出 )
        # spiderStack=LifoQueue
    
    # PriorityQueue(有序集合)
        # spiderPriorityQueue=PriorityQueue
    
    # 不仅存request 还是存request的优先级 
        # score=-request.priority  目的是 深度优先 score是正数
        # 可以在parse中print(response.request.priority)
    def push()
        pass
    def pop()
    View Code

    2.2、只使用去重,连接配置+...

    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
            #使用scrapy-redis提供的去重功能,查看源码会发现是基于Redis的集合实现的
    
        # 实际工作中:     创建dupe.py
            from scrapy_redis.dupefilter from    RFPDupeFilter
            class MyRFPDupeFilter(RFPDupeFilter):
                pass
            DUPEFILTER_CLASS = "xxxx.dupe.MyRFPDupeFilter"    
    View Code

    3、调度器

    将请求通过pickle序列化,添加到redis:列表或者有序集合,与setting配置
    SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue' 有关

    连接配置 + 下面:
        # 测试看看是否需要这个,不一定
        # DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
        
        
        SCHEDULER = "scrapy_redis.scheduler.Scheduler"       
        SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue' 
            # 默认使用优先级队列(默认广度优先),其他:PriorityQueue(有序集合 广度优先) 、
            # FifoQueue(列表 深度优先)、
            # LifoQueue(列表 深度优先)、 
            # 调度器将不重复的任务用pickle序列化后放入共享任务队列,
                   
        SCHEDULER_QUEUE_KEY = '%(spider)s:requests' 
            # 调度器中请求任务序列化后存放在redis中的key  
    
        SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"    
            # 对保存到redis中的request对象进行序列化,默认使用pickle
                            
        SCHEDULER_PERSIST = True       
            #是否在关闭时候保留原来的调度器和去重记录,True=保留,False=清空 
                                            
        SCHEDULER_FLUSH_ON_START = False    
            #是否在开始之前清空调度器和去重记录,True=清空,False=不清空 
                                      
        SCHEDULER_IDLE_BEFORE_CLOSE = 10           
            #去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。
            #如果没有则立刻返回会造成空循环次数过多,cpu占用率飙升 
                              
        SCHEDULER_DUPEFILTER_KEY = '%(spider)s:dupefilter'      
            # 去重规则,在redis中保存时对应的key 
            # import redis
            # conn = redis.Redis(host='127.0.0.1',port=6379)
            # v=conn.keys()
            # print(v)
                
        SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
        # 如果只用scrapy_redis调度器,就用下面的scrapy本身去重
        # SCHEDULER_DUPEFILTER_CLASS = 'scrapy.dupefilter.RFPDupeFilter'
            # 去重规则对应处理的类,
            # 将任务request_fingerprint(request)得到的字符串放入去重队列       
    
        DUPEFILTER_DEBUG = False
    View Code

    4、pipline持久化,item保存到redis

    from scrapy_redis.pipelines import RedisPipeline
    
    # settings.py配置   67 行
    ITEM_PIPELINES={
        'crapy_redis.pipelines.RedisPipeline':400,
        }
        
    # scrapy-redis提供了一个pipeline组件,可以帮我们把item存到redis中
    # import redis
    # conn = redis.Redis(host='127.0.0.1',port=6379)
    # v = conn.keys()  # 取值
    # print(v)
    # conn.flushall()  # 清空redis数据
    # 然后不停的生产(往redis中放数据),接着不停的存到某处(消费者)
    # 将item持久化到redis时,指定key和序列化函数 
        # REDIS_ITEMS_KEY = '%(spider)s:items' 
        # REDIS_ITEMS_SERIALIZER = 'json.dumps'
    View Code
  • 相关阅读:
    [转] 敏捷软件开发 Agile Software Development
    Concurrent Framework Synchronizer 同步器: Easy to use but easy to make dead lock as well
    Concurrent Framework Timer
    JavaScript Return Object.Type
    Js AJAX Event
    js Functor Copy
    多线程19-线程池批量插入线程
    多线程18-QueueUserWorkItem
    多线程17-Async Programming Model
    多线程16-SpinWait
  • 原文地址:https://www.cnblogs.com/nick477931661/p/9141151.html
Copyright © 2020-2023  润新知