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的。