欢迎光临
我们一直在努力

Scrapy 是一个用 Python 编写的高性能、可扩展的开源网络爬虫框架

Scrapy 是一个用 Python 编写的高性能、可扩展的开源网络爬虫框架,原生设计为单机架构,不直接支持分布式爬虫。但通过结合外部组件(如 Redis、RabbitMQ、Kafka 等),可构建分布式爬虫系统,常见方案包括:

✅ Scrapy-Redis(最经典)

  • 基于 Redis 实现请求队列(SpiderQueue/PriorityQueue)、去重集合(DupeFilter)和指纹存储;
  • 多个 Scrapy 爬虫实例共享同一 Redis 数据库,实现任务分发与状态同步;
  • 需重写 Scheduler、DupeFilter 和 ItemPipeline,继承 scrapy_redis.spiders.RedisSpider。

✅ Scrapy + Redis + 自定义调度器

  • 利用 Redis 的 LPUSH/BRPOP 实现任务队列;
  • 使用 scrapy-redis 提供的中间件或自行开发 RedisScheduler;
  • 支持动态添加起始 URL(通过 lpush myspider:start_urls http://xxx)。

⚠️ 注意事项:

  • Scrapy 本身无内置分布式协调机制(如节点发现、故障转移、负载均衡),需依赖外部服务;
  • 去重需统一使用 Redis 的 set 或 bloom filter(如 scrapy-redis-bloom)避免重复抓取;
  • Item 存储建议统一写入数据库(MySQL/PostgreSQL)或消息队列(Kafka),避免多实例写冲突;
  • 日志、监控、限速策略需集中管理(如 Prometheus + Grafana + ELK)。

📌 示例(Scrapy-Redis 快速启动):

pip install scrapy-redis

在 settings.py 中配置:

SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
REDIS_URL = 'redis://localhost:6379'

继承 RedisSpider:

import scrapy
from scrapy_redis.spiders import RedisSpider

class MySpider(RedisSpider):
name = 'myspider'
redis_key = 'myspider:start_urls'

def parse(self, response):
yield {'url': response.url, 'title': response.css('title::text').get()}

启动多个实例后,向 Redis 推送 URL 即可触发分布式抓取。

Scrapy-Redis 的去重机制核心是 将 Scrapy 原生的本地 RFPDupeFilter(基于 scrapy.utils.request.request_fingerprint)迁移到 Redis 中持久化存储,从而实现多爬虫实例共享同一去重集合。其本质不是重新设计指纹算法,而是复用 Scrapy 的指纹逻辑 + 分布式存储层。

✅ 指纹生成逻辑(与本地完全一致)
Scrapy-Redis 使用 scrapy.utils.request.request_fingerprint() 生成请求指纹(fingerprint),该函数默认行为为:

  • 对请求的 method、url、body、headers(仅含标准化后的关键头,如 User-Agent、Cookie 等,取决于 DUPEFILTER_DEBUG 和 HTTPCACHE_IGNORE_HEADERS 配置)、cookies 等字段进行规范化(如 URL 去参数顺序、body 排序、headers 小写归一化);
  • 序列化后经 SHA1 哈希,生成长度为 40 的十六进制字符串(如 'a1b2c3…');
  • ✅ 该指纹算法与 Scrapy 默认 RFPDupeFilter 完全相同,保证语义一致性——同一请求在单机或分布式环境下生成的指纹绝对一致。

✅ 去重存储与判断流程(分布式关键差异)

环节本地 RFPDupeFilterScrapy-Redis RFPDupeFilter
存储介质 Python set()(内存,进程级) Redis SET 或 Bloom Filter(如 scrapy-redis-bloom)
去重范围 单个爬虫进程内 所有连接同一 Redis 的爬虫实例全局共享
判断方式 fingerprint in self.fingerprints SISMEMBER dupefilter:myspider <fingerprint>(原子操作)
持久化 进程退出即丢失 Redis 持久化(RDB/AOF)可长期保留去重记录
扩展性 无法跨实例共享 支持无限水平扩展爬虫节点

🔧 可选增强:Bloom Filter 替代 SET
为节省内存(尤其海量 URL 场景),可启用 scrapy-redis-bloom:

  • 使用 Redis 的 bf.add/bf.exists(需 RedisBloom 模块);
  • 以极小概率误判(false positive,≈0.1% 可配置),但不产生 false negative(不会漏判重复);
  • 内存占用仅为 SET 的 1/8~1/10,适合亿级 URL 去重。

⚠️ 注意事项:

  • 若自定义 Request 并覆盖 __hash__ 或 __eq__,需确保 request_fingerprint() 仍能正确反映语义唯一性;
  • DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" 是默认配置,无需修改即可生效;
  • Redis 连接异常时,RFPDupeFilter 默认会抛出异常(可捕获并降级为本地去重,但需自行实现容错逻辑)。
    在这里插入图片描述
赞(0)
未经允许不得转载:171主机测评 » Scrapy 是一个用 Python 编写的高性能、可扩展的开源网络爬虫框架
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址