1. 项目概述:千万级电商数据爬取系统设计
这个爬虫系统最初源于一个真实的商业需求:某跨境电商平台需要持续监控15个主流电商网站的2300万SKU数据,包含价格、库存、评论等多维度信息。传统单机爬虫在数据量超过50万时就会出现性能断崖式下跌,我们不得不重构整个架构。
核心设计指标很明确:
- 日均稳定抓取300万条商品数据
- 99.9%的请求成功率
- 数据延迟不超过15分钟
- 存储成本控制在每GB小于0.3元
经过三个版本的迭代,最终形成的技术栈组合:
- 采集层:Scrapy-Redis分布式调度 + 动态代理池
- 存储层:MongoDB分片集群 + 冷热数据分离
- 分析层:PySpark预处理 + Superset可视化
- 监控层:Prometheus + Grafana告警
关键提示:在正式开发前务必检查目标网站的robots.txt协议,我们曾因疏忽触发反爬机制导致IP被封禁两周。合理的爬取间隔建议设置在5-10秒/请求,夜间可适当提升至2-3秒/请求。
2. 分布式爬虫架构实现
2.1 基础环境搭建
在阿里云ECS上部署的集群配置:
bash复制# 主节点(1台)
CPU: 8核 内存: 32GB 带宽: 100Mbps
# 工作节点(8台)
CPU: 4核 内存: 16GB 带宽: 50Mbps
# MongoDB集群(3台分片)
CPU: 16核 内存: 64GB SSD: 2TB
Python环境建议使用Miniconda管理:
bash复制conda create -n spider python=3.8
conda install -c conda-forge scrapy redis pymongo
2.2 核心组件开发
URL调度器改造:
python复制# 继承RedisSpider重写start_requests
class ProductSpider(RedisSpider):
name = 'product'
redis_key = 'product:start_urls'
def make_request_from_data(self, data):
item = json.loads(data)
return FormRequest(
url=item['url'],
formdata={'page': str(item['page'])},
meta={'proxy': get_random_proxy()}
)
反反爬策略:
- 动态UserAgent轮换(准备200+常用UA)
- 基于Luminati搭建代理池(实测成本$0.7/GB)
- 鼠标移动轨迹模拟(使用selenium-wire)
- 请求指纹随机化(每个请求添加随机参数)
3. MongoDB海量存储方案
3.1 分片集群配置
关键分片策略:
javascript复制sh.enableSharding("ecommerce")
sh.shardCollection("ecommerce.products", { "category": 1, "_id": 1 })
索引优化方案:
javascript复制db.products.createIndex({ "sku": 1 }, { unique: true })
db.products.createIndex({ "price": 1, "update_time": -1 })
3.2 数据生命周期管理
采用TTL索引自动清理历史数据:
javascript复制// 保留30天价格历史
db.price_history.createIndex(
{ "created_at": 1 },
{ expireAfterSeconds: 2592000 }
)
冷数据归档方案:
python复制# 使用mongodump按月份归档
def archive_cold_data():
last_month = datetime.now() - timedelta(days=30)
os.system(f"mongodump --db ecommerce --collection products "
f"--query '{{update_time: {{$lt: ISODate(\"{last_month}\")}}}}'")
4. 数据分析与可视化
4.1 PySpark数据处理
价格波动分析示例:
python复制from pyspark.sql import functions as F
df = spark.read.format("mongo").load()
result = df.groupBy("category") \
.agg(F.avg("price").alias("avg_price"),
F.stddev("price").alias("price_std")) \
.orderBy("price_std", ascending=False)
4.2 Superset看板配置
核心指标看板包含:
- 实时抓取成功率仪表盘
- 品类价格分布热力图
- 库存变化趋势曲线
- 竞品价格对比矩阵
5. 性能调优实战记录
5.1 爬虫效率优化
经过JMeter压测发现的瓶颈点:
- 图片下载占用90%带宽 → 启用懒加载
- XPath解析消耗40%CPU → 改用CSS选择器
- 重复请求占比15% → 强化BloomFilter去重
优化前后对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| 请求QPS | 120 | 450 |
| 内存占用 | 8GB | 3.2GB |
| 网络带宽 | 60Mbps | 22Mbps |
5.2 MongoDB性能调优
关键参数调整:
yaml复制storage:
wiredTiger:
engineConfig:
cacheSizeGB: 48 # 物理内存的70%
collectionConfig:
blockCompressor: zstd
systemLog:
verbosity: 1
operationProfiling:
mode: slowOp
slowOpThresholdMs: 100
6. 典型问题排查指南
问题1:MongoDB服务频繁崩溃
- 现象:错误代码1067,日志显示OOM
- 解决方案:
- 设置ulimit -n 64000
- 添加swap分区
- 调整wiredTiger缓存大小
问题2:爬虫被封禁
- 快速检测:curl -I 目标URL | grep X-RateLimit
- 应急方案:
- 立即切换代理池
- 降低请求频率50%
- 添加验证码识别模块
问题3:数据重复写入
- 根本原因:网络重试导致消息重复
- 最终方案:
python复制# 使用原子操作实现幂等写入
db.products.update_one(
{"sku": item["sku"]},
{"$setOnInsert": item},
upsert=True
)
在三个月稳定运行期间,这套系统累计抓取1.2亿条商品数据,存储压缩后占用437GB空间,最关键的品类价格监控看板帮助运营团队发现了17次异常价格波动,通过及时调整策略避免了约230万元的预期损失。
