Scrapy是一个分布式爬虫的框架,如果把它像普通的爬虫一样单机运行,它的优势将不会被体现出来。因此,要让Scrapy往分布式爬虫方向发展,就需要学习Scrapy与Redis的结合使用。Redis在Scrapy的爬虫中作为一个队列存在。
一、Scrapy_redis的安装和使用
Scrapy自带的待爬队列是deque,而现在需要使用Redis来作为队列,所以就需要将原来操作deque的方法替换为操作Redis的方法。但是,如果要把三轮车换成挖掘机,驾驶员也必须从三轮车驾驶员换成挖掘机驾驶员。Scrapy_redis在这里就充当驾驶员的角色。更准确地说,Scrapy_redis是Scrapy的"组件",它已经封装了使用Scrapy操作Redis的各个方法。
Windows、Linux和Mac OS都可以在CMD或者终端中使用pip安装Scrapy_redis:
pip install scrapy_redis
Scrapy_redis本身非常小,但是由于pip会自动安装依赖,所以它会去检查Scrapy和相关的依赖库是否已经安装。如果已经安装了,会提示需求已经满足(Requirement already satisfied),不会重复安装。
使用Redis缓存网页并自动去重
由于Scrapy_redis已经封装了大部分的流程,所以我们使用它不会有任何难度。
- 启动Redis
首先需要把Redis启动起来。对于Mac OS/Linux系统,直接在终端下面输入以下命令并按Enter键:
redis-server
在Windows系统中,通过CMD的cd命令进入存放Redis的文件夹,并运行:
redis-server.exe
- 修改爬虫
在前面的代码中,爬虫继承自scrapy.Spider这个父类。这是Scrapy里面最基本的一个爬虫类,只能实现基本的爬虫功能。现在需要把它替换掉,从而实现更高级的功能。
首先需要导入支持Redis的爬虫父类并使用:
from scrapy_redis.spiders import RedisSpider
class Exercise114Spider(RedisSpider):
name = "exercise11_4"
redis_key = 'exercise114spider:start_urls'
...
请对比上面这段使用了Scrapy_redis的代码与前面例子中爬虫的代码头部有什么不同。
可以看出,这里爬虫的父类已经改成了RedisSpider,同时多了以下内容:
redis_key = 'exercise114spider:start_urls'
这里的redis_key实际上就是一个变量名,之后爬虫爬到的所有URL都会保存到Redis中这个名为"exercise114spider:start_urls"的列表下面,爬虫同时也会从这个列表中读取后续页面的URL。这个变量名可以任意修改,里面的英文冒号也不是必需的。不过一般习惯上会写成"爬虫名:start_urls"这种形式,这样看到名字就知道保存的是什么内容了。
除了导入的类和redis_key这两点以外,爬虫部分的其他代码都不需要做任何修改。原来解析XPath的代码可以正常工作,原来保存数据到MongoDB的代码也可以正常工作。
实际上,此时已经建立了一个分布式爬虫,只不过现在只有一台计算机。
- 修改设置
现在已经把三轮车换成了挖掘机,但是Scrapy按照指挥三轮车的方式指挥挖掘机,所以挖掘机还不能正常工作。因此修改爬虫文件还不行,Scrapy还不能认识这个新的爬虫,还需要修改settings.py。
(1)Scheduler
首先是调度Scheduler的替换。这是Scrapy中的调度员。在settings.py中添加以下代码:
# Enables scheduling storing requests queue in redis.
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
(2)去重
# Ensure all spiders share same duplicates filter through redis.
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
设置好上面两项以后,爬虫已经可以正常开始工作了。不过我们还可以多设置一些东西使爬虫更好用。
(3)爬虫请求的调度算法
爬虫请求的调度算法,有3种情况可供选择。
① 队列
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue'
如果不配置调度算法,默认就会使用这种方式。它实现了一个先入先出的队列,先放进Redis的请求会优先爬取。
② 栈
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'
这种方式,后放入到Redis的请求会优先爬取。
③ 优先级队列
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'
这种方式,会根据一个优先级算法来计算哪些请求先爬取,哪些请求后爬取。这个优先级算法比较复杂,会综合考虑请求的深度等各个因素。
在实际爬虫开发过程中,从以上3项中选择一种并写到settings.py中即可。
(4)不清理Redis队列
# Don't cleanup redis queues, allows to pause/resume crawls.
SCHEDULER_PERSIST =True
如果这一项为True,那么Redis中的URL不会被Scrapy_redis清理掉。这样的好处是,爬虫停止了再重新启动,它会从上次暂停的地方开始继续爬取。
如果设置成了False,那么Scrapy_redis每一次读取了URL以后,就会把这个URL删除。爬虫暂停以后再重新启动,它会重新开始爬。
由于现在的爬虫和Redis在同一台计算机上面运行,所以可以不需要配置Redis的信息。Scrapy_redis会默认Redis就运行在现在这台计算机上,IP和端口也都是默认的127.0.0.1和6379。如果Redis不在本地的话,就需要将它们写出来:
REDIS_HOST = '127.0.0.1' #修改为Redis的实际IP地址
REDIS_PORT = 6379 #修改为Redis的实际端口
二、Scrapy 小结
Scrapy在Windows中的安装最为烦琐,在Mac OS中的安装最为简单。由于Scrapy需要依赖非常多的第三方库文件,因此建议无论使用哪个系统安装,都要将Scrapy安装到Virtualenv创建的虚拟Python环境中,从而避免影响系统的Python环境。
使用Scrapy爬取网页,最核心的部分是构建XPath。而其他的各种配置都是一次配好、终生使用的。由于Scrapy的理念是将数据抓取的动作和数据处理的动作分开,因此对于数据处理的各种逻辑应该让pipeline来处理。数据抓取的部分只需要关注如何使用XPath提取数据。数据提取完成以后,提交给pipeline处理即可。
由于Scrapy爬虫爬取数据是异步操作,所以从一个页面跳到另一个页面是异步的过程,需要使用回调函数。
Scrapy爬取到的数据量非常大,所以应该使用数据库来保存。使用MongoDB会让数据保存工作变得非常简单。要让Scrapy使用MongoDB,只需要在pipeline中配置好数据保存的流程,再在settings.py中配置好ITEM_PIPELINES和MongoDB的信息即可。
使用Redis做缓存是从爬虫迈向分布式爬虫的一个起点。Scrapy安装scrapy_redis组件以后,就可以具备使用Redis的能力。在Scrapy中使用Redis需要修改爬虫的父类,需要在settings.py中设置好爬虫的调度和去重。同时对于Python 3,需要修改scrapy_redis的一行代码,才能让爬虫正常运行。
没有自由的秩序和没有秩序的自由,同样具有破坏性。