介绍
原来 scrapy 的 Scheduler 维护的是本机的任务队列(存放 Request 对象及其回调函数等信息)+ 本机的去重队列(存放访问过的url地址)
所以实现分布式爬取的关键就是,找一台专门的主机上运行一个共享的队列比如 Redis,
然后重写 Scrapy 的 Scheduler,让新的 Scheduler 到共享队列存取 Request,并且去除重复的 Request 请求,所以总结下来,实现分布式的关键就是三点:#1、共享队列 #2、重写Scheduler,让其无论是去重还是任务都去访问共享队列 #3、为Scheduler定制去重规则(利用redis的集合类型)
安装
pip install scrapy-redis #源码: D:\python3.6\Lib\site-packages\scrapy_redis
scrapy-redis 组件
只使用scrapy-redis的去重功能
在 settings.py 中配置链接 Redis
REDIS_HOST = 'localhost' # 主机名 REDIS_PORT = 6379 # 端口 REDIS_URL = 'redis://user:pass@hostname:9001' # 连接URL(优先于以上配置) REDIS_PARAMS = {'password':'redis123'} # Redis连接参数 REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient' # 指定连接Redis的Python模块 REDIS_ENCODING = "utf-8" # redis编码类型
让 scrapy 使用共享的去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" from scrapy.dupefilters import RFPDupeFilter from scrapy.core.scheduler import Scheduler
将request请求转成一串字符后再存入集合
from scrapy.http import Request from scrapy.utils.request import request_fingerprint req = Request(url='http://www.baidu.com') result=request_fingerprint(req) print(result) #75d6587d87b3f4f3aa574b33dbd69ceeb9eafe7b
注意:
UR L参数位置不同时,计算结果一致;
默认请求头不在计算范围,include_headers 可以设置指定请求头req = Request(url='http://www.baidu.com?name=8&id=1',callback=lambda x:print(x),cookies={'k1':'vvvvv'}) result1 = request.request_fingerprint(req,include_headers=['cookies',]) print(result) req = Request(url='http://www.baidu.com?id=1&name=8',callback=lambda x:print(x),cookies={'k1':666}) result2 = request.request_fingerprint(req,include_headers=['cookies',]) print(result1 == result2) #True
使用 scrapy-redis 的去重 + 调度实现分布式爬取
settings.py 配置
# Enables scheduling storing requests queue in redis. SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 调度器将不重复的任务用 pickle 序列化后放入共享任务队列,默认使用优先级队列(默认),其他:PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表)
步骤
1 原来的爬虫继承
from scrapy_redis.spiders import RedisSpider class ChoutiSpider(RedisSpider): name = 'chouti' # 爬虫名字 redis_key = 'myspider:start_urls'
2 在 settings 中配置
SCHEDULER = "scrapy_redis.scheduler.Scheduler" DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 300 }
3 多台机器上启动 scrapy
4 向 redis 中发送起始 url
lpush myspider:start_urls https://www.cnblogs.com