毕业设计实战:如何用Python爬虫为你的旅游推荐系统抓取携程数据(附完整源码)
·
毕业设计实战:Python爬虫在旅游推荐系统中的全流程应用
记得去年做毕业设计时,导师的一句话让我印象深刻:"数据是推荐系统的血液,而爬虫就是造血干细胞。"当时为了构建旅游推荐系统的数据层,我花了整整两周时间研究如何从携程网获取结构化数据。本文将分享一套经过实战检验的Python爬虫方案,不仅包含代码实现,更着重讲解如何让爬取的数据真正服务于推荐算法。
1. 项目规划与法律边界
在开始写第一行代码前,我们需要明确两个核心问题:爬什么数据?如何合法合规地获取?
旅游推荐系统通常需要三类基础数据:
- 景点信息:名称、评分、简介、地理位置
- 酒店数据:价格区间、设施服务、用户评价
- 美食情报:特色菜品、人均消费、周边关联
重要提示:所有爬取操作必须严格遵守robots.txt协议,建议将爬取频率控制在每分钟不超过5次请求,且数据仅用于学术研究。
我曾遇到过一个真实案例:某同学因高频请求导致IP被封,最后不得不调整毕业设计方向。为避免这种情况,建议采用以下防护措施:
import time
import random
def safe_request(url):
"""安全请求函数"""
time.sleep(random.uniform(1, 3)) # 随机延迟1-3秒
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept-Language": "zh-CN,zh;q=0.9"
}
return requests.get(url, headers=headers)
2. 携程网数据抓取实战
2.1 页面解析技术选型
经过对比测试,BeautifulSoup4在携程网页面解析中表现最优。其优势在于:
| 解析方式 | 易用性 | 性能 | 容错性 | 学习曲线 |
|---|---|---|---|---|
| BeautifulSoup4 | ★★★★★ | ★★★ | ★★★★ | ★★ |
| 正则表达式 | ★★ | ★★★★ | ★★ | ★★★★ |
| lxml | ★★★ | ★★★★★ | ★★★ | ★★★ |
实际项目中,我采用组合策略:
from bs4 import BeautifulSoup
import re
def hybrid_parse(html):
"""混合解析方案"""
soup = BeautifulSoup(html, 'lxml')
# 先用BeautifulSoup定位大区块
main_div = soup.find('div', class_='detail-content')
# 再用正则提取精确数据
price = re.search(r'¥(\d+)', main_div.text).group(1)
return {
'price': price,
'raw_html': str(main_div)
}
2.2 反爬应对策略
携程网的反爬机制会随时间变化,2023年常见的防护措施包括:
- 请求头验证:必须包含完整的headers
- 行为检测:异常点击频率识别
- Cookie验证:部分接口需要会话保持
这里分享一个经过验证的headers模板:
HEADERS_TEMPLATE = {
"Accept": "text/html,application/xhtml+xml",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"Referer": "https://www.ctrip.com/",
"Sec-Fetch-Dest": "document",
"Sec-Fetch-Mode": "navigate",
"Sec-Fetch-Site": "same-origin",
"Upgrade-Insecure-Requests": "1"
}
3. 数据存储与清洗
3.1 结构化存储设计
为方便后续推荐算法使用,建议采用如下MongoDB文档结构:
{
"type": "attraction",
"city": "beijing",
"name": "故宫博物院",
"location": {
"lat": 39.916345,
"lng": 116.397155
},
"tags": ["历史", "世界遗产", "必去"],
"statistics": {
"avg_score": 4.8,
"comment_count": 12543
},
"raw_data": {...}
}
3.2 脏数据处理技巧
在数据清洗阶段,我总结了这些常见问题及解决方案:
- 乱码问题:使用
response.encoding = 'utf-8'强制编码 - 缺失字段:建立默认值字典补全
- 异常值:通过百分位法过滤极端数据
清洗代码示例:
def clean_price(price_str):
"""价格清洗函数"""
if not price_str:
return 0
try:
return float(price_str.replace('¥', ''))
except:
# 记录异常日志
log_error(f"价格解析失败: {price_str}")
return 0
4. 与推荐系统的对接
4.1 数据接口设计
推荐系统通常需要以下三种数据形式:
- 批量数据:用于离线模型训练
- 实时流:用于即时推荐
- 特征数据:经过预处理的特征矩阵
建议使用Flask构建简易API:
from flask import Flask, jsonify
import pymongo
app = Flask(__name__)
client = pymongo.MongoClient()
@app.route('/api/attractions/<city>')
def get_attractions(city):
"""获取城市景点接口"""
db = client.tourism
data = list(db.attractions.find({"city": city}, {"_id": 0}))
return jsonify({"data": data, "count": len(data)})
4.2 特征工程实践
旅游推荐的关键特征包括:
- 空间特征:与用户当前位置的距离
- 时间特征:景点适宜游览时段
- 人群特征:家庭/情侣/单人友好度
- 价格特征:消费等级指数
特征计算示例:
def calculate_features(item):
"""计算推荐特征"""
features = {}
features['price_level'] = min(5, item['price'] / 100)
features['time_score'] = len(item['suitable_hours']) / 24
features['distance'] = haversine(user_loc, item['location'])
return features
5. 项目优化与扩展
在实际部署时,可以考虑以下优化方向:
- 增量爬取:通过时间戳只获取新增数据
- 分布式爬虫:使用Scrapy-Redis架构
- 质量监控:建立数据质量评估体系
- 自动化测试:定期验证数据有效性
一个简单的监控脚本示例:
def check_data_quality():
"""数据质量检查"""
stats = {
'total': db.count_documents({}),
'null_fields': db.count_documents({"name": None}),
'duplicates': db.count_documents({"name": {"$exists": True}})
}
if stats['null_fields'] / stats['total'] > 0.1:
alert_admin("数据空值率过高!")
记得在项目答辩时,评委特别关注数据获取的合法性和系统可扩展性。建议在毕业设计文档中单独设立章节说明爬虫的伦理考量和技术边界,这往往能成为项目亮点。
更多推荐


所有评论(0)