分布式爬虫去重:Python + Redis实现高效URL去重

1. 引言

在互联网数据采集(爬虫)过程中,URL去重是一个关键问题。如果不对URL进行去重,爬虫可能会重复抓取相同页面,导致资源浪费、数据冗余,甚至触发目标网站的反爬机制。

对于单机爬虫,可以使用Python内置的**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">set()</font>****<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">dict</font>**进行去重,但在分布式爬虫环境下,多个爬虫节点同时工作时,内存级的去重方式不再适用。此时,需要一个共享存储来管理已爬取的URL,而Redis凭借其高性能、低延迟和分布式支持,成为理想选择。

2. URL去重的常见方法

2.1 基于内存的去重(单机适用)

Python **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">set()</font>**
最简单的去重方式,适用于小规模数据,但无法持久化,重启后数据丢失。

visited_urls = set()
if url not in visited_urls:visited_urls.add(url)# 抓取逻辑
  • Bloom Filter(布隆过滤器)
    节省内存,但有一定误判率(可能误判未访问的URL为已访问),适用于海量URL去重。

2.2 基于数据库的去重(分布式适用)

  • Redis Set / Redis HyperLogLog
    • **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">SET</font>** 结构存储URL,精确去重(100%准确)。
    • **<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">HyperLogLog</font>** 适用于统计不重复元素数量(有一定误差,但占用内存极小)。
  • 关系型数据库(MySQL, PostgreSQL)
    通过**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">UNIQUE</font>**约束去重,但性能较低,不适合高并发爬虫。
  • 分布式键值存储(如Memcached)
    类似Redis,但功能较少,通常仅用于缓存。

3. Redis 在分布式爬虫去重中的优势

Redis 是一个高性能的内存数据库,支持多种数据结构,适用于分布式爬虫去重,主要优势包括:

  1. 高性能:数据存储在内存中,读写速度极快(10万+ QPS)。
  2. 持久化:支持RDB/AOF持久化,避免数据丢失。
  3. 分布式支持:可通过集群模式扩展,支持多爬虫节点共享数据。
  4. 丰富的数据结构**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">SET</font>**(精确去重)、**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">HyperLogLog</font>**(近似去重)、**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">Bitmap</font>**(位图去重)等。

4. Python + Redis 实现分布式URL去重

4.1 方案1:使用 Redis Set 精确去重

import redisclass RedisUrlDedupe:def __init__(self, redis_host='localhost', redis_port=6379, redis_db=0):self.redis = redis.StrictRedis(host=redis_host, port=redis_port, db=redis_db)self.key = "visited_urls"def is_visited(self, url):"""检查URL是否已访问"""return self.redis.sismember(self.key, url)def mark_visited(self, url):"""标记URL为已访问"""self.redis.sadd(self.key, url)# 示例用法
deduper = RedisUrlDedupe()
url = "https://example.com/page1"if not deduper.is_visited(url):deduper.mark_visited(url)print(f"抓取: {url}")
else:print(f"已访问: {url}")

优点

  • 100% 准确,无误差。
  • 适用于中小规模爬虫(百万级URL)。

缺点

  • 存储所有URL,内存占用较高。

4.2 方案2:使用 Redis HyperLogLog 近似去重

如果允许少量误差(~0.8%),可使用**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">HyperLogLog</font>**节省内存:

class RedisHyperLogLogDedupe:def __init__(self, redis_host='localhost', redis_port=6379, redis_db=0):self.redis = redis.StrictRedis(host=redis_host, port=redis_port, db=redis_db)self.key = "hll_visited_urls"def is_visited(self, url):"""检查URL是否可能已访问(可能有误判)"""before = self.redis.pfcount(self.key)after = self.redis.pfadd(self.key, url)return after == 0  # 如果添加后计数未变,说明可能已存在# 示例用法
hll_deduper = RedisHyperLogLogDedupe()
url = "https://example.com/page1"if not hll_deduper.is_visited(url):print(f"抓取: {url}")
else:print(f"可能已访问: {url}")

优点

  • 内存占用极低(12KB可存储数亿URL)。
  • 适用于超大规模爬虫(如全网爬取)。

缺点

  • 有少量误判(可能将未访问的URL误判为已访问)。

4.3 方案3:使用 Redis Bloom Filter(需安装RedisBloom模块)

Redis 官方提供 RedisBloom 模块,支持布隆过滤器(需额外安装):

# 需确保Redis服务器加载了RedisBloom模块
class RedisBloomFilterDedupe:def __init__(self, redis_host='localhost', redis_port=6379, redis_db=0):self.redis = redis.StrictRedis(host=redis_host, port=redis_port, db=redis_db)self.key = "bloom_visited_urls"def is_visited(self, url):"""检查URL是否可能已访问(可能有误判)"""return self.redis.execute_command("BF.EXISTS", self.key, url)def mark_visited(self, url):"""标记URL为已访问"""self.redis.execute_command("BF.ADD", self.key, url)# 示例用法
bloom_deduper = RedisBloomFilterDedupe()
url = "https://example.com/page1"if not bloom_deduper.is_visited(url):bloom_deduper.mark_visited(url)print(f"抓取: {url}")
else:print(f"可能已访问: {url}")

优点

  • 内存占用低,误判率可控。
  • 适用于海量URL去重。

缺点

  • 需要额外安装RedisBloom模块。

5. 性能优化与对比

方法准确率内存占用适用场景
Redis Set100%中小规模爬虫(<1000万URL)
Redis HyperLogLog~99.2%极低超大规模爬虫(允许少量误判)
Redis Bloom Filter可调海量URL(需额外模块)

优化建议

  1. 短URL优化:存储URL的MD5或SHA1哈希值(减少内存占用)。
  2. 分片存储:按域名或哈希分片,避免单个Key过大。
  3. TTL过期:设置过期时间,避免长期累积无用URL。

6. 结论

在分布式爬虫中,Redis 是URL去重的理想选择,支持多种数据结构:

  • 精确去重**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">Redis Set</font>**
  • 低内存消耗**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">HyperLogLog</font>**
  • 可控误判率**<font style="color:rgb(64, 64, 64);background-color:rgb(236, 236, 236);">Bloom Filter</font>**

通过合理选择方案,可以显著提升爬虫效率,避免重复抓取。本文提供的Python代码可直接集成到Scrapy或其他爬虫框架中,助力高效数据采集。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/904985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# WPF 颜色拾取器

x:Name=Color Picker 语言:C# WPF 下载:https://download.csdn.net/download/polloo2012/90780640 主界面 颜色库 关于我们 颜色拾取器是一种能够帮助用户获取颜色信息,并进行颜色选择、识别和调整的工具,以下将从其常见类型、使用场景及部分软件工具这几个维度展开介绍…

Git 使用的全流程以及SourceTree工具的使用操作和忽略文件的配置

1. 安装 Git 要使用 Git&#xff0c;首先得在你的系统上安装它。你可以按照不同操作系统的安装指南来操作&#xff1a; Windows&#xff1a;访问 Git 官方下载页面&#xff0c;下载安装程序并运行。 macOS&#xff1a;可以使用 Homebrew 来安装&#xff0c;命令为 brew inst…

《深入理解Linux网络》笔记

《深入理解Linux网络》笔记 前言参考 前言 前段时间看了《深入理解Linux网络》这本书&#xff0c;虽然有些地方有以代码充篇幅的嫌疑&#xff0c;但总体来说还是值得一看的。在这里简单记录一下笔记&#xff0c;记录下对网络新的理解。 内核是如果接受网络包的&#xff1f; 如…

数仓-可累计,半累加,不可累加指标,是什么,举例说明及解决方案

目录 1. 可累计指标定义&#xff1a;举例&#xff1a;解决方案&#xff1a; 2. 半累加指标定义&#xff1a;举例&#xff1a;解决方案&#xff1a; 3. 不可累加指标定义&#xff1a;举例&#xff1a;解决方案&#xff1a; 4. 总结对比5. 实际场景中的注意事项 这是数据仓库设计…

NestJS 的核心构建块有哪些?请简要描述它们的作用(例如,Modules, Controllers, Providers)

NestJS 核心构建块解析&#xff08;Modules、Controllers、Providers&#xff09; NestJS 是一个基于 TypeScript 的渐进式 Node.js 框架&#xff0c;核心设计借鉴了 Angular 的模块化思想。下面从实际开发角度解析它的三大核心构建块&#xff0c;并附代码示例和避坑指南。 一…

vue2 上传pdf,拖拽盖章,下载图片

效果图片&#xff1a; 不多废话上代码&#xff1a; <template><div class"pdf-stamp" onbeforecopyreturn false onselectdocument.selection.empty() ondragstartreturn false onselectstart return false ><div class"scroll-box" scro…

理性地倾听与表达:检索算法的语言学改进

论文标题 Rational Retrieval Acts: Leveraging Pragmatic Reasoning to Improve Sparse Retrieval 论文地址 https://arxiv.org/pdf/2505.03676 代码地址 https://github.com/arthur-75/Rational-Retrieval-Acts 作者背景 巴黎萨克雷大学&#xff0c;索邦大学&#xff…

MySQL及线程关于锁的面试题

目录 1.了解过 MySQL 死锁问题吗&#xff1f; 2.什么是线程死锁&#xff1f;死锁相关面试题 2.1 什么是死锁&#xff1a; 2.2 形成死锁的四个必要条件是什么&#xff1f; 2.3 如何避免线程死锁&#xff1f; 3. MySQL 怎么排查死锁问题&#xff1f; 4.Java线上死锁问题如…

【Reality Capture 】Reality Capture1.5中文版安装教程(附安装包下载)

文章目录 一、Reality Capture1.5中文版安装教程二、拷贝中文补丁三、Reality Capture1.5中文版下载地址一、Reality Capture1.5中文版安装教程 1. Reality Capture v1.4.0汉化版安装包下载并解压 2. 运行EpicInstaller-15.17.1-4a91a118786f4c2aa3c0093b23f83863.msi 3. 更改…

SVG数据可视化设计(AI)完全工作流解读|计育韬

AI 的 SVG 创作极限在哪里&#xff1f;绝不是那些初级的流程图生成和粗糙的商业模型设计。以下是由我们 JZ Creative Studio 通过 Claude 和 Deepseek 开展的专业级 SVG Data Visualization 创作&#xff0c;应广大读者强烈要求&#xff0c;专程直播讲授了一期 AI 工作流分享。…

not a genuine st device abort connection的问题

1.魔法棒里面电机Settings 2.然后在Other里面把Enabled的钩子去掉

uv简单使用

通过uv创建项目和虚拟环境 初始化项目 uv init --package my-project 初始化一个名为 my-project 的新项目&#xff0c;并生成必要的文件结构。 创建虚拟环境 uv venv .venv 激活虚拟环境 # For Windows .venv\Scripts\activate# For macOS/Linux source .venv/bin/acti…

测试左移系列-产品经理实战-实战认知1

课程&#xff1a;B站大学 记录产品经理实战项目系统性学习&#xff0c;从产品思维&#xff0c;用户画像&#xff0c;用户体验&#xff0c;增长数据驱动等不同方向理解产品&#xff0c;从0到1去理解产品从需求到落地的全过程&#xff0c;测试左移方向&#xff08;靠近需求、设计…

从需求到用例的AI路径:准确率与挑战

用工作流生成测试用例和自动化测试脚本&#xff01; 引言&#xff1a;用例的黄金起点 在软件工程中&#xff0c;“测试用例”是连接需求理解与质量保障之间的关键桥梁。一份高质量的测试用例&#xff0c;不仅是验证功能实现是否符合需求的工具&#xff0c;更是产品风险感知、用…

大语言模型中的“温度”参数到底是什么?如何正确设置?

近年来&#xff0c;市面上涌现了大量调用大模型的工具&#xff0c;如 Dify、Cherry Studio 等开源或自研平台&#xff0c;几乎都提供了 “温度”&#xff08;Temperature&#xff09; 选项。然而&#xff0c;很多人在使用时并不清楚该如何选择合适的温度值。 今天&#xff0c;…

如何删除网上下载的资源后面的文字

这是我在爱给网上下载的音效资源&#xff0c;但是发现资源后面跟了一大段无关紧要的文本&#xff0c;但是修改资源名称后还是有。解决办法是打开属性然后删掉资源的标签即可。

hot100-子串-JS

一、560.和为k的子串 560. 和为 K 的子数组 提示 给你一个整数数组 nums 和一个整数 k &#xff0c;请你统计并返回 该数组中和为 k 的子数组的个数 。 子数组是数组中元素的连续非空序列。 示例 1&#xff1a; 输入&#xff1a;nums [1,1,1], k 2 输出&#xff1a;2示例 2…

01背包类问题

文章目录 [模版]01背包1. 第一问: 背包不一定能装满(1) 状态表示(2) 状态转移方程(3) 初始化(4) 填表顺序(5) 返回值 2. 第二问: 背包恰好装满3. 空间优化 416.分割等和子集1. 状态表示2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 [494. 目标和](https://leetcode.cn/proble…

解锁 DevOps 新境界 :使用 Flux 进行 GitOps 现场演示 – 自动化您的 Kubernetes 部署

前言 GitOps 是实现持续部署的云原生方式。它的名字来源于标准且占主导地位的版本控制系统 Git。GitOps 的 Git 在某种程度上类似于 Kubernetes 的 etcd&#xff0c;但更进一步&#xff0c;因为 etcd 本身不保存版本历史记录。毋庸置疑&#xff0c;任何源代码管理服务&#xf…

将Docker镜像变为可执行文件?体验docker2exe带来的便捷!

在现代软件开发中,容器化技术极大地改变了应用程序部署和管理的方式。Docker,作为领先的容器化平台,已经成为开发者不可或缺的工具。然而,对于不熟悉Docker的用户来说,接触和运行Docker镜像可能会是一个复杂的过程。为了解决这一问题,docker2exe项目应运而生。它提供了一…