scrapy-redis 中 RedisSpider 的正确使用方式--第三遍学习scrapy-redis的心得体会
scrapy-redis 的核心使用方式是: 起始 URL 不是爬虫自己生成的,而是外部动态投递进来的。 父类 这是一个持续阻塞监听 Redis 的循环,保证爬虫进程一直活着。 如果你重写了 后果: 注意: scrapy-redis 运行时,Redis 里至少存在以下三个 Key: 三个 Key 的职责分工:scrapy-redis 中 RedisSpider 的正确使用方式
核心结论: 继承 RedisSpider 后,不能重写
start_requests(),要重写 make_requests_from_url()。scrapy-redis 的使用场景
外部脚本持续发现新 URL → push 到 Redis Key
↓
爬虫从 Redis 里取 URL 去爬(多台机器同时消费)两种爬虫的本质区别
常规 Scrapy scrapy-redis 任务来源 代码里写死 外部动态 push 到 Redis 任务数量 明确知道 不确定,随时可能有新任务 工作模式 批处理,像跑脚本,有头有尾 常驻服务,像 worker 进程,随时待命 爬完之后 进程退出 继续等待新任务 为什么不能重写 start_requests()?
RedisSpider 已经重写了 start_requests(),内部逻辑大致如下:# 父类内部简化逻辑
def start_requests(self):
while True:
urls = self.next_requests() # 从 Redis 里取 URL
if urls:
yield from urls
else:
time.sleep(self.waiting_time) # 没数据就等待,继续监听start_requests():# ❌ 错误做法
def start_requests(self):
yield scrapy.Request("https://example.com/page1")
yield scrapy.Request("https://example.com/page2")正确做法:重写 make_requests_from_url()
完整数据流
外部脚本 lpush URL 到 Redis Key(如 my_spider:start_urls)
↓
父类 start_requests() 持续监听
调用 next_requests() 用 rpop 从列表取出 URL
↓
把 URL 传入 make_requests_from_url(url) ← 你重写这里,负责构造请求
↓
打包成 Request 对象(可定制 headers、callback、meta 等)
↓
Request 对象交给 Redis Scheduler
↓
dont_filter=False → 走指纹去重(dupefilter),指纹写入 Redis Set
↓
去重通过 → 放入 Redis 队列等待下载
↓
下载 → parse() → 提取新 URL → 继续入队
↓
队列空了也不退出,继续监听 Redis Key 等待新任务make_requests_from_url() 只负责构造请求,取 URL 的动作由父类的 next_requests() 完成,两者职责不同。make_requests_from_url() 是父类监听逻辑内部的钩子,重写它只是定制"拿到 URL 后怎么构造请求",不破坏整个监听机制。# ✅ 正确做法
from scrapy_redis.spiders import RedisSpider
import scrapy
class MySpider(RedisSpider):
name = "my_spider"
redis_key = "my_spider:start_urls" # 监听的 Redis Key
def make_requests_from_url(self, url):
return scrapy.Request(
url,
headers={"User-Agent": "Mozilla/5.0"},
callback=self.parse,
dont_filter=False # 开启去重
)
def parse(self, response):
...监听的工作流程
Redis Key: my_spider:start_urls
[url1, url2, url3] ← 初始有3条
爬虫A 取走 url1
爬虫B 取走 url2
爬虫C 取走 url3
队列空了... 父类继续等待,进程不退出
10分钟后,外部脚本又 push 了 url4、url5
爬虫继续取任务,继续爬Redis 中的三个核心 Key
Key 数据结构 作用 写入时机 读取时机 my_spider:start_urlsList 存储外部投递的起始 URL 外部脚本 lpush爬虫 rpop 取任务my_spider:dupefilterSet 存储请求指纹,用于去重 每次有新请求时写入指纹 判断请求是否已爬过 my_spider:requestsZSet 存储序列化后的 Request 对象 去重通过后入队 Scheduler 取出交给下载器 外部 lpush → start_urls(List)
↓
rpop 取出 URL,构造 Request
↓
写指纹 → dupefilter(Set)判断是否重复
↓
去重通过 → requests(ZSet)等待调度
↓
Scheduler 取出 → 下载器总结
不清楚有多少 URL 要爬,也不清楚什么时候新的 URL 会进来,所以要一直监听。
常规爬虫明确知道有多少 URL,爬完就结束,不需要监听。start_requests() → 能跑,但丢失了"外部投递任务 + 持续监听 + 多机分工"三个核心能力make_requests_from_url() → 在保留完整机制的前提下,定制请求构造逻辑