当前位置: 首页 > news >正文

零基础掌握 Scrapy 和 Scrapy-Redis:爬虫分布式部署深度解析

如果你对网络数据抓取充满好奇,想从海量信息中提取有价值的内容,那么 Scrapy 绝对是你不可错过的利器!而当你需要处理大规模数据抓取,或者担心单机性能瓶颈时,Scrapy-Redis 更是你的不二之选,它能让你的爬虫具备分布式、可扩展的能力。

本篇博客将带你从零开始,深入理解 Scrapy 的执行流程,并手把手教你如何使用 Scrapy-Redis 构建一个分布式爬虫系统。即使你是编程小白,也能轻松掌握!

Scrapy 篇:单机爬虫的精妙艺术

首先,我们来认识 Scrapy,它是 Python 领域一个强大而高效的爬虫框架。它的设计理念是高度模块化,让你可以专注于数据提取和业务逻辑,而无需过多关注底层的网络请求、并发处理等细节。

Scrapy 的核心组件

理解 Scrapy 的执行流程,要从它的核心组件说起:

  • Scrapy Engine(引擎):Scrapy 的核心,负责控制所有组件的数据流,并根据请求和响应进行调度。它就像一个指挥官,协调各个部件协同工作。
  • Scheduler(调度器):负责接收引擎发来的请求,并将其放入队列中,等待引擎请求时提供。它会根据优先级对请求进行排序,并负责去重。
  • Downloader(下载器):负责下载网页内容。它接收引擎发来的请求,向目标网站发送 HTTP/HTTPS 请求,并将返回的响应(网页内容)发送给引擎。
  • Spiders(爬虫):这是你编写爬虫逻辑的地方。它负责解析下载器返回的响应,提取所需数据,并生成新的请求(比如页面中的其他链接)。
  • Item Pipelines(项目管道):负责处理爬虫提取到的数据。你可以将数据清洗、验证、持久化(保存到数据库、文件等)等操作放在这里。
  • Downloader Middlewares(下载器中间件):介于引擎和下载器之间,可以在请求发送前和响应接收后进行处理。比如设置代理、User-Agent、处理 cookies 等。
  • Spider Middlewares(爬虫中间件):介于引擎和爬虫之间,可以在请求发送给爬虫前和爬虫处理响应后进行处理。
Scrapy 的执行流程(单机版)

理解了核心组件,Scrapy 的执行流程就变得清晰起来:

  1. 启动爬虫:当你运行 scrapy crawl your_spider_name 命令时,Scrapy 引擎会启动。
  2. 生成初始请求:引擎会向你定义的 Spider 发送一个信号,告知其开始爬取。Spider 会生成初始的 Request 对象(通常是爬取入口 URL),并将其发送给引擎。
  3. 请求入队:引擎接收到 Request 后,会将其转发给 SchedulerScheduler 将请求添加到队列中,并进行去重。
  4. 请求出队,发送下载:引擎从 Scheduler 请求下一个可用的 RequestSchedulerRequest 返回给引擎。引擎再将 Request 转发给 Downloader Middlewares 进行预处理(比如添加代理)。
  5. 下载页面:经过 Downloader Middlewares 处理的 Request 会被发送给 DownloaderDownloader 向目标网站发送 HTTP/HTTPS 请求,获取网页内容。
  6. 响应处理Downloader 接收到网站响应后,会将其封装成 Response 对象,并先经过 Downloader Middlewares 进行后处理。
  7. 响应解析:经过 Downloader Middlewares 处理的 Response 对象被发送回引擎。引擎再将其转发给 Spider Middlewares 进行预处理,最后交给 Spider 进行解析。
  8. 数据提取与新请求生成Spider 接收到 Response 后,会根据你编写的解析规则(通常使用 XPath 或 CSS 选择器)提取所需数据,并封装成 Item 对象。同时,它可能会从当前页面中提取新的链接,并生成新的 Request 对象。
  9. 数据入管道,新请求入队SpiderItem 和新的 Request 都发送给引擎。引擎将 Item 转发给 Item Pipelines 进行后续处理(清洗、存储等)。新的 Request 则再次发送给 Scheduler,重复步骤 3-8。
  10. 爬虫结束:当 Scheduler 中没有待处理的 Request,并且所有 Item Pipelines 都处理完毕时,Scrapy 引擎会停止,爬虫任务完成。
动手实践:一个简单的 Scrapy 爬虫

为了让你更好地理解,我们来创建一个简单的 Scrapy 爬虫,抓取某个网站的标题和链接。

  1. 安装 Scrapy

    pip install scrapy
    
  2. 创建 Scrapy 项目

    scrapy startproject myproject
    cd myproject
    
  3. 创建 Spider

    scrapy genspider example example.com
    

    这会在 myproject/myproject/spiders/ 目录下生成 example.py 文件。

  4. 编辑 example.py

    import scrapyclass ExampleSpider(scrapy.Spider):name = "example"allowed_domains = ["example.com"] # 限制爬取范围start_urls = ["http://example.com"] # 初始请求的URLdef parse(self, response):# 提取页面标题title = response.css('h1::text').get()# 提取所有链接links = response.css('a::attr(href)').getall()yield {'title': title,'links': links,}# 如果需要继续爬取其他页面,可以生成新的请求# for link in links:#     yield response.follow(link, callback=self.parse)
    
  5. 运行爬虫

    scrapy crawl example -o output.json
    

    这会将抓取到的数据保存到 output.json 文件中。

Scrapy-Redis 篇:分布式爬虫的实现

单机 Scrapy 爬虫在处理大量数据时可能会遇到性能瓶颈,比如内存占用过高、请求频率受限等。这时,Scrapy-Redis 就派上用场了!它能将 Scrapy 爬虫的请求队列和去重指纹存储到 Redis 数据库中,从而实现多个爬虫实例共享队列、协同工作,达到分布式爬取的效果。

为什么需要 Scrapy-Redis?
  • 分布式爬取:多台机器可以同时运行爬虫实例,共享同一个 Redis 队列,提高爬取效率。
  • 断点续爬:请求队列和去重指纹存储在 Redis 中,即使爬虫意外中断,重启后也能从上次中断的地方继续爬取,避免重复抓取和数据丢失。
  • 共享 Request 队列:所有爬虫实例从同一个 Redis 队列中获取待爬取的 URL,避免重复爬取。
  • 共享去重指纹:Redis 存储了已爬取 URL 的指纹,确保不会重复爬取相同页面。
Scrapy-Redis 的核心原理

Scrapy-Redis 的核心在于将 Scrapy 的 SchedulerDupeFilter(去重过滤器)替换掉,转而使用 Redis 来存储和管理请求队列以及去重指纹。

当使用 Scrapy-Redis 时,Scrapy 的执行流程会发生如下变化:

  1. 启动爬虫(Scrapy-Redis 版):当你运行 Scrapy-Redis 爬虫时,它会连接到 Redis 数据库。
  2. 初始请求入 RedisSpider 生成的初始 Request 对象不再直接发送给 Scrapy 内置的 Scheduler,而是被发送到 Redis 队列中。
  3. 请求从 Redis 出队:Scrapy-Redis 的 Scheduler 会从 Redis 队列中获取待爬取的 Request
  4. 去重在 Redis:在将 Request 放入队列前或从队列取出后,Scrapy-Redis 的 DupeFilter 会检查 Redis 中是否已经存在该请求的指纹,从而实现去重。
  5. 后续流程不变:一旦 Request 从 Redis 队列中取出并经过去重,后续的下载、响应处理、数据提取等流程与单机 Scrapy 基本一致。
  6. 新请求入 RedisSpider 解析页面后生成的新 Request 也同样发送到 Redis 队列中。
动手实践:构建一个 Scrapy-Redis 分布式爬虫

接下来,我们来改造上面的 Scrapy 爬虫,让它具备分布式能力。

  1. 安装 Scrapy-Redis 和 Redis

    pip install scrapy-redis redis
    

    你还需要在本地或服务器上安装并运行 Redis 服务。具体安装方法请参考 Redis 官方文档。

  2. 修改 settings.py 文件
    在你的 Scrapy 项目的 settings.py 文件中,添加或修改以下配置:

    # 启用 Scrapy-Redis 的调度器和去重过滤器
    SCHEDULER = "scrapy_redis.scheduler.Scheduler"
    DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"# 设置调度器是否持久化。如果为 True,Scrapy 停止后,Redis 中的请求队列和指纹不会被清除。
    SCHEDULER_PERSIST = True# 设置 Redis 连接信息
    REDIS_HOST = 'localhost' # 你的 Redis 服务器地址
    REDIS_PORT = 6379 # 你的 Redis 服务器端口
    REDIS_DB = 0 # Redis 数据库编号# 可以设置 Scrapy-Redis 的队列类型,默认是 LIFO(栈),也可以改为 FIFO(队列)
    # SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue" # 队列
    # SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack" # 栈
    # SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue" # 优先级队列# 如果需要爬虫启动时清除 Redis 中之前的请求,可以设置为 False
    # Dont cleanup redis queues, allows to start where was disconnected.
    # SCHEDULER_PERSIST = True
    
  3. 修改 example.py 文件
    让你的 Spider 继承 scrapy_redis.spiders.RedisSpider
    注意: 继承 RedisSpider 后,你的 start_urls 不再生效,你需要通过 Redis 来提交初始 URL。

    import scrapy
    from scrapy_redis.spiders import RedisSpiderclass ExampleSpider(RedisSpider): # 继承 RedisSpidername = "example_redis" # 更改爬虫名称,避免与之前的冲突allowed_domains = ["example.com"]# start_urls 不再需要,初始 URL 将从 Redis 中获取# start_urls = ["http://example.com"]# Redis 键名,用于存储待爬取的 URLredis_key = 'example_redis:start_urls'def parse(self, response):title = response.css('h1::text').get()links = response.css('a::attr(href)').getall()yield {'title': title,'links': links,}for link in links:# 使用 response.follow 生成新的请求,这些请求会自动发送到 Redisyield response.follow(link, callback=self.parse)
    
  4. 启动 Redis
    确保你的 Redis 服务正在运行。

  5. 提交初始 URL 到 Redis
    在运行爬虫之前,你需要手动将初始 URL 提交到 Redis 中。你可以使用 Redis 客户端工具(如 redis-cli)或者 Python 代码来完成。

    使用 redis-cli

    redis-cli LPUSH example_redis:start_urls http://example.com
    

    这里的 example_redis:start_urls 就是你在 Spider 中定义的 redis_keyLPUSH 命令将 URL 添加到 Redis 列表的左侧。

  6. 运行分布式爬虫

    scrapy crawl example_redis
    

    现在,你的爬虫实例会从 Redis 中获取 URL 进行爬取。你可以启动多个终端,运行相同的命令,它们会共享同一个 Redis 队列,实现分布式爬取。

分布式部署的关键步骤
  1. 准备多台机器:你需要多台服务器或虚拟机来部署你的爬虫实例。
  2. 安装 Redis:在一台独立的服务器上部署 Redis 服务,确保所有爬虫实例都能访问到它。
  3. 部署代码:将你的 Scrapy-Redis 项目代码部署到每台爬虫机器上。
  4. 启动爬虫:在每台机器上运行 scrapy crawl your_redis_spider_name 命令。

总结与展望

通过本篇博客,相信你已经对 Scrapy 和 Scrapy-Redis 的执行流程有了清晰的理解。

  • Scrapy 提供了一个高效且模块化的框架,让你能够专注于数据提取和业务逻辑。
  • Scrapy-Redis 则在此基础上,通过利用 Redis 的特性,实现了分布式爬虫的强大功能,包括断点续爬、共享队列、去重等,大大提升了大规模数据抓取的效率和稳定性。
http://www.lryc.cn/news/609504.html

相关文章:

  • 分布式版本控制工具Git
  • Spring之【Bean的实例化方式】
  • 电脑忘记开机密码怎么办?【图文详解】5种方法重置/更改/取消/设置开机密码?
  • Java从入门到精通 - 算法、正则、异常
  • 深入浅出 RabbitMQ:简单队列实战指南
  • 【Linux指南】软件安装全解析:从源码到包管理器的进阶之路
  • 小杰数据结构(five day)——知人者智,自知者明。
  • WPF 按钮背景色渐变
  • 飞算 JavaAI:给需求分析装上 “智能大脑“
  • VPS云服务器Linux性能分析与瓶颈解决方案设计
  • 机器学习 决策树案例电信用户流失
  • 豆包新模型+PromptPilot深度评测:提示词工程的智能化突破
  • Chrontel 【CH7104B-BF】CH7104B HDMI to HDTV/VGA Converter
  • SJW-app-1
  • 力扣热题100——双指针
  • Android GPU测试
  • 豹女篇章-人形态技能加攻速
  • 数据离不开哈希
  • 【Linux | 网络】网络层(IP协议、NAT技术和ICMP协议)
  • 【前端:Html】--1.3.基础语法
  • 【人工智能99问】什么是Post-Training,包含哪些内容?(19/99)
  • 3.JVM,JRE和JDK的关系是什么
  • Linux 系统重置用户密码指南
  • 【09】C++实战篇——C++ 生成静态库.lib 及 C++调用lib,及实际项目中的使用技巧
  • vue3指定设置了dom元素的ref但是为null问题
  • 大模型 与 自驾 具身 3D世界模型等相关知识
  • 华为OD机考2025C卷 - 最小矩阵宽度(Java Python JS C++ C )
  • vim 组件 使用pysocket进行sock连接
  • 408数据结构排序部分知识的复盘:从原理到辨析的系统化梳理
  • 抗辐照DCDC与MCU在核环境监测设备中的集成应用