srcapy-redis 分布式爬虫

整体架构

主服务器:部署了 redis ,我们通过手动的方式,加入 start_urls 然后在启动爬虫

从服务器:部署了多个爬虫

 

srcapy-redis 分布式爬虫

使用官方的例子来修改

先从 GitHub 上拿到scrapy-redis的示例,然后将里面的example-project目录移到指定的地址:

# clone github scrapy-redis源码文件
git clone https://github.com/rolando/scrapy-redis.git

# 直接拿官方的项目范例,改名为自己的项目用(针对懒癌患者)
mv scrapy-redis/example-project ~/scrapyredis-project

我们clone到的 scrapy-redis 源码中有自带一个example-project项目,这个项目包含3个spider,分别是dmoz, myspider_redis,mycrawler_redis。

配置文件详解

setting

# Scrapy settings for example project
#
# For simplicity, this file contains only the most important settings by
# default. All the other settings are documented here:
#
#     http://doc.scrapy.org/topics/settings.html
#

# 指定 redis 的地址和端口
REDIS_HOST = 'localhost'
REDIS_PORT = 6379

# 指定 redis 的密码
REDIS_PARAMS = {
   'password': '123456',
}

SPIDER_MODULES = ['example.spiders']
NEWSPIDER_MODULE = 'example.spiders'

USER_AGENT = 'scrapy-redis (+https://github.com/rolando/scrapy-redis)'

# redis 过滤器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 指定是否开启断点续传
SCHEDULER_PERSIST = True

# SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
# SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
# SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"

# 需要开启中间件管道中间件
ITEM_PIPELINES = {
   'example.pipelines.ExamplePipeline': 300,
   'scrapy_redis.pipelines.RedisPipeline': 400,
}

LOG_LEVEL = 'DEBUG'

# Introduce an artifical delay to make use of parallelism. to speed up the
# crawl.
DOWNLOAD_DELAY = 1
一、dmoz (class DmozSpider(CrawlSpider))

这个没有进行分布式架构

这个爬虫继承的是CrawlSpider,它是用来说明Redis的持续性,当我们第一次运行dmoz爬虫,然后Ctrl + C停掉之后,再运行dmoz爬虫,之前的爬取记录是保留在Redis里的。

分析起来,其实这就是一个 scrapy-redis 版 CrawlSpider 类,需要设置Rule规则,以及callback不能写parse()方法。

> 执行方式 scrapy crawl dmoz

这部分都是一样的

from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule


class DmozSpider(CrawlSpider):
   """Follow categories and extract links."""
   name = 'dmoz'
   allowed_domains = ['74.120.174.165']
   start_urls = ['http://74.120.174.165:8888/']

   rules = [
       Rule(LinkExtractor(restrict_xpaths=('//a[@class="btn btn-warning"]')),callback='parse_directory', follow=True),
  ]

   def parse_directory(self, response):
       print(response)

 

二、myspider_redis (class Myspider(RedisSpider))

这个爬虫继承了RedisSpider, 它能够支持分布式的抓取,采用的是basic spider,需要写parse函数。

其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出来,成为请求的url地址。

scrapy 会在取 redis 中的urls,如果没有就会阻塞,直到redis有值

from scrapy_redis.spiders import RedisSpider


class MySpider(RedisSpider):
   """Spider that reads urls from redis queue (myspider:start_urls)."""
   name = 'myspider_redis'

   # 这里相当于是定义好的 start_urls ,只不过要到 redis 中定义这个值
   # scrapy 会在 redis 当中取这个值
   # 在 redis 既可以是字符串,也可以是列表
   redis_key = 'myspider:start_urls'

   def __init__(self, *args, **kwargs):
       # 可选:等效于allowd_domains(),__init__方法按规定格式写,使用时只需要修改super()里的类名参数即可
       # Dynamically define the allowed domains list.
       domain = kwargs.pop('domain', '')
       self.allowed_domains = filter(None, domain.split(','))
       
       # 修改这里的类名为当前类名
       super(MySpider, self).__init__(*args, **kwargs)

   def parse(self, response):
       print(response.url)

       # 这个下面具体的内容,会保存在 redis 当中
       return {
           'name': 'stefan',
           'url': response.url,
      }
   
  # 或者还是 yield ,自己在管道里面处理。
       # 同时也可以 scrapy.Request()

 

注意

RedisSpider类 不需要写allowd_domainsstart_urls

  1. scrapy-redis将从在构造方法__init__()里动态定义爬虫爬取域范围,也可以选择直接写allowd_domains

  2. 必须指定redis_key,即启动爬虫的命令,参考格式:redis_key = 'myspider:start_urls'

  3. 根据指定的格式,start_urls将在 Master端的 redis-cli 里 lpush 到 Redis数据库里,RedisSpider 将在数据库里获取start_urls。

 

执行方式
  1. 通过runspider方法执行爬虫的py文件(也可以分次执行多条),爬虫(们)将处于等待准备状态:

    scrapy runspider myspider_redis.py

    scrapy crawl myspider_redis.py

  2. 在Master端的redis-cli输入push指令,参考格式:

    $redis > lpush myspider:start_urls http://www.dmoz.org/

  3. Slaver端爬虫获取到请求,开始爬取。

 

 

三、mycrawler_redis (class Mycrawler (RedisCrawlSpider))

这个RedisCrawlSpider类爬虫继承了RedisCrawlSpider,能够支持分布式的抓取。因为采用的是crawlSpider,所以需要遵守Rule规则,以及callback不能写parse()方法。

同样也不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出来,成为请求的url地址。

from scrapy.spiders import Rule
from scrapy.linkextractors import LinkExtractor

from scrapy_redis.spiders import RedisCrawlSpider


class MyCrawler(RedisCrawlSpider):
   """Spider that reads urls from redis queue (myspider:start_urls)."""
   name = 'mycrawler_redis'
   redis_key = 'mycrawler:start_urls'

   rules = (
       # follow all links
       Rule(LinkExtractor(), callback='parse_page', follow=True),
  )

   # __init__方法必须按规定写,使用时只需要修改super()里的类名参数即可
   def __init__(self, *args, **kwargs):
       # Dynamically define the allowed domains list.
       domain = kwargs.pop('domain', '')
       self.allowed_domains = filter(None, domain.split(','))

       # 修改这里的类名为当前类名
       super(MyCrawler, self).__init__(*args, **kwargs)

   def parse_page(self, response):
       return {
           'name': response.css('title::text').extract_first(),
           'url': response.url,
      }

 

注意

同样的,RedisCrawlSpider类不需要写allowd_domainsstart_urls

  1. scrapy-redis将从在构造方法__init__()里动态定义爬虫爬取域范围,也可以选择直接写allowd_domains

  2. 必须指定redis_key,即启动爬虫的命令,参考格式:redis_key = 'myspider:start_urls'

  3. 根据指定的格式,start_urls将在 Master端的 redis-cli 里 lpush 到 Redis数据库里,RedisSpider 将在数据库里获取start_urls。

执行方式
  1. 通过runspider方法执行爬虫的py文件(也可以分次执行多条),爬虫(们)将处于等待准备状态:

    scrapy runspider myspider_redis.py

    scrapy crawl myspider_redis.py

  2. 在Master端的redis-cli输入push指令,参考格式:

    $redis > lpush myspider:start_urls http://www.dmoz.org/

  3. Slaver端爬虫获取到请求,开始爬取。

 

 

总结

  1. 如果只是用到Redis的去重和保存功能,就选第一种;

  2. 如果要写分布式,则根据情况,选择第二种、第三种;

  3. 通常情况下,会选择用第三种方式编写深度聚焦爬虫。

  4.  

最新评论
暂无评论
登录后评论