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

相关推荐
Storynone1 天前
【Day20】LeetCode:39. 组合总和,40. 组合总和II,131. 分割回文串
python·算法·leetcode
小鸡吃米…1 天前
Python—— 环境搭建
python
io_T_T1 天前
python 文件管理库 Path 解析(详细&基础)
python
渔阳节度使1 天前
SpringAI实时监控+观测性
后端·python·flask
铁手飞鹰1 天前
Visual Studio创建Cmake工程导出DLL,通过Python调用DLL
android·python·visual studio
飞Link1 天前
告别盲目找Bug:深度解析 TSTD 异常检测中的预测模型(Python 实战版)
开发语言·python·算法·bug
7yewh1 天前
jetson_yolo_deployment 02_linux_dev_skills
linux·python·嵌入式硬件·yolo·嵌入式
love530love1 天前
ComfyUI rgthree-comfy Image Comparer 节点无输出问题排查与解决
人工智能·windows·python·comfyui·rgthree-comfy·nodes 2.0·vue 节点
badhope1 天前
Docker从零开始安装配置全攻略
运维·人工智能·vscode·python·docker·容器·github
用户0332126663671 天前
使用 Python 复制 Excel 工作表
python