scrapy源码分析:redis分布式爬虫队列中,priority值越大,优先级越高

scrapy源码分析:redis分布式爬虫队列中,priority值越大,优先级越高

一、背景

scrapy爬虫项目中,遇到scrapy的priority属性,搞不懂priority的值越大优先级越高,还是值越小优先级越高

# 通过priority修改优先级
return scrapy.Request(url=request.url, dont_filter=True, callback=spider.parse, priority=request.priority + 1)

为了搞清楚状况,直接盘scrapy源码,一探究竟。

参考:

https://blog.csdn.net/u011423145/article/details/103235874

redis

https://www.lanmper.cn/redis/t9455

https://deepinout.com/redis-cmd/redis-ordered-set-cmd/redis-cmd-zcard.html

https://www.yiibai.com/redis/sorted_sets_zremrangebyrank.html

二、版本和场景

1、scrapy版本:2.3.0

2、scrapy分布式爬虫,redis做调度器的队列。

3、Redis版本:6.2.4

先说结论:priority的值越大优先级越高;越小优先级越低。

三、源码分析

1、队列类型

# 源码位置:settings.py
# 默认的请求出队列排序, scrapy-redis请求集合, 里面做了优先级排序, 一般用这个
SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"

2、权重队列源码和解读

# 源码位置:xxx_spider.py
from scrapy_redis.queue import SpiderPriorityQueue
# 源码位置:queue.py
SpiderQueue = FifoQueue
SpiderStack = LifoQueue
SpiderPriorityQueue = PriorityQueue  # 解读1:SpiderPriorityQueue就是PriorityQueue类对象

# 解读2:PriorityQueue中有3个方法:
# (1)__len__ 私有方法返回队列的长度
# (2)push 方法将request请求对象的权重值取反得到score,并通过zadd将request对象data和取反权重值score,放入redis有序集合self.key中。
# 说明:在redis的有序集合中,score值越小,越靠前。score可以为负数。
# (3)pop 方法通过zremrangebyrank将redis有序集合self.key中,score最小的元素取出。
class PriorityQueue(Base):
    """Per-spider priority queue abstraction using redis' sorted set"""

    def __len__(self):
        """Return the length of the queue"""
        return self.server.zcard(self.key)

    def push(self, request):
        """Push a request"""
        data = self._encode_request(request)
        score = -request.priority
        # We don't use zadd method as the order of arguments change depending on
        # whether the class is Redis or StrictRedis, and the option of using
        # kwargs only accepts strings, not bytes.
        self.server.execute_command('ZADD', self.key, score, data)

    def pop(self, timeout=0):
        """
        Pop a request
        timeout not support in this queue class
        """
        # use atomic range/remove using multi/exec
        pipe = self.server.pipeline()
        pipe.multi()
        pipe.zrange(self.key, 0, 0).zremrangebyrank(self.key, 0, 0)
        results, count = pipe.execute()
        if results:
            return self._decode_request(results[0])

3、结论

priority的值越大,score的值就越小,在redis的有序集合中就越是靠前,zremrangebyrank方法取的最靠前的元素。

所以priority的值越大优先级越高;越小优先级越低。

延伸:亲测:scrapy的redis爬虫,从redis的list中获取数据时,是从redis的list的左边开始取采集目标url的。

posted @ 2023-08-02 12:44  安迪9468  阅读(197)  评论(0编辑  收藏  举报