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编码类型
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()
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"
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
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'