笔记-爬虫-scrapy-srcapy-redis组件
笔记-爬虫-scrapy-srcapy-redis组件
1. 简介
scrapy是一个爬虫框架,但不支持分布式,scrapy-redis是为了更方便的实现scrapy分布式爬虫的组件。
可以在pypi上找到:https://pypi.org/project/scrapy-redis/
1.1. 安装
可以使用pip安装
pip install scrapy-redis
pip show scrapy-redis
目前最新版是0.6.8。
2. 使用
Scrapy-redis提供了下面四种组件(components):(意味着原始scrapy爬虫这四个部分都要做相应的修改)
Scheduler
Duplication Filter
Item Pipeline
Base Spider
先不管那么多,先跑一个案例;
-----实测------
3. scrapy-redis实测
3.1. 环境准备
主:虚拟机 centos6.5
从:物理机win8
3.2. redis安装配置
见笔记-redis安装
3.3. centos python环境安装
centos下已有python环境,安装参考文档:笔记-python3环境安装-centos6.5
安装相关包:
pip3 install redis,scrapy,scrapy-redis,lxml
包括redis-py,scrapy-redis,
通过pip安装就可以了,比较简单。
3.4. 代码
与scrapy爬虫代码大同小异,主要是spider类和settings中设置调度器,去重功能:
3.4.1. item
完全一样;
3.4.2. spiders/sina_news.py
spider类的基类改为RedisSpider
from scrapy_redis.spiders import RedisSpider
注释掉start_urls。
新增属性:
redis_key = ‘sinanewsspider:start_urls’
这个属性是给redis中建组用的,:作为组名和key名的间隔。
3.4.3. settings.py
需要设置以下内容:
#使用scrapy_redis调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
#使用scrapy_redis的去重处理器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
#不清理Redis队列
SCHEDULER_PERSIST = True
如果这一项为True,那么在Redis中的URL不会被Scrapy_redis清理掉,这样的好处是:爬虫停止了再重新启动,它会从上次暂停的地方开始继续爬取。但是它的弊端也很明显,如果有多个爬虫都要从这里读取URL,需要另外写一段代码来防止重复爬取。
如果设置成了False,那么Scrapy_redis每一次读取了URL以后,就会把这个URL给删除。这样的好处是:多个服务器的爬虫不会拿到同一个URL,也就不会重复爬取。但弊端是:爬虫暂停以后再重新启动,它会重新开始爬。
#redis服务器地址,主机写本地,从机写远程IP
REDIS_HOST = "192.168.199.129"
#redis端口
REDIS_PORT = 6379
其他设置(可选)
爬虫请求的调度算法
爬虫的请求调度算法,有三种情况可供选择:
1.队列
SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.SpiderQueue'
如果不配置调度算法,默认就会使用这种方式。它实现了一个先入先出的队列,先放进Redis的请求会优先爬取。
2.栈
SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.SpiderStack'
这种方式,后放入到Redis的请求会优先爬取。
3.优先级队列
SCHEDULER_QUEUE_CLASS='scrapy_redis.queue.SpiderPriorityQueue'
这种方式,会根据一个优先级算法来计算哪些请求先爬取,哪些请求后爬取。这个优先级算法比较复杂,会综合考虑请求的深度等各个因素。
3.4.4. pipeline
本来就是一个分离的组件,想改就改,不改也没问题。
scrapy-redis自带的pipeline是将items写入redis数据库中的items中。
前面声明的redis_key = ‘sinanewsspider:start_urls’
提供了组名,完整的key名为sinanewsspider:items
3.5. 运行
- 在主从机上都运行爬虫,爬虫进入等待状态,
因为都要去redis数据库的sina_news:start_urls中取链接,但现在没有该KEY,所以都在等待;
- 在redis数据库中添加初始爬取地址:
lpush sinanewsspider:start_urls http://news.sina.com.cn/guide/
- 然后就开始爬取了,在案例中设定了一个全局参数pages_max_num限制二级解析的YIELD次数,以此来限定总爬取页面数;
- 爬取完成,主从爬虫都进入等待状态。
3.6. 理解
scrapy-redis在数据库中新增三个key,dupefilter,items,requests:
- items:很好理解,存放item数据;
- dupefilter:
- requests:请求,
个人理解:为了实现分布式爬虫,需要一个跨平台的信息传递,目前是通过redis的远程访问满足这一点,至于为什么是redis而不是其它数据库或中间件那是另外一个问题了;
下一个问题是传递什么信息,最简单也是数据量最小的是传递url地址,但这样功能不够丰富,scrapy-redis放进去的是requests;
总之具体实现就是scrapy-redis把请求放到redis数据库中,爬虫去数据库中拿到请求,爬取,再把结果放到items中。
关于dupefilter,它是用于去重,看上去是hash的结果,类似于指纹。
4. scrapy-redis原理理解
4.1. scrapy-redis分布式爬取实现原理
因为官方文档没什么内容,下面的内容取自网络及个人理解。
从爬虫实现的过程来讲,爬虫分布式最容易实现的方式是共享请求,也就是“待爬队列”;
从爬虫整体的合理设计来讲,爬虫要做的事就是得到请求,去重,采集,存储数据四部分,下面一一解释scrapy-redis的实现方法。
- 请求发起/获取
怎么发起就不废话了,scrapy是从爬取队列中获取请求的,它具体的数据结构就是python自带的collection.deque,当然是改造过后的啦(后面所说到的deque均是指scrapy改造之后的队列)。
scrapy-redis提供了一个分布式解决方法,把deque换成redis数据库,在同一个redis服务器写/读要爬取的request,这样就让多个spider共享了请求。
问题来了,换了redis来存放队列,怎么去发起/获取请求?
scrapy中做这个事的是调度器“Scheduler”,它负责对新request入列(加入deque),取出待爬取的request(从deque中出殡)等操作。
另外,在scrapy中,Scheduler为deque提供了一个比较高级的组织方法,它把待爬队列按照优先级建立了一个字典结构,比如:
{
priority0:队列0
priority1:队列2
priority2:队列2
}
然后根据request中的priority属性,来决定该入哪个队列。而出列时,则按priority较小的优先出列。为了管理这个比较高级的队列字典,Scheduler需要提供一系列的方法。
这样做的结果就是如果换了redis做队列,scrapy下的Scheduler就用不了,需要重写。
待爬队列+调度器解决了,分布式爬虫也就基本可以运行了。
2.去重
爬虫有一个重要的功能是去重,scrapy中用集合解决;scrapy-redis用dupefilter存放请求的指纹,在进行调度前做对比。
3.采集
请求的格式与接口不变,这一部分也不需要变化,与scrapy没什么不同。
4数据存储
分布式爬取带来的一个问题是数据在不同的主机上,那么理论上有两种方法:
- 各存各的,master提供url,slave采集后存在本地,把title或指纹汇总,这样好处是开销小,问题是数据汇总麻烦;
- slave把采集到的数据实时发送到master或其它主机,这样数据存放在一起,slave仅做采集。
实际中 一般使用第二种方法,另备一台mongodb/mysql服务器,用于采集数据存储。
scrapy-redis的RedisPipeline将数据存入master的redis数据库中。
5. 源码分析
scrapy-redis官方文档内容有限,要想理解其实现过程,还是得看看源码。
5.1. connection.py
连接redis
有一个问题是没有提供password参数的连接模式
在源码中对于这一部分的处理如下:
url = kwargs.pop('url', None)
if url:
return redis_cls.from_url(url, **kwargs)
else:
return redis_cls(**kwargs)
它还是调用redis模块的函数去连接,可以参照redis模块中的格式redis://[:password]@localhost:6379/0
注意,在settings中的变量名需要做一个转换:REDIS_URL
5.2. pipelines.py
主要是将内容推进数据库的items中,用于解析结果的共享,一般可以写入其它服务器数据库,减少master的压力。
# 最主要的方法
def process_item(self, item, spider):
# 调用了一个线程方法
return deferToThread(self._process_item, item, spider)
def _process_item(self, item, spider):
key = self.item_key(item, spider)
# 序列化item
data = self.serialize(item)
# 将item同意添加到redis队列里面, 存到主机
self.server.rpush(key, data)
return item
5.3. queue.py
实现了三种队列,
SpiderQueue = FifoQueue
SpiderStack = LifoQueue
SpiderPriorityQueue = PriorityQueue
LIFO,FIFO很好看懂,优先级队列的实现没看懂,调用redis的函数,需要详细去看redis接口代码。
5.4. dupefilter.py
主要是实现了判重,根据源代码来看,scrapy-redis在计算特征码时使用了scrapy本身的一个fingerprint接request_fingerprint。
特征码保存在redis的组名:dupefilter中。
5.5. scheduler.py
爬取队列管理,核心部分如下:
def enqueue_request(self, request):
if not request.dont_filter and self.df.request_seen(request):
self.df.log(request, self.spider)
return False
if self.stats:
self.stats.inc_value('scheduler/enqueued/redis', spider=self.spider)
self.queue.push(request)
return True
def next_request(self):
block_pop_timeout = self.idle_before_close
request = self.queue.pop(block_pop_timeout)
if request and self.stats:
self.stats.inc_value('scheduler/dequeued/redis', spider=self.spider)
return request
5.6. spider.py
不在使用scrapy原有的Spider类,重写的RedisSpider继承了Spider和RedisMixin这两个类,RedisMixin是用来从redis读取url的类。
笔记-爬虫-scrapy-srcapy-redis组件的更多相关文章
- Python分布式爬虫打造搜索引擎完整版-基于Scrapy、Redis、elasticsearch和django打造一个完整的搜索引擎网站
Python分布式爬虫打造搜索引擎 基于Scrapy.Redis.elasticsearch和django打造一个完整的搜索引擎网站 https://github.com/mtianyan/Artic ...
- 爬虫 scrapy 笔记
scrapy 基础 1. 创建一个spider项目 a) Scrapy startproject project_name [project_dir] b) Cd p ...
- 爬虫Ⅱ:scrapy框架
爬虫Ⅱ:scrapy框架 step5: Scrapy框架初识 Scrapy框架的使用 pySpider 什么是框架: 就是一个具有很强通用性且集成了很多功能的项目模板(可以被应用在各种需求中) scr ...
- Scrapy、Scrapy-redis组件
目录 Scrapy 一.安装 二.基本使用 1. 基本命令 2.项目结构以及爬虫应用简介 3. 小试牛刀 4. 选择器 5. 格式化处理 6.中间件 7. 自定制命令 8. 自定义扩展 9. 避免重复 ...
- 自己动手实现爬虫scrapy框架思路汇总
这里先简要温习下爬虫实际操作: cd ~/Desktop/spider scrapy startproject lastspider # 创建爬虫工程 cd lastspider/ # 进入工程 sc ...
- 笔记-爬虫-去重/bloomfilter
笔记-爬虫-去重/bloomfilter 1. 去重 为什么要去重? 页面重复:爬的多了,总会有重复的页面,对已爬过的页面肯定不愿意再爬一次. 页面更新:很多页面是会更新的,爬取这种页面时就 ...
- 网页爬虫--scrapy入门
本篇从实际出发,展示如何用网页爬虫.并介绍一个流行的爬虫框架~ 1. 网页爬虫的过程 所谓网页爬虫,就是模拟浏览器的行为访问网站,从而获得网页信息的程序.正因为是程序,所以获得网页的速度可以轻易超过单 ...
- WebMagic的设计参考了业界最优秀的爬虫Scrapy
http://webmagic.io/docs/zh/posts/ch1-overview/thinking.html https://github.com/psvehla/liferay-sprin ...
- python爬虫scrapy项目详解(关注、持续更新)
python爬虫scrapy项目(一) 爬取目标:腾讯招聘网站(起始url:https://hr.tencent.com/position.php?keywords=&tid=0&st ...
随机推荐
- 简单封装的web里面的tab点击和swipe滑动的小插件
简单封装的一个web的手势,tab和swipe,里面的具体数值都是自定义上去的,没有实际的标准,可以自行去修改都行 前两个是详解,js插件在最后一部分代码 ``` //封装web的tab步骤详解 &l ...
- input type="file"获取文件名方法
文件上传比较丑,样式调整时会有一个获取文件名,或者包含文件路径的文件名的方法 html代码 <div class="file-box"> <form id=&qu ...
- 使用windows资源管理器打开jar
在命令行里输入: assoc .jar=CompressedFolder
- dojo query 基本用法
1. 常用的 dojo.query 用法 dojo.query("#header > h1") //ID 为 header 的元素的直接子节点中的 h3 元素 dojo. ...
- Python开发环境Wing IDE的Blender的Python代码调试技巧
Wing IDE是一个集成开发环境,可用于开发.测试和调试为Blender编写的Python代码,Blender是一个开源的3 D内容创建系统.Wing IDE提供自动完成.调用提示.强大的调试器.以 ...
- Unity3d开发集成Google Admob广告增加收入
在Unity游戏中植入广告是Unity 游戏产品增加收入的一种重要方式,常用的广告有谷歌Admob,百度ssp,腾讯广点通,unity公司的unityads等等,而使用的最多的应该属于谷歌Admob, ...
- Android开发由eclipse转Android Studio中一些常见出错问题解决方法
1.给一个Activity添加了一个Dialog主题,结果出现了下面的问题,在eclipse却没有出错 <activity android:name=".DialogActivity& ...
- [原创]在Debian9上配置NAS
序言 此教程安装的都是最新版本的.由于是当NAS让它非常稳定的运行,所以能不安装的软件尽量不要安装. 一.准备工作 1. 更新系统 没啥,就他喵想用个最新的. apt update && ...
- Tomcat启动报Error listenerStart错误 | "beans" 必须匹配 DOCTYPE 根 "null" | java.lang.reflect.MalformedParameterizedTypeException
maven打包发布工程时,发布上去却报错FAIL - Deployed application at context path /ch but context failed to start 在服务器 ...
- shell去重
sort命令可以对文本的内容进行排序 uniq命令可以对文本内容连续的内容进行去重,非连续的重复内容无法去重 sort 文件 | uniq 可以达到去除所有重复数据的目的(因为先排序了,这样相同的内容 ...