Scrapy 是 Python 的一个非常强大的爬虫库,但是当我们要爬取的页面非常多的时候,单个主机的处理能力就不能满足我们的需求了(无论是处理速度还是网络请求的并发数),这时候分布式爬虫的优势就显现出来。而 scrapy_redis 就是结合了分布式数据库 Redis,重写了 Scrapy 的任务调度器,将 Scrapy 变成一个可以在多个主机上同时运行的分布式爬虫。
scrapy_redis 工程的主体还是是 Redis 和 Scrapy 两个库,工程本身实现的东西不是很多,这个工程就像胶水一样,把这两个插件粘结了起来。下面我们来看看,scrapy_redis 的每一个源代码文件都实现了什么功能,最后如何实现分布式的爬虫系统。
defaults: 默认参数配置
本模块主要定义了一些默认参数,这些都可以在 Scrapy 的 settings 中设置:
- Redis 连接参数
- REDIS_CLS
- REDIS_ENCODING
- REDIS_PARAMS
- PIPELINE_KEY: 数据存储在 Redis 的 key
- SCHEDULER_*: 参与任务调度的 Redis key,包括 requests 存储,调度队列类型选择,去重指纹存储
- START_URLS_*: 任务注入 Redis 的 key 和 数据类型
import redis
# For standalone use.
DUPEFILTER_KEY = 'dupefilter:%(timestamp)s'
PIPELINE_KEY = '%(spider)s:items'
REDIS_CLS = redis.StrictRedis
REDIS_ENCODING = 'utf-8'
# Sane connection defaults.
REDIS_PARAMS = {
'socket_timeout': 30,
'socket_connect_timeout': 30,
'retry_on_timeout': True,
'encoding': REDIS_ENCODING,
}
SCHEDULER_QUEUE_KEY = '%(spider)s:requests'
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
SCHEDULER_DUPEFILTER_KEY = '%(spider)s:dupefilter'
SCHEDULER_DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
START_URLS_KEY = '%(name)s:start_urls'
START_URLS_AS_SET = False
connection: 建立 Redis 连接
顾名思义,本模块用于建立 Redis 连接,其中定义了:
- SETTINGS_PARAMS_MAP: 用于将 Redis 参数名映射到 redis 库的参数名
- get_redis_from_settings 函数: 从 Scrapy 的 settings 对象获取连接参数并调用 get_redis 建立 Redis 连接
- get_redis 函数: 辅助函数,从传入参数建立 Redis 连接
SETTINGS_PARAMS_MAP = {
'REDIS_URL': 'url',
'REDIS_HOST': 'host',
'REDIS_PORT': 'port',
'REDIS_ENCODING': 'encoding',
}
def get_redis_from_settings(settings):
"""Returns a redis client instance from given Scrapy settings object.
This function uses ``get_client`` to instantiate the client and uses
``defaults.REDIS_PARAMS`` global as defaults values for the parameters. You
can override them using the ``REDIS_PARAMS`` setting.
Parameters
----------
settings : Settings
A scrapy settings object. See the supported settings below.
Returns
-------
server
Redis client instance.
Other Parameters
----------------
REDIS_URL : str, optional
Server connection URL.
REDIS_HOST : str, optional
Server host.
REDIS_PORT : str, optional
Server port.
REDIS_ENCODING : str, optional
Data encoding.
REDIS_PARAMS : dict, optional
Additional client parameters.
"""
def get_redis(**kwargs):
"""Returns a redis client instance.
Parameters
----------
redis_cls : class, optional
Defaults to ``redis.StrictRedis``.
url : str, optional
If given, ``redis_cls.from_url`` is used to instantiate the class.
**kwargs
Extra parameters to be passed to the ``redis_cls`` class.
Returns
-------
server
Redis client instance.
"""
utils
模块内只有一个方法 bytes_to_str,用于将字节序列转换为字符串,因为使用 redis 模块读取的字符数据都为 bytes,所以使用前需要解码为 str 。
queue: 任务调度队列
本模块定义了三中队列(FifoQueue、PriorityQueue、LifoQueue)用于任务调度。
- Base 基类:
- _encode_request: 将 request 对象转为字典并序列化(默认 pickle)
- _decode_request: 和上面相反,反序列化回 request 对象
class Base(object):
"""Per-spider base queue class"""
def __init__