世界杯红牌 / 2026-03-03 05:44:47
如果你对网络数据抓取充满好奇,想从海量信息中提取有价值的内容,那么 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 的执行流程就变得清晰起来:
启动爬虫 :当你运行 scrapy crawl your_spider_name 命令时,Scrapy 引擎会启动。
生成初始请求 :引擎会向你定义的 Spider 发送一个信号,告知其开始爬取。Spider 会生成初始的 Request 对象(通常是爬取入口 URL),并将其发送给引擎。
请求入队 :引擎接收到 Request 后,会将其转发给 Scheduler。Scheduler 将请求添加到队列中,并进行去重。
请求出队,发送下载 :引擎从 Scheduler 请求下一个可用的 Request。Scheduler 将 Request 返回给引擎。引擎再将 Request 转发给 Downloader Middlewares 进行预处理(比如添加代理)。
下载页面 :经过 Downloader Middlewares 处理的 Request 会被发送给 Downloader。Downloader 向目标网站发送 HTTP/HTTPS 请求,获取网页内容。
响应处理 :Downloader 接收到网站响应后,会将其封装成 Response 对象,并先经过 Downloader Middlewares 进行后处理。
响应解析 :经过 Downloader Middlewares 处理的 Response 对象被发送回引擎。引擎再将其转发给 Spider Middlewares 进行预处理,最后交给 Spider 进行解析。
数据提取与新请求生成 :Spider 接收到 Response 后,会根据你编写的解析规则(通常使用 XPath 或 CSS 选择器)提取所需数据,并封装成 Item 对象。同时,它可能会从当前页面中提取新的链接,并生成新的 Request 对象。
数据入管道,新请求入队 :Spider 将 Item 和新的 Request 都发送给引擎。引擎将 Item 转发给 Item Pipelines 进行后续处理(清洗、存储等)。新的 Request 则再次发送给 Scheduler,重复步骤 3-8。
爬虫结束 :当 Scheduler 中没有待处理的 Request,并且所有 Item Pipelines 都处理完毕时,Scrapy 引擎会停止,爬虫任务完成。
动手实践:一个简单的 Scrapy 爬虫
为了让你更好地理解,我们来创建一个简单的 Scrapy 爬虫,抓取某个网站的标题和链接。
安装 Scrapy:
bash
复制代码
pip install scrapy
创建 Scrapy 项目:
bash
复制代码
scrapy startproject myproject
cd myproject
创建 Spider:
bash
复制代码
scrapy genspider example example.com
这会在 myproject/myproject/spiders/ 目录下生成 example.py 文件。
编辑 example.py:
python
复制代码
import scrapy
class ExampleSpider(scrapy.Spider):
name = "example"
allowed_domains = ["example.com"] # 限制爬取范围
start_urls = ["http://example.com"] # 初始请求的URL
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:
# yield response.follow(link, callback=self.parse)
运行爬虫:
bash
复制代码
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 的 Scheduler 和 DupeFilter(去重过滤器)替换掉,转而使用 Redis 来存储和管理请求队列以及去重指纹。
当使用 Scrapy-Redis 时,Scrapy 的执行流程会发生如下变化:
启动爬虫(Scrapy-Redis 版):当你运行 Scrapy-Redis 爬虫时,它会连接到 Redis 数据库。
初始请求入 Redis :Spider 生成的初始 Request 对象不再直接发送给 Scrapy 内置的 Scheduler,而是被发送到 Redis 队列中。
请求从 Redis 出队 :Scrapy-Redis 的 Scheduler 会从 Redis 队列中获取待爬取的 Request。
去重在 Redis :在将 Request 放入队列前或从队列取出后,Scrapy-Redis 的 DupeFilter 会检查 Redis 中是否已经存在该请求的指纹,从而实现去重。
后续流程不变 :一旦 Request 从 Redis 队列中取出并经过去重,后续的下载、响应处理、数据提取等流程与单机 Scrapy 基本一致。
新请求入 Redis :Spider 解析页面后生成的新 Request 也同样发送到 Redis 队列中。
动手实践:构建一个 Scrapy-Redis 分布式爬虫
接下来,我们来改造上面的 Scrapy 爬虫,让它具备分布式能力。
安装 Scrapy-Redis 和 Redis:
bash
复制代码
pip install scrapy-redis redis
你还需要在本地或服务器上安装并运行 Redis 服务。具体安装方法请参考 Redis 官方文档。
修改 settings.py 文件 :
在你的 Scrapy 项目的 settings.py 文件中,添加或修改以下配置:
python
复制代码
# 启用 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
修改 example.py 文件 :
让你的 Spider 继承 scrapy_redis.spiders.RedisSpider。
注意: 继承 RedisSpider 后,你的 start_urls 不再生效,你需要通过 Redis 来提交初始 URL。
python
复制代码
import scrapy
from scrapy_redis.spiders import RedisSpider
class ExampleSpider(RedisSpider): # 继承 RedisSpider
name = "example_redis" # 更改爬虫名称,避免与之前的冲突
allowed_domains = ["example.com"]
# start_urls 不再需要,初始 URL 将从 Redis 中获取
# start_urls = ["http://example.com"]
# Redis 键名,用于存储待爬取的 URL
redis_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 生成新的请求,这些请求会自动发送到 Redis
yield response.follow(link, callback=self.parse)
启动 Redis :
确保你的 Redis 服务正在运行。
提交初始 URL 到 Redis :
在运行爬虫之前,你需要手动将初始 URL 提交到 Redis 中。你可以使用 Redis 客户端工具(如 redis-cli)或者 Python 代码来完成。
使用 redis-cli:
bash
复制代码
redis-cli LPUSH example_redis:start_urls http://example.com
这里的 example_redis:start_urls 就是你在 Spider 中定义的 redis_key。LPUSH 命令将 URL 添加到 Redis 列表的左侧。
运行分布式爬虫:
bash
复制代码
scrapy crawl example_redis
现在,你的爬虫实例会从 Redis 中获取 URL 进行爬取。你可以启动多个终端,运行相同的命令,它们会共享同一个 Redis 队列,实现分布式爬取。
分布式部署的关键步骤
准备多台机器:你需要多台服务器或虚拟机来部署你的爬虫实例。
安装 Redis:在一台独立的服务器上部署 Redis 服务,确保所有爬虫实例都能访问到它。
部署代码:将你的 Scrapy-Redis 项目代码部署到每台爬虫机器上。
启动爬虫 :在每台机器上运行 scrapy crawl your_redis_spider_name 命令。
总结与展望
通过本篇博客,相信你已经对 Scrapy 和 Scrapy-Redis 的执行流程有了清晰的理解。
Scrapy 提供了一个高效且模块化的框架,让你能够专注于数据提取和业务逻辑。
Scrapy-Redis 则在此基础上,通过利用 Redis 的特性,实现了分布式爬虫的强大功能,包括断点续爬、共享队列、去重等,大大提升了大规模数据抓取的效率和稳定性。
晋江文学城「舞蹈教父」馬雷蒙之女馬靚辳完整拼湊父親生前風光 遺傳音樂 DNA 入行選擇靠自己