Scrapy五大核心组件详解 - 五脏六腑怎么协同干活?
大家好呀,我是道满PythonAI!上篇我们聊了为什么选Scrapy(异步、高并发、扩展性强),今天直接拆解它的核心5件套——看完就能搞懂为啥Scrapy能“快、稳、巧”爬数据!
📂 所属阶段:第一阶段 — 初出茅庐(框架核心篇)
🔗 相关章节:为什么选择 Scrapy? · 创建你的首个工程
目录
1分钟看全局架构
Scrapy采用事件驱动异步架构,5个核心组件各司其职,Engine作为“总指挥”串联所有环节,形成一条自动化数据流水线:
flowchart LR
A[Spider<br>解析逻辑师] -->|Requests| B[Engine<br>核心指挥家]
B -->|排队Requests| C[Scheduler<br>任务调度管家]
C -->|取优先级Requests| B
B -->|发Requests| D[Downloader<br>内容搬运工]
D -->|HTTP请求| E[目标网站]
E -->|HTTP响应| D
D -->|Responses| B
B -->|Responses| A
A -->|新Requests/Items| B
B -->|Items| F[Pipeline<br>数据加工厂]
F --> G[(数据存储)]
极简数据流向
Spider(要爬的URL/解析好的数据)→ Engine(分配/处理)→ 目标环节
Engine(核心指挥家)
Engine是Scrapy的“大脑”,不处理具体业务,但决定所有组件的“什么时候、做什么、给谁做”。
核心职责
- 事件循环驱动:用Twisted异步库接管整个流程的执行节奏
- 组件生命周期管理:启动、运行、暂停、停止爬虫
- 信号分发与处理:协调组件间的状态通知
- 数据流转监控:确保Requests/Responses/Items在组件间正确传递
常用生命周期信号
# 在中间件/爬虫中常用的信号(不需要写太多代码)
from scrapy import signals
# spider_opened: 爬虫刚启动(可以初始化数据库连接)
# spider_closed: 爬虫停止前(可以关闭连接、统计数据)
# response_received: 刚拿到HTTP响应
# item_scraped: Item经过所有Pipeline后成功生成
配置注意
# settings.py 中Engine相关的核心开关
"""
# 爬虫空闲多久后停止(0=不自动停,但生产环境建议设)
CLOSESPIDER_TIMEOUT = 3600 # 1小时后自动停
CLOSESPIDER_PAGECOUNT = 1000 # 爬够1000页自动停
CLOSESPIDER_ITEMCOUNT = 10000 # 爬够10000条数据自动停
"""
Scheduler(任务调度管家)
Scheduler是“仓库管理员+优先级经理”,专门管理待爬的Requests队列,避免重复爬取、按优先级分配任务。
核心功能
- 去重:默认用
RFPDupeFilter生成请求指纹(哈希值),判断是否爬过
- 排队:支持FIFO/LIFO/优先级队列(默认FIFO)
- 持久化:设置
JOBDIR后,中断的任务可以续爬!
配置与技巧
# settings.py 中的核心配置
"""
# 去重器(想自定义去重逻辑?改这个!)
DUPEFILTER_CLASS = 'scrapy.dupefilters.RFPDupeFilter'
# 持久化续爬目录(生成后别随便删!)
JOBDIR = 'crawls/my_spider_20260410/'
# 优先级队列(数字越大优先级越高,默认0)
# 比如可以把详情页优先级设为5,列表页设为1
SCHEDULER_PRIORITY_QUEUE = 'scrapy.pqueues.ScrapyPriorityQueue'
"""
自定义去重(简单版)
# 只需要继承默认去重器,重写生成指纹的方法就行
# 比如:忽略URL中的时间戳参数,避免重复爬同一个页面
from scrapy.dupefilters import RFPDupeFilter
from scrapy.utils.url import urljoin_rfc
from scrapy.utils.request import request_fingerprint
class IgnoreTimestampDupeFilter(RFPDupeFilter):
def request_fingerprint(self, request):
# 复制一个request,移除时间戳参数
new_request = request.replace(url=request.url.split('?')[0])
return request_fingerprint(new_request)
Downloader(内容搬运工)
Downloader是“高速快递员”,负责发送HTTP请求、接收HTTP响应,支持多线程复用连接、自动限速、反爬处理。
核心子系统
- 下载中间件(Downloader Middleware):拦截Requests/Responses,修改User-Agent、加代理、处理重定向/重试等
- 连接池:复用TCP连接,减少握手开销
- 自动限速器(AutoThrottle):根据目标网站的响应速度动态调整延迟
生产级配置
# settings.py 中的核心反爬+性能配置
"""
# 并发控制(核心!别太高,容易被封!)
CONCURRENT_REQUESTS = 16 # 总并发请求数
CONCURRENT_REQUESTS_PER_DOMAIN = 4 # 单域名并发数(建议2-8)
# 延迟控制(搭配自动限速更稳)
DOWNLOAD_DELAY = 1 # 基础延迟1秒
RANDOMIZE_DOWNLOAD_DELAY = 0.5 # 随机浮动±50%
AUTOTHROTTLE_ENABLED = True # 必开!自动调整
AUTOTHROTTLE_TARGET_CONCURRENCY = 2.0 # 目标域名并发利用率
AUTOTHROTTLE_MAX_DELAY = 10 # 最大延迟不超过10秒
# 重试控制
RETRY_TIMES = 3 # 最多重试3次
RETRY_HTTP_CODES = [500, 502, 503, 408, 429] # 只重试这些状态码
# 超时控制
DOWNLOAD_TIMEOUT = 180 # 180秒没响应就算超时
"""
Spiders(解析逻辑师)
Spiders是“唯一需要你写业务的地方”!负责定义起始URL、解析HTTP响应、生成新Requests、生成Items。
最常用的2种Spider
- Basic Spider:适合简单页面、自定义请求逻辑
- CrawlSpider:适合全站爬取,用
Rule+LinkExtractor自动提取链接
Basic Spider 最简示例
import scrapy
class DoubanTop250Spider(scrapy.Spider):
name = "douban_top250" # 必须唯一!启动爬虫用的名字
allowed_domains = ["movie.douban.com"] # 限制只爬这个域名的子页面
start_urls = ["https://movie.douban.com/top250?start=0"]
def parse(self, response):
# 解析当前页面的电影信息
for movie in response.css("ol.grid_view li"):
yield {
"title": movie.css("span.title::text").get(),
"rating": movie.css("span.rating_num::text").get(),
"quote": movie.css("span.inq::text").get(),
}
# 提取下一页链接,自动跟进
next_page = response.css("div.paginator a.next::attr(href)").get()
if next_page:
yield response.follow(next_page, callback=self.parse) # follow自动拼接相对URL
Pipeline(数据加工厂)
Pipeline是“质检+仓储流水线”,负责处理Spider生成的Items:清洗数据、验证必填项、去重(比Scheduler的URL去重更细)、存储到数据库/文件。
Pipeline的生命周期
每个Pipeline必须实现以下1-2个方法(其他可选):
open_spider(self, spider):爬虫启动时执行(比如初始化MySQL连接)
process_item(self, item, spider):必写!处理每个Item,返回Item或抛出DropItem
close_spider(self, spider):爬虫停止时执行(比如关闭连接)
配置顺序
# settings.py 中按数字从小到大依次执行(300先验证,500后存储)
ITEM_PIPELINES = {
'myproject.pipelines.ValidationPipeline': 300,
'myproject.pipelines.CleaningPipeline': 400,
'myproject.pipelines.MongoDBPipeline': 500,
}
完整协同工作流(必看!)
7步走通整个流程
- 初始化:启动爬虫 → Engine加载Spider → Scheduler初始化队列 → Downloader准备连接池
- 发起始请求:Spider生成
start_urls → Engine转发给Scheduler → Scheduler去重后入队
- 取请求:Engine从Scheduler取优先级最高的Request → 转发给Downloader
- 下载:Downloader发送HTTP请求 → 拿到响应 → 转发给Engine
- 解析:Engine把响应转发给Spider的对应
callback → Spider解析出新Requests和Items
- 循环与存储:
- 新Requests → Engine → Scheduler → 重复步骤3-5
- Items → Engine → 按顺序执行所有Pipeline → 存储到目标位置
- 停止:Scheduler队列空 → 无新Requests生成 → Engine关闭所有组件 → 结束爬虫
优化小锦囊
性能优化
- 合理设并发:总并发
16-64,单域名2-8,别太高容易被封
- 必开自动限速:
AUTOTHROTTLE_ENABLED = True
- 复用中间件逻辑:别把所有反爬代码写在Spider里,用中间件更方便复用
内存优化
- 及时丢弃无效Item:用
raise DropItem
- 限制爬取时长/页数/条数:比如
CLOSESPIDER_TIMEOUT = 3600
常见问题快答
Q1: Spider怎么传参数给Pipeline?
A: 可以用spider.settings.get()或者直接spider.custom_param(在Spider里定义属性)。
Q2: 怎么续爬中断的任务?
A: 在settings.py里设置JOBDIR = 'crawls/xxx/',启动爬虫后会自动保存状态,中断后再次启动同一个命令就能续爬!
Q3: 怎么让详情页比列表页先爬?
A: 在生成详情页Request时加priority=5(列表页默认0或1,数字越大优先级越高)。
🏷️ 标签云: Scrapy 核心组件 Engine Scheduler Downloader Spiders Pipeline 爬虫架构 数据采集