一、scrapy-redis(0.6)依赖的环境

Scrapy >= 1.0.0                #终于过了1版本,这个太重要了,总算坑小了点,感谢那些为了解决各种scrapy与scrapy-redis不兼容做出了贡献的开发者和博主。
redis-py >= 2.10.0
redis server >= 2.8.0

0.6版本的主要更新内容是更新代码以支持Scrapy 1.0; 增加了-a domain=... option for example spiders.

官方源代码

二、scrapy-redis的作用和特点

作用:scrapy-redis为Scrapy提供Redis-backed组件

特点: 可以启动多个爬虫实例共享一个单一的 redis队列。是最适合广泛的多域爬虫。

分布式的post处理。scrapy到的items放入一个redis队列意味着可以分享这个items队列,并在其中启用足够多的post处理进程。

三、scrapy和scrapy-redis的区别与组件的意义
scrapy 是一个通用的爬虫框架
scrapy-redis是为了更方便地实现scrapy分布式爬取,而提供了一些以redis为基础的组件(仅有组件)
scrapy-redis提供了下面四种组件(components):(四种组件意味着这四个模块都要做相应的修改)
Scheduler  Duplication Filter Item PipelineBase Spider

scrapy改造了python本来的collection.deque形成了自己的scrqueue(scrapy-redis基础和介绍_qt自己取得名字) 传送门:queuelib/queuelib/queue.py源码
scrapy多个spider不能共享待爬取队列scrqueue, 即scrapy本身不支持爬虫分布式,解决是把这个scrqueue换成redis数据库(也是指redis队列),从同一个redis-server存放要爬取的request,便能让多个spider去同一个数据库里读取。
 
scrapy中跟“待爬队列”直接相关的就是调度器“Scheduler”,它负责对新的request进行入列操作(加入scrqueue),取出下一个要爬取的request(从scrqueue中取出)等操作。它把待爬队列按照优先级建立了一个字典结构,比如:
{
priority0:队列0
priority1:队列2
priority2:队列2
}
然后根据request中的priority属性,来决定该入哪个队列。而出列时,则按priority较小的优先出列。为了管理这个比较高级的队列字典,Scheduler需要提供一系列的方法。原来的Scheduler已经无法使用(被替换掉了,注意上一个红色字段),所以使用scrapy-redis的scheduler组件。
 
scrapy中用集合实现这个request去重功能,scrapy中把已经发送的request指纹放入到一个集合中,把下一个request的指纹拿到集合中比对,如果该指纹存在于集合中,说明这个request发送过了,如果没有则继续操作。(源码传送)这个核心的判重功能是这样实现的:
[plain] view plain copy
 
  1. </pre></div></blockquote><pre name="code" class="plain">def request_seen(self, request):  
  2.     #self.figerprints就是一个指纹集合  
  3.     fp = self.request_fingerprint(request)  
  4.     if fp in self.fingerprints:#这就是判重的核心操作。  
  5.         return True  
  6.     self.fingerprints.add(fp)  
  7.     ......  

在scrapy-redis中去重是由Duplication Filter组件来实现的。

四、最快的安装和启用

安装:

[plain] view plain copy
 
  1. $ pip install scrapy-redis   
  2. 或者   
  3. $ git clone https://github.com/darkrho/scrapy-redis.git  
  4. $ cd scrapy-redis  
  5. $ python setup.py install  
  在 settings.py 中启用组件们:
[plain] view plain copy
 
  1. </pre></blockquote><pre name="code" class="plain"># Enables scheduling storing requests queue in redis.  
  2. SCHEDULER = "scrapy_redis.scheduler.Scheduler"  
  3. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_16_2220405" name="code" class="python"># Don't cleanup redis queues, allows to pause/resume crawls.  
  4. SCHEDULER_PERSIST = True  
  5. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_19_5349541" name="code" class="python"># Schedule requests using a priority queue. (default)  
  6. SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'  
  7. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_22_4193298" name="code" class="python"># Schedule requests using a queue (FIFO).  
  8. SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue'  
  9. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_25_5337568" name="code" class="python"># Schedule requests using a stack (LIFO).  
  10. SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'  
  11. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_28_6547876" name="code" class="python"># Max idle time to prevent the spider from being closed when distributed crawling.  
  12. # This only works if queue class is SpiderQueue or SpiderStack,  
  13. # and may also block the same time when your spider start at the first time (because the queue is empty).  
  14. SCHEDULER_IDLE_BEFORE_CLOSE = 10  
  15. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_33_5980278" name="code" class="python"># Store scraped item in redis for post-processing.  
  16. ITEM_PIPELINES = {  
  17.     'scrapy_redis.pipelines.RedisPipeline': 300  
  18. }  
  19. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_38_8651283" name="code" class="python"># Specify the host and port to use when connecting to Redis (optional).  
  20. REDIS_HOST = 'localhost'  
  21. REDIS_PORT = 6379  
  22. </pre></div></blockquote><blockquote style="margin:0 0 0 40px; border:none; padding:0px"><div><span style="white-space:pre"></span><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_42_1638716" name="code" class="python"># Specify the full Redis URL for connecting (optional).  
  23. # If set, this takes precedence over the REDIS_HOST and REDIS_PORT settings.  
  24. REDIS_URL = 'redis://user:pass@hostname:9001'  

 

五、通过redis来喂饱爬虫们~

scrapy_redis.spiders.RedisSpider类启用了爬虫通过redis得到urls,这些在redis队列中的爬虫将会一个接一个的被处理,!!如果第一个request产生了更多的request,爬虫会先处理这些请求,再从redis队列中抓取其他url。

上面偷懒,这里举个栗子:创建 couxiaoxiao.py

 

[plain] view plain copy
 
  1. from scrapy_redis.spiders import RedisSpider  
  2. </pre></div><div><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_47_2390110" name="code" class="python">class MySpider(RedisSpider):  
  3.     name = 'myspider'  
  4. </pre></div><div><pre code_snippet_id="1682225" snippet_file_name="blog_20160513_50_2662327" name="code" class="python">    def parse(self, response):  
  5.         # do stuff  
  6.         pass  

 

运行爬虫
[python] view plain copy
 
  1. scrapy runspider myspider.py  
向redis中装入url们
 
[python] view plain copy
 
  1. redis-cli lpush myspider:start_urls http://xiaowangzhi.com