【Scrapy-Redis】分布式爬虫实战(非常详细)

一、概要

1.分布式爬虫概念

        分布式爬虫是一种利用多台机器协同工作的网络爬虫系统,通过任务分解、并行处理和资源共享,高效抓取并处理海量网页数据。其核心在于将爬取任务分配到不同节点,避免单点性能瓶颈,同时支持动态扩展和容错机制,适用于大规模数据采集场景。

        在爬虫众多框架中,scrapy-redis是最常用的实现分布式爬虫的框架,它区别于之前我们学习的scrapy,它将Redis作为他的调度器队列,所有的请求对象均从Redis获取,Redis的set集合会自动对所有请求对象进行去重,从实现了多台机器同时爬取和断点续爬的功能。

2.分布式爬虫流程

        下图形象的展示了scrapy-redis的工作流程,可以看到和我们之前的scrapy的spider,schedule换了个方向,spider被放到了最上方。

        下面这个图更加形象的展示四台主机同时连接Redis服务器进行爬虫的过程。当然我们也可以扩充到多台主机的情况。在scrapy-redis中,Redis服务端被称作master主机,而把用于跑爬虫程序的机器称为slave。

        简要概括,scrapy-redis的工作流程如下:

  1. 调度器共享:所有爬虫实例共享同一个 Redis 中的请求队列,新发现的 URL 会被统一存入队列。
  2. 请求去重:利用 Redis 的集合结构(Set)对请求 URL 进行全局去重,避免重复爬取。
  3. 任务分配:各爬虫从 Redis 队列中竞争获取待爬 URL,实现负载均衡。
  4. 数据存储:爬取到的数据可统一存入 Redis 或其他存储系统(如数据库)。
  5. 断点续传:Redis 持久化保存爬取进度,支持暂停后恢复。

二、分布式爬虫准备

1.准备工作

        我们准备三台电脑进行分布式爬取,(忽略图中的centos),其中远程Ubuntu16.04作为我们的Redis服务器(master端),不负责爬取,只负责数据的分配。而使用Windows和另外一台本地虚拟机Ubuntu16.04作为slaver端进行爬虫的执行。

        

           

2.Master端配置

        首先我们在远程ubuntu服务器上安装Redis,命令如下:

sudo apt install redis-server

        接下来我们尝试打开redis-cli,并ping,如果返回pong就说明安装成功了。命令如下:

redis-cli
ping

        接下来我们要配置Redis,允许远程主机连接。操作如下:

sudo vi /etc/redis/redis.conf

               第一步,将bind 127.0.0.1注释掉。

        第二步,将protected mode从yes改成no。关闭保护模式。

        然后按ESC,输入:wq!保存,输入下面命令重启Redis即可。

sudo systemctl restart redis-server

       然后准备好Redis的主机IP地址,后续连接需要要到。

        如果你是远程Redis的话,不要忘了关闭防火墙,并开放相应的6379端口。本地的话就不用了。

3.Slaver端配置

        首先我们给两台slaver分别安装上scrapy和scrapy-redis,注意scrapy安装2.8以下的版本,这样才能和scrapy-redis兼容,scrapy-redis安装最新版本即可。输入以下命令即可安装。

        注意!!!这里一定要重新安装twisted旧版本,因为新版本的scrapy不兼容。所以下图的命令还要再加一个。

pip install twisted==22.10.0

        安装完成之后接下来我们测试一下两台slaver能否正常连接Redis服务器。

        可以直接在slaver端装上Redis的图形化界面控制端,用来测试Redis的连接。当然,如果是ubuntu,也可以通过运行Python脚本来测试是否能够正常连接Redis。这里给出方法:

  •  对于Windows

        安装包:https://wwql.lanzout.com/b052o0lmf,密码:3rsj。

        链接中包含redis图形化界面和redis安装包,我们只需要安装图形化界面即可。我这里临时测试,就不下载工具了,直接用PyCharm的自带的Redis链接工具连接了。如果你对PyCharm不太熟悉,建议直接使用图形化界面。

        下面给出在PyCharm中链接Redis的方法:

  • 对于Ubuntu

        我们采用一个简单的Python脚本来测试是否能够正常连接Redis服务器。脚本如下,注意主机和其它选项要改成你自己的:

import redis

def test_redis_connection(host, port=6379, password=None, db=0):
    """
    测试Redis连接
    :param host: Redis服务器地址
    :param port: 端口 (默认6379)
    :param password: 密码 (可选)
    :param db: 数据库编号 (默认0)
    """
    try:
        # 创建Redis连接
        r = redis.Redis(
            host=host,
            port=port,
            password=password,
            db=db,
            socket_timeout=3  # 3秒超时
        )
        
        # 发送PING命令测试连接
        response = r.ping()
        if response:
            print(f"✅ 连接成功!Redis版本: {r.info()['redis_version']}")
        return True
    except Exception as e:
        print(f"❌ 连接失败: {str(e)}")
        return False

if __name__ == "__main__":
    # 在此处填写Redis连接信息
    HOST = "your_redis_host"  # 替换为实际主机IP/域名
    PORT = 6379               # 替换为实际端口
    PASSWORD = None           # 如有密码,替换为字符串(如: "mypassword")
    DB = 0                    # 替换为实际数据库编号
    
    # 执行测试
    test_redis_connection(
        host=HOST,
        port=PORT,
        password=PASSWORD,
        db=DB
    )

三、分布式爬虫实现

        scrapy-redis的分布式爬虫实现步骤可以总结为以下几步:

  1.         编写scrapy爬虫项目
  2.         更换默认spider父类为Redis类
  3.         修改配置文件setting.py
  4.         设置起始url的key 为[top250:start_urls]  

1.爬虫生成

        这里我们用最经典的豆瓣电影top250作为示例。首先在控制台输入下面命令生成爬虫项目。

#创建项目
scrapy startproject douban
cd douban
#创建Spider
scrapy genspider movie_rank movie.douban.com

        生成的项目目录如下:

        接着这里我直接复制使用之前已经写好了的豆瓣top250爬虫逻辑,建议先提前将基础爬虫逻辑用scrapy写完,然后修改成scrapy-redis即可。

     具体的代码逻辑可以直接参考我之前的文章,scrapy爬取豆瓣250。

2.修改父类

        打开movie_rank.py,导入Scrapy_redis的redis-spider,然后让爬虫类继承它。

3.修改setting.py

        打开settings.py文件,将以下设置覆盖掉,使用scrapy-redis的配置,不建议将管道添加Redis,因为Redis适合存取常用数据。Redis地址要记得换成自己的。

# Obey robots.txt rules
# 关闭遵守协议
ROBOTSTXT_OBEY = False
# 持久化配置
SCHEDULER_PERSIST = True
# 使用scrapy - redis调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# scrapy - redis指纹过滤器
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# redis链接地址
REDIS_URL ='redis://127.0.0.1:6379/0'
# 任务的优先级别
SCHEDULER_QUEUE_CLASS ='scrapy_redis.queue.PriorityQueue'
# 存放的管道,可以开通第一个,数据会保存到redis,但不建议这么做
ITEM_PIPELINES = {
   # 'scrapy_redis.pipelines.RedisPipeline': 300,
    'douban.pipelines.DoubanPipeline': 301,
}
# 请求头
DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q = 0.9,*/*;q = 0.8',
    'Accept - Language': 'en',
    'User - Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
}

4.设置起始url的key

        因为我们的爬取URL都是要从Redis获取的,所有我们不需要手动设置起始的URL,也就是START_URL,在scrapy-Redis中,只需要设置redis-key,scrapy就会自动去Redis中寻找起始的url。操作如下:

        

# 前面是爬虫名,后面是固定start_urls
redis_key = 'movie_rank:start_urls'

5.slaver1测试

        接下来我们可以尝试运行slaver1的scrapy-redis项目。

scrapy crawl movie_rank

        可以看到卡在了此处,因为程序正在等待我们向Redis中添加起始URL。

         我们现在尝试使用Python脚本在Redis中添加Redis_key作为起始URL。

import redis

# 连接到Redis
r = redis.Redis(host='127.0.0.1', port=6379)

# 添加起始URL
r.lpush('movie_rank:start_urls', 'https://book.douban.com/top250')

        可以看到爬虫自动读取到了我们添加的URL,不过抓取失败了,因为400错误码,我们的请求头有问题。在scrapy-Redis中,默认的请求头是scrapy-Redis,我们需要修改它。

        我们在中间件中重写下载器中间件的请求头,示例代码如下:

class DoubanDownloaderMiddleware:
    # Not all methods need to be defined. If a method is not defined,
    # scrapy acts as if the downloader middleware does not modify the
    # passed objects.

    @classmethod
    def from_crawler(cls, crawler):
        # This method is used by Scrapy to create your spiders.
        s = cls()
        crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
        return s

    def process_request(self, request, spider):
        # Called for each request that goes through the downloader
        # middleware.

        # Must either:
        # - return None: continue processing this request
        # - or return a Response object
        # - or return a Request object
        # - or raise IgnoreRequest: process_exception() methods of
        #   installed downloader middleware will be called
        request.headers.setdefault('User-Agent', self.get_random_ua())
        print(request.headers)
        return None

    def get_random_ua(self):
        # 随机 User-Agent 列表
        user_agents = [
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Safari/605.1.15',
            'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36'
        ]
        return random.choice(user_agents)

        然后再设置中启用中间件,再次运行可以看到成功拿到数据了。

6.slaver2测试
        接下来我们来调试slaver2,slaver2使用的是Ubuntu16.04操作系统,所以需要提前准备好Python解释器和其他配置项。这里就不多加赘述了。

        然后将我们之前的项目全部打包放入任意位置。不需要做任何修改,直接运行爬虫即可。这里就不再演示,大家可以自己尝试一下。

四、总结

最后附上源码地址:豆瓣读书分布式爬虫: 采用scrapy-Redis实现豆瓣阅读分布式爬虫。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值