Python爬虫——Scrapy_redis快速上手(爬虫分布式改造)

文章目录

  • 前言
  • 分布式原理
  • scrapy_redis项目编写

前言

scrapy是python界出名的一个爬虫框架。Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
虽然scrapy能做的事情很多,但是要做到大规模的分布式应用则捉襟见肘。有能人改变了scrapy的队列调度,将起始的网址从start_urls里分离出来,改为从redis读取,多个客户端可以同时读取同一个redis,从而实现了分布式的爬虫。就算在同一台电脑上,也可以多进程的运行爬虫,在大规模抓取的过程中非常有效。

分布式原理

scrapy-redis实现分布式,其实从原理上来说很简单,这里为描述方便,我们把自己的核心服务器称为master,而把用于跑爬虫程序的机器称为slave。

我们知道,采用scrapy框架抓取网页,我们需要首先给定它一些start_urls,爬虫首先访问start_urls里面的url,再根据我们的具体逻辑,对里面的元素、或者是其他的二级、三级页面进行抓取。而要实现分布式,我们只需要在这个starts_urls里面做文章就行了。

我们在master上搭建一个redis数据库(注意这个数据库只用作url的存储,不关心爬取的具体数据,不要和后面的mongodb或者mysql混淆),并对每一个需要爬取的网站类型,都开辟一个单独的列表字段。通过设置slave上scrapy-redis获取url的地址为master地址。这样的结果就是,尽管有多个slave,然而大家获取url的地方只有一个,那就是服务器master上的redis数据库。

并且,由于scrapy-redis自身的队列机制,slave获取的链接不会相互冲突。这样各个slave在完成抓取任务之后,再把获取的结果汇总到服务器上(这时的数据存储不再在是redis,而是mongodb或者 mysql等存放具体内容的数据库了)

这种方法的还有好处就是程序移植性强,只要处理好路径问题,把slave上的程序移植到另一台机器上运行,基本上就是复制粘贴的事情。

Scrapy-Redis是一个基于Redis的Scrapy分布式组件。它利用Redis对用于爬取的请求(Requests)进行存储和调度(Schedule),并对爬取产生的项目(items)存储以供后续处理使用。scrapy-redi重写了scrapy一些比较关键的代码,将scrapy变成一个可以在多个主机上同时运行的分布式爬虫。

scrapy_redis项目编写

  1. 首先需要编写一个scrapy的项目,之后在该项目的基础上修改相关配置即可实现,这里就不再做过多的解释
  2. 准备好redis数据库,打开,连接上客户端
  3. 修改settings、以及爬虫文件

settings文件中加入以下配置,并根据自己配置修改IP地址、端口号、以及密码

# 启用 Scrapy-Redis 调度存储请求队列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 去重规则对应处理的类
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

# 对保存到 redis 中的数据进行序列化,默认使用pickle
# SCHEDULER_SERIALIZER = "scrapy_redis.picklecompat"

# 不清除 Redis 队列,即是否在关闭时候保留原来的调度器和去重记录。
# True=保留,False=清空。这样可以暂停/恢复 爬取
SCHEDULER_PERSIST = True

# 是否在开始之前清空 调度器和去重记录,True=清空,False=不清空
# SCHEDULER_FLUSH_ON_START = True

DEPTH_PRIORITY = 1  # 广度优先
# DEPTH_PRIORITY = -1 # 深度优先
# 使用优先级调度请求队列 (默认使用)
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'

# 可选用的其它队列 PriorityQueue(有序集合),FifoQueue(列表)、LifoQueue(列表)
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'  # 广度优先
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'  # 深度优先

# 最大空闲时间防止分布式爬虫因为等待而关闭
# 去调度器中获取数据时,如果为空,最多等待时间(最后没数据,未获取到)。
# SCHEDULER_IDLE_BEFORE_CLOSE = 10

# 使用 scrapy-redis 的 pipeline 进行数据处理


# 序列化项目管道作为redis Key存储
# REDIS_ITEMS_KEY = '%(spider)s:items'

# 默认使用 ScrapyJSONEncoder进行项目序列化
# You can use any importable path to a callable object.
# REDIS_ITEMS_SERIALIZER = 'json.dumps'

# 指定连接到redis时使用的端口和地址(可选)
# REDIS_HOST = 'localhost'
# REDIS_PORT = 6379

# 指定用于连接 redis 的 URL(可选)。
# 如果设置此项,则此项优先级高于设置的 REDIS_HOST 和 REDIS_PORT。
# 如果没有 user 默认是 root 。
# 示例 REDIS_URL = "redis://root:[email protected]:6379"
# REDIS_URL = 'redis://user:pass@hostname:9001'


# 连接redis
REDIS_HOST = '127.0.0.1'  # 主机名
REDIS_PORT = 6379  # 端口
REDIS_PARAMS = {'password': ''}  # Redis连接参数。
REDIS_ENCODING = "utf-8"  # redis编码类型。默认:'utf-8'
# 或者:
# REDIS_URL = 'redis://user:pass@hostname:6379'  # 连接 URL(优先于以上配置)

# 自定义redis客户端类
# REDIS_PARAMS['redis_cls'] = 'myproject.RedisClient'

# 如果为True,则使用redis的'spop'进行操作。
# 如果需要避免起始网址列表出现重复,这个选项非常有用。开启此选项 urls 必须通过sadd添加,否则会出现类型错误。
# REDIS_START_URLS_AS_SET = False

# RedisSpider 和 RedisCrawlSpider 默认 start_usls 键
# REDIS_START_URLS_KEY = '%(name)s:start_urls'

爬虫文件中修改如下:
1.修改继承的父类
2.注销之前写好的 allowed_domains和start_urls
3编写__init__方法,copy下面的代码即可,形式比较固定
4.设置redis_key的键名,并在redis中加入该键名,值为之前
start_urls中的值。
代码为:lpush py21 + start_urls中的值

from scrapy_redis.spiders import RedisCrawlSpider
class OutsideSpider(RedisCrawlSpider):
    num = 0
    name = 'outside'
    # allowed_domains = ['www.chinaseed114.com']
    # start_urls = ['https://www.chinaseed114.com/seed/xiaomai']
    def __init__(self, *args,**kwargs):
        domain = kwargs.pop('domain', '')
        self.allowed_domains = list(filter(None, domain.split(',')))
        super(OutsideSpider, self).__init__(*args, **kwargs)
    redis_key = 'py21'
  1. 多终端测试

最后可以开启多个终端来测试本次分布式爬虫是否成功。
tips:终端中启动爬虫的命令是scrapy runspider + 爬虫文件名
例如:scrapy runspider outside.py

你可能感兴趣的:(#,Python爬虫,python,redis,网络爬虫,爬虫,分布式)