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

Scrapy 工作流程深度解析:引擎驱动的完美协作

一、Scrapy 核心组件全景图

引擎 Engine
调度器 Scheduler
下载器 Downloader
爬虫 Spider
管道 Pipeline

Scrapy 是一个引擎驱动的框架,所有组件都通过引擎进行通信,形成闭环的数据流系统。下面我们将详细解析每个步骤。

二、Scrapy 完整工作流程(引擎为核心)

SpiderEngineSchedulerDownloaderPipeline1. 初始化请求yield Request(url)添加请求到队列获取下一个请求返回请求对象发送请求返回Response传递Responseyield Item传递Item处理完成yield Request(new_url)添加新请求alt[解析出数据][解析出新URL]loop[循环处理]SpiderEngineSchedulerDownloaderPipeline

详细步骤解析:

  1. 爬虫发起初始请求

    class BookSpider(scrapy.Spider):name = 'book_spider'start_urls = ['http://books.com/category1']def parse(self, response):# 解析逻辑...
    
    • 爬虫定义起始URL
    • 引擎自动创建初始Request对象
  2. 引擎 → 调度器

    • 引擎接收Request
    • 将Request放入调度器的队列中
    • 调度器实现去重(相同URL只存一份)
  3. 引擎 ← 调度器

    • 引擎向调度器请求下一个要处理的Request
    • 调度器返回优先级最高的Request
  4. 引擎 → 下载器

    # 中间件处理流程
    def process_request(self, request, spider):# 添加代理/UA等request.headers['User-Agent'] = random.choice(USER_AGENTS)return request
    
    • 引擎发送Request给下载器
    • 经过下载中间件(可修改请求)
  5. 下载器 → 引擎

    • 下载器获取网页内容
    • 封装成Response对象
    • 通过引擎返回给爬虫
  6. 引擎 → 爬虫

    def parse(self, response):# 解析数据yield {'title': response.css('h1::text').get(),'price': response.css('.price::text').get()[1:]}# 提取新链接for next_page in response.css('a.next-page'):yield response.follow(next_page, self.parse)
    
    • 引擎将Response传递给爬虫
    • 爬虫解析响应内容
  7. 爬虫处理结果 → 引擎

    • 情况1:生成数据Item → 发送给管道
    • 情况2:生成新Request → 发送给调度器
  8. 引擎 → 管道

    class MongoDBPipeline:def process_item(self, item, spider):self.collection.insert_one(dict(item))return item
    
    • 引擎将Item传递给管道
    • 管道进行数据清洗、存储等操作
    • 多个管道按优先级顺序处理
  9. 循环继续

    • 引擎继续向调度器请求下一个Request
    • 直到调度器队列为空

三、引擎的核心作用详解

引擎作为中央控制器,负责:

  1. 组件协调

    • 控制所有组件间的数据流动
    • 决定请求处理的优先级顺序
  2. 事件驱动

    # 事件触发示例
    engine.signals.item_scraped.connect(item_scraped_handler)
    engine.signals.request_scheduled.connect(request_scheduled_handler)
    
  3. 流量控制

    • 通过设置控制并发数
    # settings.py
    CONCURRENT_REQUESTS = 16  # 最大并发请求数
    DOWNLOAD_DELAY = 0.5       # 请求延迟
    
  4. 错误处理

    • 捕获组件异常
    • 重试失败请求
    RETRY_TIMES = 2
    RETRY_HTTP_CODES = [500, 502, 503]
    

四、开发者关注点:爬虫与管道

爬虫开发重点

import scrapyclass NewsSpider(scrapy.Spider):name = 'news'def start_requests(self):# 自定义初始请求yield scrapy.Request('http://news.com/latest', callback=self.parse_headlines,meta={'page': 1})def parse_headlines(self, response):# 解析新闻标题for article in response.css('div.article'):yield {'title': article.css('h2::text').get(),'url': article.css('a::attr(href)').get()}# 分页处理next_page = response.css('a.next::attr(href)').get()if next_page:yield response.follow(next_page, self.parse_headlines, meta={'page': response.meta['page'] + 1})

管道开发重点

from itemadapter import ItemAdapterclass ValidationPipeline:"""数据验证管道"""def process_item(self, item, spider):adapter = ItemAdapter(item)if not adapter.get('title'):raise DropItem("缺少标题字段")if len(adapter['title']) > 200:adapter['title'] = adapter['title'][:200] + '...'return itemclass CSVExportPipeline:"""CSV导出管道"""def open_spider(self, spider):self.file = open('output.csv', 'w', encoding='utf-8')self.writer = csv.DictWriter(self.file, fieldnames=['title', 'url'])self.writer.writeheader()def close_spider(self, spider):self.file.close()def process_item(self, item, spider):self.writer.writerow(item)return item

五、实际工作流程示例:图书抓取案例

起始URL
添加请求
返回请求
发送请求
获取网页
返回响应
解析数据
数据Item
新URL
Spider
引擎
调度器
下载器
管道
  1. 爬虫定义起始URL:http://books.com/fiction
  2. 引擎将请求加入调度器队列
  3. 调度器返回请求给引擎
  4. 引擎发送请求给下载器
  5. 下载器获取HTML返回给引擎
  6. 引擎将响应传递给爬虫
  7. 爬虫解析出:
    • 10本图书数据(发送到管道)
    • 下一页链接(发送到调度器)
  8. 管道处理图书数据(存储到数据库)

六、常见误区澄清

  1. 误区:爬虫直接与下载器通信
    正确:所有通信必须通过引擎

  2. 误区:调度器只做简单排队
    正确:调度器实现复杂功能:

    • 请求去重
    • 优先级管理
    • 并发控制
  3. 误区:管道只用于数据存储
    正确:管道可执行多种操作:

    • 数据清洗
    • 去重处理
    • 格式转换
    • 数据验证

七、高级工作流程:中间件介入

请求
请求
响应
响应
引擎
下载中间件
下载器

中间件的作用点:

  1. 请求发出前:修改请求头、设置代理

    class ProxyMiddleware:def process_request(self, request, spider):request.meta['proxy'] = 'http://proxy.com:8080'
    
  2. 响应返回后:处理异常、修改响应内容

    class RetryMiddleware:def process_response(self, request, response, spider):if response.status == 503:new_request = request.copy()return new_request  # 自动重试return response
    
  3. 数据处理时:爬虫中间件可修改Item/Request

    class ItemProcessorMiddleware:def process_spider_output(self, response, result, spider):for item in result:if isinstance(item, dict):item['source'] = spider.nameyield item
    

八、最佳实践建议

  1. 保持爬虫简洁:仅关注解析逻辑

  2. 管道职责分离:每个管道只做一件事

  3. 善用中间件:处理通用逻辑

  4. 监控引擎事件:了解系统状态

    from scrapy import signalsclass StatsExtension:def __init__(self, stats):self.stats = stats@classmethoddef from_crawler(cls, crawler):ext = cls(crawler.stats)crawler.signals.connect(ext.request_scheduled, signal=signals.request_scheduled)return ext
    
  5. 合理配置设置

    # settings.py
    CONCURRENT_REQUESTS = 32  # 根据网络条件调整
    DOWNLOAD_TIMEOUT = 30     # 超时设置
    RETRY_TIMES = 2           # 失败重试
    

九、总结:Scrapy 工作流程精髓

  1. 引擎中心化:所有组件通过引擎通信
  2. 数据驱动:Request/Item 在组件间流动
  3. 闭环处理:从请求到存储的完整生命周期
  4. 可扩展架构:通过中间件灵活扩展功能

理解 Scrapy 的工作流程,关键在于把握引擎的核心调度作用组件间的数据流向。这种设计使得 Scrapy 能够高效处理大规模数据采集任务,同时保持代码的模块化和可维护性。

http://www.lryc.cn/news/609795.html

相关文章:

  • 从医学视角深度解析微软医学 Agent 服务 MAI-DxO
  • STM32入门之SPI协议
  • Hexo - 免费搭建个人博客07 - 添加右上角的“目录”
  • (2023ICML)BLIP-2:使用冻结图像编码器和大语言模型引导语言-图像预训练
  • 数据分页异步后台导出excel
  • VBA-Excel图片下载到本地文件夹
  • 基于知识图谱增强的RAG系统阅读笔记(一)提升大语言模型的准确性
  • 从exec到Shell:深度解析Linux进程等待,程序替换与自主Shell实现
  • Assistant API——构建基于大语言模型的智能体应用
  • 在 C++ 中实现类似 Vue 3 的 Pinia 状态管理库
  • 反转字符串中的元音字母:Swift 双指针一步到位
  • 数据在内存中的存储深度解析
  • 【基础完全搜索】USACO Bronze 2019 January - 猜动物Guess the Animal
  • [找出字符串中第一个匹配项的下标]
  • OCR 精准识别验讫章:让登记与校验更智能
  • 嵌入式 - 数据结构:查找至双向链表
  • 用户管理——配置文件和命令
  • 【数据库】使用Sql Server创建索引优化查询速度,一般2万多数据后,通过非索引时间字段排序查询出现超时情况
  • Linux-Shell脚本基础用法
  • 【VSCode】 使用 SFTP 插件实现多服务器同步
  • 随机森林知识点整理:从原理到实战
  • 区块链基础之Merkle树
  • 数据结构——单向链表
  • CMakeLists.txt学习
  • 《JavaScript高级程序设计》读书笔记 35 - 代理捕获器、反射方法以及代理模式
  • React 19 + Next.js 15 中实现混合布局
  • React配置proxy跨域
  • ref和reactive的区别
  • 通过 Flink 和 CDC 从 Oracle 数据库获取增量数据,并将这些增量数据同步到 MySQL 数据库中
  • [GESP202306 四级] 2023年6月GESP C++四级上机题超详细题解,附带讲解视频!