Scrapy 分布式爬虫基于阿里云 Redis 集群实战:反向海淘 Taocarts 商品采集日 10 万数据踩坑全复盘

简介: Taocarts团队为解决单机Scrapy爬虫吞吐低、易丢任务、OOM、难扩容等痛点,基于阿里云Redis集群重构分布式架构:多ECS协同抓取、断点续爬、全局去重、合规限流(15req/min/IP),集成RDS+OSS+MaxCompute,日采达10.6万条,任务丢失率降至0.03%,成本降38%。

一、业务场景与原生单机爬虫痛点

我所在团队负责 Taocarts 反向海淘代购系统商品采集模块,业务需求是每日合规采集 1688、淘宝零售商品基础数据,同步至 Bidfins 跨境前端展示,初期使用单机 Scrapy 爬虫上线后暴露出大量不可控线上问题。

单机架构存在四大致命短板:第一,单进程抓取上限仅 8000 条 / 天,无法支撑大促 10 万 + 日采集需求;第二,任务无持久化,服务器重启、进程崩溃后全部待爬 URL 丢失,只能全量重爬,浪费接口调用成本;第三,去重基于内存 Set,单机内存超过 16G 频繁 OOM,大量重复请求触发平台风控 IP 封禁;第四,无法横向扩容,业务高峰期只能临时换高配 ECS,资源利用率不足 20%,云成本极高。

初期尝试自建单机 Redis 做任务存储,但无集群主从同步、无持久化策略,Redis 宕机后采集任务全部丢失,多次造成商品价格、库存同步滞后,引发前端超卖投诉。经过两周重构,基于阿里云 Redis 集群版搭建分布式爬虫架构,实现多 ECS 节点协同抓取、任务断点续爬、分布式全局 URL 去重,稳定支撑日 10 万商品采集,下文完整拆解架构、可运行代码、线上踩坑与阿里云优化方案。

二、分布式爬虫整体架构拆解

整体四层架构:采集层(多台阿里云 ECS 部署 Scrapy 节点)、调度层(阿里云 Redis 集群 6.0)、存储层(阿里云 RDS MySQL + OSS)、计算层(MaxCompute 离线清洗)。

  1. Redis 集群职责:存储待爬任务队列、分布式指纹去重、请求限流计数器、代理 IP 池状态缓存;
  2. ECS 节点:多台轻量应用服务器横向扩容,无状态,可随时弹性增减;
  3. 合规约束:单 IP 每分钟请求≤15 次,搭配代理池轮换,所有采集仅用于自有代购业务,不对外分发数据,符合平台数据合规要求。

2.1 阿里云 Redis 集群关键配置要点

开通阿里云 Redis 集群版,选择 2 主 2 从架构,开启 RDB+AOF 双重持久化,开启集群读写分离,连接地址使用内网 VPC 地址,避免公网延迟;安全组仅开放 ECS 内网 IP 访问,RAM 子账号分配 Redis 只读 / 读写细分权限,杜绝全量权限泄露。

三、完整可运行工程代码(Python3.9 + scrapy-redis 0.8.0)

3.1 settings.py 分布式 Redis 核心配置(对接阿里云内网 Redis)

# 分布式爬虫开启
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 任务持久化,重启不丢失
SCHEDULER_PERSIST = True
# 阿里云Redis集群内网连接地址,替换为实例内网端点
REDIS_URL = "redis://:xxxx@r-xxxx.redis.rds.aliyuncs.com:6379/0"
# 爬虫并发、限流配置(合规采集核心)
CONCURRENT_REQUESTS = 12
DOWNLOAD_DELAY = 4
RANDOMIZE_DOWNLOAD_DELAY = True
# 全局请求限速,Redis计数器控制单IP 15次/分钟
DOWNLOADER_MIDDLEWARES = {
    'taocarts_spider.middlewares.RateLimitMiddleware': 543,
    'scrapy.downloadermiddlewares.retry.RetryMiddleware': 550,
    'scrapy_redis.downloadmiddleware.RedisRetryMiddleware': 560,
}
# 数据入库Pipeline:RDS MySQL + OSS图片存储
ITEM_PIPELINES = {
    'taocarts_spider.pipelines.MysqlPipeline': 300,
    'taocarts_spider.pipelines.OssImgPipeline': 350,
}
# 关闭本地文件缓存,全部缓存至Redis
HTTPCACHE_ENABLED = False

3.2 自定义限流中间件 RateLimitMiddleware.py(Redis 计数器限流,规避风控封禁)

import redis
import time
from scrapy.http import HtmlResponse
from scrapy.utils.response import response_status_message
from scrapy_redis import get_redis_from_settings

class RateLimitMiddleware:
    def __init__(self, settings):
        self.redis = get_redis_from_settings(settings)
        self.rate_key = "crawl:rate:ip_limit"
        self.max_request = 15  # 单IP每分钟最大请求15次,合规阈值
        self.expire = 60

    @classmethod
    def from_crawler(cls, crawler):
        return cls(crawler.settings)

    def process_request(self, request, spider):
        # Redis自增计数,控制请求频率
        current = self.redis.incr(self.rate_key)
        if current == 1:
            self.redis.expire(self.rate_key, self.expire)
        if current > self.max_request:
            spider.logger.warning(f"请求超限,休眠5s,当前计数:{current}")
            time.sleep(5)
        return None

3.3 分布式爬虫主 spider taobao_spider.py(RedisSpider,多节点共享任务)

from scrapy_redis.spiders import RedisSpider
from taocarts_spider.items import GoodsItem
import json

class TaobaoGoodsRedisSpider(RedisSpider):
    name = "taobao_goods"
    # Redis队列key,多节点共用
    redis_key = "taobao:goods:start_urls"
    custom_settings = {
        "LOG_LEVEL": "INFO"
    }

    def parse(self, response):
        # 解析商品基础字段
        goods_list = response.xpath("//div[@class='item J_MouserOnverReq']")
        for goods in goods_list:
            item = GoodsItem()
            item["goods_id"] = goods.xpath("./@data-nid").get()
            item["title"] = goods.xpath(".//a[@class='J_ClickStat']/@title").get().strip()
            item["price"] = goods.xpath(".//strong/text()").get()
            item["img_url"] = goods.xpath(".//img/@src").get()
            item["source_type"] = "taobao"
            yield item
            # 分页请求推入Redis队列,分布式共享
            next_page = response.xpath("//a[contains(text(),'下一页')]/@href").get()
            if next_page:
                yield response.follow(next_page, callback=self.parse)

3.4 OSS 图片存储 Pipeline oss_pipeline.py(阿里云 OSS Python SDK)

import oss2
from scrapy.utils.project import get_project_settings

class OssImgPipeline:
    def __init__(self):
        settings = get_project_settings()
        # 阿里云OSS RAM子账号密钥,最小权限
        auth = oss2.Auth(settings.get("OSS_ACCESS_KEY_ID"), settings.get("OSS_ACCESS_KEY_SECRET"))
        self.bucket = oss2.Bucket(auth, settings.get("OSS_ENDPOINT"), settings.get("OSS_BUCKET_NAME"))
        self.img_prefix = "crawl/goods/"

    def process_item(self, item, spider):
        if item.get("img_url"):
            img_name = f"{item['source_type']}/{item['goods_id']}.jpg"
            try:
                # 流式上传商品图至OSS,配合CDN加速前端访问
                self.bucket.put_object_from_url(f"{self.img_prefix}{img_name}", item["img_url"])
                # 覆盖为OSS CDN访问地址
                item["oss_img_url"] = f"https://cdn.xxxx.oss-cn-shanghai.aliyuncs.com/{self.img_prefix}{img_name}"
            except Exception as e:
                spider.logger.error(f"OSS上传失败 goods_id:{item['goods_id']}, err:{str(e)}")
                item["oss_img_url"] = ""
        return item

四、线上分布式爬虫八大踩坑复盘(一线真实故障,高收录加分核心)

坑 1:单机 Redis 无集群,主节点宕机任务全部丢失

现象:凌晨阿里云单节点 Redis 磁盘满宕机,待爬 URL 队列清空,当日 3 万采集任务全部丢失,前端商品库存停滞 4 小时。
根因:未开通 Redis 集群版,无从节点热备,仅开启 RDB 未定时持久化。
阿里云修复方案:升级 2 主 2 从 Redis 集群,开启每日自动 RDB 快照备份,配置云监控磁盘使用率告警阈值 80%。

坑 2:多 ECS 节点并发过高,未做 Redis 分布式限流,IP 批量封禁

现象:扩容至 4 台 ECS 后并发达到 40,单 IP 一分钟请求超 60 次,采集代理 IP 池 120 个 IP 全部被平台风控封禁,采集中断 12 小时。
根因:原限流中间件仅单机计数,未使用 Redis 全局计数器,多节点计数隔离。
修复:改造 RateLimitMiddleware 使用全局 Redis key 做全分布式限流,统一管控所有节点请求频率。

坑 3:OSS 图片上传频繁超时,公网 Endpoint 延迟高

现象:爬虫上传商品图平均超时 3s,大量图片存储失败,前端无商品封面。
根因:爬虫 ECS 与 OSS 使用公网域名传输,跨公网带宽波动大。
优化:切换阿里云 VPC 内网 OSS Endpoint,内网传输无流量费,上传耗时降至 200ms 内。

坑 4:Scrapy-Redis 指纹去重内存暴涨,Redis 内存占用超 90%

现象:运行 7 天 Redis 内存占用从 10G 涨到 28G,集群触发内存淘汰,待爬任务被随机删除。
根因:RFPDupeFilter 永久存储指纹,无过期清理逻辑,商品 URL 指纹无限堆积。
解决方案:自定义去重过滤器,给指纹 key 设置 30 天过期,每日定时清理无效商品指纹,Redis 内存稳定控制在 10G 以内。

坑 5:ECS 轻量服务器内存不足,Playwright 辅助爬虫 OOM 被杀

现象:带有动态渲染页面的采集节点,每日凌晨内存溢出进程被系统 kill,断点续爬失效。
优化:ECS 升级 2C4G 配置,阿里云云监控配置内存使用率告警,Redis 任务分段分片抓取,单次不超过 500 条 URL。

坑 6:RDS MySQL 写入频繁超时,爬虫批量入库无事务分批提交

现象:Pipeline 单次一次性写入 1000 条商品数据,数据库连接池耗尽,写入超时。
修复:MysqlPipeline 改造批量分批次提交,单次 200 条开启事务,阿里云 RDS 开启读写分离,写入走主库、离线查询走从库。

坑 7:Redis 集群内网端口未限制安全组,存在公网扫描爆破风险

现象:云安全中心告警 Redis 暴力破解扫描记录,安全组开放 6379 全网段访问。
修复:安全组仅允许爬虫 ECS 内网网段访问 6379,RAM 子账号精细化权限,禁止 Redis 公网访问。

坑 8:爬虫无日志归集,异常封禁只能登录服务器看本地日志

现象:批量 IP 封禁后,无法快速定位是哪类 URL 触发风控,本地日志分散多台 ECS 排查效率极低。
阿里云优化:接入 SLS 日志服务,所有爬虫 stdout/stderr 日志实时归集,配置关键词 “封禁、403、timeout” 告警,钉钉实时推送异常。

五、阿里云架构优化后量化性能提升数据

  1. 采集吞吐量:8000 条 / 天 → 10.6 万条 / 天,扩容至 6 台 ECS 无风控封禁;
  2. 任务丢失率:12% → 0.03%,Redis 集群持久化保障崩溃续爬;
  3. 商品图片加载速度:前端海外用户平均 4.2s → 600ms,OSS 搭配全球 CDN;
  4. 云资源成本:同等采集量下,集群 Redis 比多台单机 Redis 节省 38% 云服务费;
  5. 故障排查耗时:单次采集故障 4 小时定位 → 10 分钟通过 SLS 日志定位根因。
目录
相关文章
|
23天前
|
Linux 程序员 数据格式
【2026最新】Notepad++下载、安装和使用一篇搞定(附中文版安装包)
Notepad++ 是一款免费开源、轻量高效的 Windows 文本编辑器,支持 C/Python/HTML 等 80+ 语言语法高亮、代码折叠、正则替换、编码转换及插件扩展,专为程序员与文本处理用户打造,完美替代系统记事本。(239字)
|
8天前
|
人工智能 缓存 安全
Claude Code 封号真实原因曝光,这次彻底不装了,直接针对国内开发者的账号下手?
Claude Code 封号潮背后:逆向扒出客户端隐写区域标记,Anthropic 政策收紧叠加 DeepSeek 7 月涨价,国产替代更紧迫。
|
13天前
|
人工智能 JSON 自然语言处理
让教学更智慧:用阿里云百炼工作流,自动生成中小学教材内容#小有可为#有温度的AI
通过可视化工作流编排,将大模型推理能力转化为标准化的教学内容生成引擎。教师只需输入教材标题和适用学段,即可自动获得结构完整、符合课程标准的章节内容,大幅降低备课门槛,助力教育资源均衡化。
500 127
|
17天前
|
存储 人工智能 监控
QoderWork完全指南:从入门到精通,把“AI实习生”变成你的全能工作搭档
阿里云2026年推出的桌面端AI工作助手QoderWork,不止聊天,更可动手干活:本地运行、安全可控,支持文件整理、数据分析、PPT生成、网页开发等;内置专家套件、多Agent协作与自定义Skills,让AI真正成为你身边的“AI实习生”。
|
8天前
|
人工智能 安全 程序员
终于,Claude Code 封号的原因被曝光了!竟然针对中国用户,植入隐形代码?!
通俗易懂地揭秘 Claude Code 封号的手段,分享一些自己对 AI 编程困境的思考,Codex、Cursor、DeepSeek、智谱 GLM、甚至是豆包,都有所行动了
474 1
|
9天前
|
人工智能 安全 Cloud Native
Higress 新发布:AI Gateway 能力增强,Gateway API 及其推理扩展持续打磨
增强 AI 网关能力,持续打磨 Gateway API 及其推理扩展。
397 126
|
7天前
|
人工智能 编解码 物联网
2026 最新Stable Diffusion 本地部署教程 下载安装使用详细图解(含官网安装包)
Stable Diffusion(SD)是2022年发布的开源文生图模型,由Stability AI等联合开发。支持文生图、图生图、局部重绘等,依托VAE降低算力需求,可在消费级显卡运行。本文提供秋葉aaaki制作的Windows整合包(含图形界面与插件),开箱即用,零配置启动。