首页 > 其他 > 详细

scrapy-redis 实现分布式爬虫

时间:2019-11-30 01:45:14      阅读:123      评论:0      收藏:0      [点我收藏+]

 

一 介绍

原来scrapy的Scheduler维护的是本机的任务队列(存放Request对象及其回调函数等信息)+本机的去重队列(存放访问过的url地址)

技术分享图片

所以实现分布式爬取的关键就是,找一台专门的主机上运行一个共享的队列比如Redis,
然后重写Scrapy的Scheduler,让新的Scheduler到共享队列存取Request,并且去除重复的Request请求,所以总结下来,实现分布式的关键就是三点:

#1、共享队列
#2、重写Scheduler,让其无论是去重还是任务都去访问共享队列
#3、为Scheduler定制去重规则(利用redis的集合类型)

以上三点便是scrapy-redis组件的核心功能

技术分享图片

#安装:
pip3 install scrapy-redis

#源码:
D:\python3.6\Lib\site-packages\scrapy_redis

二、scrapy-redis组件

1、只使用scrapy-redis的去重功能

技术分享图片 

技术分享图片
技术分享图片
#一、源码:D:\python3.6\Lib\site-packages\scrapy_redis\dupefilter.py



#二、配置scrapy使用redis提供的共享去重队列

#2.1 在settings.py中配置链接Redis
REDIS_HOST = localhost                            # 主机名
REDIS_PORT = 6379                                   # 端口
REDIS_URL = redis://user:pass@hostname:9001       # 连接URL(优先于以上配置)
REDIS_PARAMS  = {}                                  # Redis连接参数
REDIS_PARAMS[redis_cls] = myproject.RedisClient # 指定连接Redis的Python模块
REDIS_ENCODING = "utf-8"                            # redis编码类型  
# 默认配置:D:\python3.6\Lib\site-packages\scrapy_redis\defaults.py

#2.2 让scrapy使用共享的去重队列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#使用scrapy-redis提供的去重功能,查看源码会发现是基于Redis的集合实现的

#2.3、需要指定Redis中集合的key名,key=存放不重复Request字符串的集合
DUPEFILTER_KEY = dupefilter:%(timestamp)s
#源码:dupefilter.py内一行代码key = defaults.DUPEFILTER_KEY % {‘timestamp‘: int(time.time())}

#2.4、去重规则源码分析dupefilter.py
def request_seen(self, request):
    """Returns True if request was already seen.

```
Parameters
----------
request : scrapy.http.Request

Returns
-------
bool

"""
fp = self.request_fingerprint(request) 
# This returns the number of values added, zero if already exists.
added = self.server.sadd(self.key, fp)
return added == 0
```

#2.5、将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

#2.6、注意:
    - URL参数位置不同时,计算结果一致;
    - 默认请求头不在计算范围,include_headers可以设置指定请求头
    - 示范:
    from scrapy.utils import request
    from scrapy.http import Request
     

```
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
```
技术分享图片

2、使用scrapy-redis的去重+调度实现分布式爬取

技术分享图片 View Code

3、持久化

技术分享图片
技术分享图片
#从目标站点获取并解析出数据后保存成item对象,会由引擎交给pipeline进行持久化/保存到数据库,scrapy-redis提供了一个pipeline组件,可以帮我们把item存到redis中

#1、将item持久化到redis时,指定key和序列化函数 
REDIS_ITEMS_KEY = %(spider)s:items
REDIS_ITEMS_SERIALIZER = json.dumps

#2、使用列表保存item数据
技术分享图片

4、从Redis中获取起始URL

技术分享图片
技术分享图片
scrapy程序爬取目标站点,一旦爬取完毕后就结束了,如果目标站点更新内容了,我们想重新爬取,那么只能再重新启动scrapy,非常麻烦
scrapy-redis提供了一种供,让scrapy从redis中获取起始url,如果没有scrapy则过一段时间再来取而不会关闭
这样我们就只需要写一个简单的脚本程序,定期往redis队列里放入一个起始url。

#具体配置如下

#1、编写爬虫时,起始URL从redis的Key中获取
REDIS_START_URLS_KEY = %(name)s:start_urls
    
#2、获取起始URL时,去集合中获取还是去列表中获取?True,集合;False,列表
REDIS_START_URLS_AS_SET = False    # 获取起始URL时,如果为True,则使用self.server.spop;如果为False,则使用self.server.lpop
技术分享图片

 

scrapy-redis 实现分布式爬虫

原文:https://www.cnblogs.com/mofujin/p/11960990.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!