1. 项目背景与核心价值
酒店价格实时抓取是旅游行业数据分析的基础能力之一。去年帮朋友做民宿定价策略时,我发现手动比价效率极低,而市面上的价格监测工具要么功能过剩要么价格昂贵。于是用Python写了个轻量级爬虫,每天自动抓取携程酒店价格数据,帮助他动态调整房源报价,三个月内入住率提升了22%。
这个项目的核心价值在于:
- 实时性:数据更新频率可精确到小时级
- 定制化:能针对特定城市、商圈、房型进行定向监测
- 低成本:无需购买商业数据接口,服务器月成本不足50元
重要提示:爬虫开发需遵守《数据安全法》相关规定,本案例仅抓取公开价格数据,不涉及用户隐私信息,单IP请求频率控制在15次/分钟以下。
2. 技术架构设计
2.1 整体流程图解
[定时触发器] → [URL生成器] → [请求管理器] → [HTML解析器] ↓ ↑ [异常重试机制] ← [数据清洗模块] ← [反爬绕过模块] ↓ [数据存储] → [可视化报表]2.2 关键技术选型
- 请求库:aiohttp(异步IO支持)
- 解析库:parsel(比BeautifulSoup快40%)
- 存储方案:MongoDB(应对字段变更)
- 反反爬方案:
- 动态User-Agent池(维护200+浏览器指纹)
- 代理IP轮询(使用芝麻代理API)
- 鼠标移动轨迹模拟(通过PyMouse实现)
3. 核心代码实现
3.1 请求头智能生成
def gen_headers(): ua = UserAgent().random return { 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.9', 'User-Agent': ua, 'X-Requested-With': 'XMLHttpRequest', 'Referer': 'https://www.ctrip.com/' }3.2 价格解析关键逻辑
def parse_price(html): sel = parsel.Selector(html) # 处理三种价格展示形式 price = sel.xpath('//span[@class="base_price"]/text()').get() \ or sel.css('div.price::attr(data-price)').get() \ or re.search(r'"price":(\d+)', html).group(1) return float(price) if price else None3.3 反爬异常处理
async def safe_fetch(session, url): try: async with session.get(url, headers=gen_headers(), proxy=PROXY_POOL.get_ip(), timeout=20) as resp: if resp.status == 403: raise AntiSpiderException return await resp.text() except Exception as e: await asyncio.sleep(random.uniform(1,3)) return await safe_fetch(session, url) # 指数退避重试4. 数据存储优化方案
4.1 MongoDB文档设计
{ "_id": ObjectId("..."), "hotel_id": "123456", "check_in": ISODate("2023-08-20"), "price": 598.0, "timestamp": ISODate("2023-08-01T14:30:00Z"), "room_type": "豪华大床房", "breakfast": True, "cancel_policy": "免费取消", "data_source": "ctrip" }4.2 索引优化策略
db.prices.createIndex({hotel_id: 1, check_in: 1, timestamp: 1}) db.prices.createIndex({timestamp: -1})5. 实战避坑指南
5.1 动态参数破解
携程2023年新版页面增加了_fxpcqlniredt参数,需通过以下方式获取:
- 分析首页JavaScript代码
- 提取
window.__DC__对象中的加密字段 - 使用PyExecJS执行加密函数
5.2 价格抖动处理
实测发现同一房型在短时间内可能出现±5%的价格波动,建议:
- 设置5分钟内的重复请求去重
- 计算移动平均值作为参考
- 忽略小于3%的价格变动
5.3 法律合规要点
- 在robots.txt允许的目录下爬取
- 单个IP请求间隔≥4秒
- 不爬取用户评价等UGC内容
- 数据存储不超过6个月
6. 可视化分析案例
使用Pyecharts生成价格热力图:
from pyecharts import options as opts from pyecharts.charts import Calendar calendar = ( Calendar() .add("", data, calendar_opts=opts.CalendarOpts(range_="2023-08")) .set_global_opts( visualmap_opts=opts.VisualMapOpts(max_=2000), title_opts=opts.TitleOpts(title="8月价格波动趋势") ) ) calendar.render("price_calendar.html")最终效果展示(模拟数据):
日价格中位数波动区间: ┌──────────┬─────────────┐ │ 日期 │ 价格(元) │ ├──────────┼─────────────┤ │ 2023-08-01 │ 588 - 612 │ │ 2023-08-08 │ 702 - 735 │ # 周末溢价 │ 2023-08-15 │ 558 - 578 │ # 工作日特惠 └──────────┴─────────────┘这个项目最让我意外的是携程的反爬策略每季度都会升级,最近他们开始检测WebGL指纹了。建议维护一个特征库,定期更新爬虫的浏览器环境参数。另外用Serverless架构部署会更经济,阿里云函数计算每月免费额度足够支撑10万次请求。