Redis 作为爬虫去重与任务队列实战

在分布式爬虫开发中,去重任务调度是两大核心痛点。单机内存去重容量有限、无法跨节点共享;任务队列不统一则会导致重复抓取、效率低下。Redis 凭借高性能、丰富数据结构与分布式友好特性,成为爬虫去重与任务队列的首选中间件。本文从原理到代码,带你实现工业级 Redis 爬虫去重 + 任务队列实战。


一、为什么选 Redis 做爬虫中间件

  • 高性能:内存读写,QPS 可达 10 万 +,秒级响应 URL 查重与入队出队
  • 分布式:多爬虫节点共享同一套队列与去重库,天然支持横向扩展
  • 数据结构适配:List 做队列、Set 做精确去重、Bitmap/BloomFilter 做海量去重
  • 持久化:RDB+AOF 保证断电不丢任务、不丢去重记录
  • 轻量易用:无复杂依赖,Python 通过 redis-py 即可快速接入

二、核心数据结构选型

1. 任务队列:List(双向链表)

  • 命令:LPUSH 入队、RPOP 出队、BLPOP 阻塞取任务
  • 优势:FIFO 严格有序、支持阻塞等待、原子操作防并发争抢
  • 适用:待爬 URL 队列、失败重试队列

2. 精确去重:Set(集合)

  • 命令:SADD 添加指纹、SISMEMBER 判断是否存在
  • 优势:100% 精确、自动去重、O (1) 查询
  • 适用:中小规模 URL 去重、重要业务必选

3. 海量去重:布隆过滤器(RedisBloom)

  • 优势:1 亿 URL 仅占~120MB 内存,查询极快
  • 适用:超大规模爬取、允许极低误判率

4. 统计去重量:HyperLogLog

  • 优势:极小内存统计唯一值数量
  • 适用:只统计不查重、监控总去重规模

三、环境准备

  1. 安装 Redis
  2. 安装 Python 依赖

bash

运行

复制代码
pip install redis requests hashlib
  1. 连接测试

python

运行

复制代码
import redis
r = redis.Redis(
    host='localhost',
    port=6379,
    db=0,
    decode_responses=True
)
print(r.ping())

四、实战一:Redis URL 精确去重(生产级)

去重流程

  1. 对 URL 做 SHA1 哈希生成指纹(缩短长度、统一格式)
  2. SISMEMBER 判断指纹是否在去重集合
  3. 不存在则 SADD 加入集合,允许爬取
  4. 存在则直接跳过

完整代码

python

运行

复制代码
import hashlib
import redis

class RedisDupeFilter:
    def __init__(self, redis_host='localhost', redis_port=6379, redis_db=0):
        self.redis = redis.Redis(host=redis_host, port=redis_port, db=redis_db, decode_responses=True)
        self.dupe_key = 'crawler:dupe:set'

    def url_to_fingerprint(self, url):
        # URL生成固定长度指纹
        sha1 = hashlib.sha1()
        sha1.update(url.encode('utf-8'))
        return sha1.hexdigest()

    def is_duplicated(self, url):
        # 检查是否重复
        fp = self.url_to_fingerprint(url)
        return self.redis.sismember(self.dupe_key, fp)

    def add(self, url):
        # 添加到去重库
        fp = self.url_to_fingerprint(url)
        self.redis.sadd(self.dupe_key, fp)

# 测试
if __name__ == '__main__':
    df = RedisDupeFilter()
    url = 'https://www.baidu.com'
    if df.is_duplicated(url):
        print('已爬取,跳过:', url)
    else:
        df.add(url)
        print('开始爬取:', url)

五、实战二:Redis 任务队列(生产者 - 消费者模型)

队列流程

  • 生产者:解析页面→提取链接→去重校验→LPUSH 推入队列
  • 消费者:BLPOP 阻塞取任务→执行爬取→新链接入队→循环

完整代码

python

运行

复制代码
import time
import requests
from bs4 import BeautifulSoup

# 队列配置
QUEUE_KEY = 'crawler:task:queue'

# 生产者:加入任务
def producer(url):
    if df.is_duplicated(url):
        return
    df.add(url)
    r.lpush(QUEUE_KEY, url)
    print(f'入队: {url}')

# 消费者:取任务并爬取
def consumer():
    while True:
        # 阻塞取任务,超时3秒
        task = r.blpop(QUEUE_KEY, timeout=3)
        if not task:
            print('队列为空,等待任务...')
            continue
        url = task[1]
        try:
            print(f'开始爬取: {url}')
            resp = requests.get(url, timeout=5)
            soup = BeautifulSoup(resp.text, 'html.parser')
            # 模拟提取链接
            for a in soup.find_all('a', href=True):
                link = a['href']
                if link.startswith('http'):
                    producer(link)
            print(f'爬取完成: {url}')
        except Exception as e:
            print(f'爬取失败: {url}, 错误: {e}')
            # 失败重新入队
            r.lpush(QUEUE_KEY, url)
        time.sleep(1)

if __name__ == '__main__':
    df = RedisDupeFilter()
    # 启动入口
    producer('https://www.baidu.com')
    # 启动消费者
    consumer()

六、分布式扩展:多节点协同

  1. 所有节点连接同一台 Redis
  2. 共用crawler:dupe:set去重库
  3. 共用crawler:task:queue任务队列
  4. 多节点同时运行 consumer,自动负载均衡
  5. 无重复、无遗漏、水平扩展

七、生产环境优化建议

  1. 指纹优化:对 URL 排序参数、去噪后再哈希
  2. 队列优化:使用 BLPOP 替代 RPOP,避免空轮询
  3. 去重优化:千万级 URL 改用布隆过滤器
  4. 持久化:开启 AOF,每秒刷盘
  5. 过期清理:给历史去重数据设置过期时间,避免内存膨胀
  6. 监控:

bash

运行

复制代码
redis-cli scard crawler:dupe:set   # 查看去重总量
redis-cli llen crawler:task:queue # 查看待爬任务数

八、总结

Redis 用List 做任务队列Set 做精确去重布隆过滤器做海量去重,是分布式爬虫的标准方案。本文代码可直接部署,支持单机 / 分布式切换,解决重复爬取、任务丢失、并发争抢三大问题。

相关推荐
郝学胜-神的一滴1 小时前
FastAPI:Python 高性能 Web 框架的优雅之选
开发语言·前端·数据结构·python·算法·fastapi
IP搭子来一个2 小时前
爬虫使用代理IP全解析:原理、类型与实战指南
爬虫·网络协议·tcp/ip
柒.梧.2 小时前
Java位运算详解:原理、用法及实战场景(面试重点)
开发语言·数据库·python
Scott.W2 小时前
跟我学Easyi3C Tower Adapter Console(9)
人工智能·python·嵌入式硬件·i3c
多恩Stone2 小时前
【3D-AICG 系列-14】Trellis 2 的 Texturing Pipeline 保留单层薄壳,而 Textured GLB 会变成双层
人工智能·python·算法·3d·aigc
刘恒1234567892 小时前
Windows 电脑文件夹手动分类指南
java·windows·python·电脑·php
测试渣2 小时前
持续集成中的自动化测试框架优化实战指南
python·ci/cd·单元测试·自动化·pytest
dzl843942 小时前
mac 安装python
开发语言·python·macos
清水白石0082 小时前
观察者模式全解析:用 Python 构建优雅的事件系统,让组件彻底解耦
java·python·观察者模式