1. 项目背景与核心思路
去年双十一期间,我偶然发现某OTA平台凌晨3点会放出少量1折机票。但手动刷新根本抢不到,于是萌生了用Python搭建自动化监控系统的想法。经过两个月的迭代,这套系统成功帮我抢到7次1折机票,累计节省2.3万元。下面分享具体实现方案。
注意:本文仅讨论技术实现,所有操作需遵守平台规则。建议监控频率控制在5分钟/次以内,避免对服务器造成压力。
2. 系统架构设计
2.1 整体技术栈
mermaid复制graph TD
A[爬虫集群] --> B[Redis消息队列]
B --> C[价格分析引擎]
C --> D[自动下单模块]
D --> E[通知系统]
2.2 关键组件选型
| 模块 | 技术方案 | 选型理由 |
|---|---|---|
| 数据采集 | Scrapy+selenium | 兼顾效率与动态渲染 |
| 消息队列 | Redis Stream | 轻量级+持久化 |
| 存储 | MongoDB | 灵活处理非结构化数据 |
| 分析 | Pandas+Numpy | 快速计算价格波动 |
| 通知 | Telegram Bot | 高送达率+跨平台 |
3. 核心代码实现
3.1 智能爬虫设计
python复制class OtaSpider(scrapy.Spider):
def __init__(self):
self.proxy_pool = ProxyMiddleware()
self.retry_strategy = {
'total': 3,
'backoff': [5,10,15] # 指数退避策略
}
def parse(self, response):
try:
items = response.xpath('//div[@class="flight-item"]')
for item in items:
price = float(item.xpath('.//span[@class="price"]/text()').get()[1:])
if self.is_abnormal_price(price):
self.send_alert(price)
except Exception as e:
self.logger.error(f"解析失败: {e}")
yield self.retry_request(response.url)
def is_abnormal_price(self, price):
# 基于历史价格的Z-Score检测
history_prices = self.get_history_prices()
mean = np.mean(history_prices)
std = np.std(history_prices)
return (price - mean) < -3*std # 3σ原则
3.2 价格分析算法
python复制def detect_price_drop(prices):
"""
使用CUSUM算法检测价格突变
:param prices: 历史价格序列
:return: bool 是否出现异常低价
"""
target = np.median(prices)
C_plus, C_minus = 0, 0
threshold = target * 0.3 # 30%跌幅阈值
for p in prices[-24:]: # 最近24次记录
C_plus = max(0, C_plus + (target - p))
C_minus = max(0, C_minus + (p - target))
if C_plus > threshold or C_minus > threshold:
return True
return False
4. 反反爬策略实战
4.1 指纹混淆方案
python复制def get_random_headers():
return {
'User-Agent': random.choice(USER_AGENTS),
'Accept-Language': f"en-US,en;q=0.{random.randint(5,9)}",
'X-Forwarded-For': f"{random.randint(1,255)}.{random.randint(0,255)}.{random.randint(0,255)}.{random.randint(0,255)}",
'Accept-Encoding': 'gzip, deflate, br'
}
4.2 行为模拟策略
- 随机点击页面非核心区域
- 模拟鼠标移动轨迹(贝塞尔曲线)
- 随机间隔(3-8秒)翻页
- 动态调整请求速率(根据响应时间自适应)
5. 系统优化经验
5.1 性能调优记录
| 优化点 | 优化前 | 优化后 | 方法 |
|---|---|---|---|
| 解析速度 | 1200ms/页 | 400ms/页 | 改用lxml替代parsel |
| 内存占用 | 2.1GB | 680MB | 启用scrapy的JOBDIR |
| 成功率 | 72% | 93% | 增加TLS指纹轮换 |
5.2 踩坑实录
- Cookie失效:解决方案是维护多个账号的Cookie池
- 验证码触发:通过控制单个IP的请求频率在15次/分钟以下
- 数据漂移:增加XPath的多重fallback选择器
- 代理失效:实现自动化的代理质量检测系统
6. 部署方案
6.1 服务器配置建议
yaml复制# docker-compose.yml示例
services:
spider:
image: scrapy:3.0
deploy:
replicas: 3
resources:
limits:
cpus: '0.5'
memory: 512M
redis:
image: redis:6-alpine
volumes:
- redis_data:/data
volumes:
redis_data:
6.2 监控指标设计
- 成功率指标:
(200响应数)/(总请求数) - 有效数据率:
(解析成功数)/(200响应数) - 报警响应延迟:
从发现低价到通知的时间差
7. 法律与伦理边界
- 严格遵守robots.txt协议
- 单IP请求频率≤12次/分钟
- 不绕过任何付费接口
- 数据仅用于个人使用
- 不干扰正常用户访问
这套系统经过半年运行,核心经验是:异常价格往往出现在(1)平台BUG价(2)供应商标错价(3)特殊促销时段。建议重点关注凌晨3-5点、整点时刻的价格波动。