1. 项目背景与核心价值
爬取携程酒店评论数据是旅游行业数据分析的基础工作之一。作为国内领先的OTA平台,携程积累了海量真实用户评价,这些数据对酒店运营者、市场研究人员和数据分析师具有重要价值。通过Python爬虫技术获取这些数据并存储到MySQL数据库,可以建立本地化的评论分析系统,为后续的情感分析、服务质量评估等提供数据支持。
这个项目涉及的核心技术栈包括:
- Python网络请求库(如requests)
- 网页解析工具(如BeautifulSoup)
- 反爬虫绕过技术
- MySQL数据库操作
- 数据清洗与存储
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术方案设计
2.1 整体架构设计
项目采用典型的三层架构:
- 数据采集层:负责发送HTTP请求获取网页内容
- 数据处理层:解析HTML提取目标数据
- 数据存储层:将结构化数据存入MySQL数据库
mermaid复制graph TD
A[采集层] -->|HTTP请求| B[携程网页]
B -->|HTML响应| C[处理层]
C -->|解析数据| D[存储层]
D -->|SQL操作| E[MySQL数据库]
2.2 关键技术选型
2.2.1 爬虫框架选择
考虑携程的反爬机制较为严格,我们选择以下技术组合:
- requests + BeautifulSoup:轻量级组合,适合中小规模爬取
- 配合随机User-Agent和代理IP池应对反爬
- 使用selenium处理动态加载内容(如部分评论的懒加载)
2.2.2 数据库设计
MySQL表结构设计要点:
sql复制CREATE TABLE hotel_reviews (
id INT AUTO_INCREMENT PRIMARY KEY,
hotel_id VARCHAR(50) NOT NULL,
review_id VARCHAR(50) UNIQUE NOT NULL,
user_name VARCHAR(100),
user_level VARCHAR(20),
review_date DATETIME,
room_type VARCHAR(100),
score TINYINT,
content TEXT,
useful_count INT,
images TEXT,
crawl_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
INDEX idx_hotel (hotel_id),
INDEX idx_date (review_date)
);
3. 核心实现步骤
3.1 环境准备
安装必要依赖:
bash复制pip install requests beautifulsoup4 pymysql selenium
3.2 爬虫实现
3.2.1 基础请求函数
python复制import requests
from bs4 import BeautifulSoup
import random
def get_html(url, headers=None, proxies=None):
default_headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...',
'Accept-Language': 'zh-CN,zh;q=0.9'
}
final_headers = {**default_headers, **(headers or {})}
try:
response = requests.get(
url,
headers=final_headers,
proxies=proxies,
timeout=10
)
response.raise_for_status()
return response.text
except Exception as e:
print(f"请求失败: {e}")
return None
3.2.2 评论解析函数
python复制def parse_reviews(html):
soup = BeautifulSoup(html, 'html.parser')
reviews = []
for item in soup.select('.comment-item'):
try:
review = {
'review_id': item.get('data-cid'),
'user_name': item.select_one('.user-name').text.strip(),
'user_level': item.select_one('.user-level').text.strip(),
'score': int(item.select_one('.score > span').text),
'content': item.select_one('.content').text.strip(),
'review_date': item.select_one('.time').text.strip(),
'useful_count': int(item.select_one('.useful').text.strip() or 0)
}
reviews.append(review)
except Exception as e:
print(f"解析评论出错: {e}")
return reviews
3.3 数据库操作
3.3.1 数据库连接池
python复制import pymysql
from dbutils.pooled_db import PooledDB
class MySQLPool:
def __init__(self, config):
self.pool = PooledDB(
creator=pymysql,
maxconnections=5,
**config
)
def get_conn(self):
return self.pool.connection()
3.3.2 数据存储函数
python复制def save_to_db(conn, data):
sql = """
INSERT INTO hotel_reviews (
hotel_id, review_id, user_name, user_level,
review_date, score, content, useful_count
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
ON DUPLICATE KEY UPDATE
useful_count = VALUES(useful_count)
"""
with conn.cursor() as cursor:
try:
cursor.executemany(sql, [
(
data['hotel_id'], item['review_id'],
item['user_name'], item['user_level'],
item['review_date'], item['score'],
item['content'], item['useful_count']
)
for item in data['reviews']
])
conn.commit()
return cursor.rowcount
except Exception as e:
conn.rollback()
print(f"数据库操作失败: {e}")
return 0
4. 反爬虫策略应对
4.1 常见反爬措施
携程采用的反爬手段包括:
- User-Agent检测
- 请求频率限制
- IP封禁
- 验证码挑战
- 行为分析(鼠标轨迹等)
4.2 应对方案
4.2.1 请求头优化
python复制user_agents = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15...',
# 至少准备10个不同的UA
]
def get_random_headers():
return {
'User-Agent': random.choice(user_agents),
'Accept': 'text/html,application/xhtml+xml...',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://www.ctrip.com/'
}
4.2.2 代理IP池实现
python复制class ProxyPool:
def __init__(self):
self.proxies = [
'http://user:pass@ip:port',
# 多个代理IP
]
self.current = 0
def get_proxy(self):
proxy = self.proxies[self.current % len(self.proxies)]
self.current += 1
return {'http': proxy, 'https': proxy}
4.2.3 请求间隔控制
python复制import time
class RequestController:
def __init__(self, base_delay=3, random_factor=0.5):
self.base_delay = base_delay
self.random_factor = random_factor
def wait(self):
delay = self.base_delay * (1 + random.random() * self.random_factor)
time.sleep(delay)
5. 完整爬取流程
5.1 主控程序
python复制def main():
# 初始化各组件
db_config = {
'host': 'localhost',
'user': 'root',
'password': 'yourpassword',
'database': 'ctrip',
'charset': 'utf8mb4'
}
db_pool = MySQLPool(db_config)
proxy_pool = ProxyPool()
request_controller = RequestController()
# 目标酒店列表
hotel_ids = ['12345', '67890'] # 实际应从配置文件或数据库读取
for hotel_id in hotel_ids:
conn = db_pool.get_conn()
page = 1
while True:
url = f'https://hotels.ctrip.com/hotel/{hotel_id}/review_{page}.html'
html = get_html(
url,
headers=get_random_headers(),
proxies=proxy_pool.get_proxy()
)
if not html:
print(f"获取页面失败: {url}")
break
reviews = parse_reviews(html)
if not reviews:
print(f"没有更多评论: {url}")
break
save_result = save_to_db(conn, {
'hotel_id': hotel_id,
'reviews': reviews
})
print(f"保存了{save_result}条评论")
page += 1
request_controller.wait()
conn.close()
if __name__ == '__main__':
main()
5.2 异常处理增强
python复制def safe_main():
try:
main()
except KeyboardInterrupt:
print("用户中断执行")
except Exception as e:
print(f"程序异常: {e}")
finally:
print("爬取任务结束")
safe_main()
6. 数据清洗与优化
6.1 数据清洗策略
常见需要清洗的情况:
- 特殊字符处理(emoji、HTML实体等)
- 虚假评论识别(模板化内容)
- 评分异常值检测
python复制def clean_content(text):
# 处理HTML实体
text = html.unescape(text)
# 去除特殊字符
text = re.sub(r'[\x00-\x1F\x7F]', '', text)
# 标准化空白字符
text = ' '.join(text.split())
return text
6.2 数据库优化建议
-
添加适当的索引:
sql复制ALTER TABLE hotel_reviews ADD FULLTEXT INDEX ft_content (content); -
定期维护:
sql复制OPTIMIZE TABLE hotel_reviews; ANALYZE TABLE hotel_reviews; -
考虑分区表设计(按酒店ID或日期分区)
7. 项目扩展方向
7.1 数据分析应用
获取数据后可进行的分析:
- 情感分析(使用NLP技术)
- 评分趋势分析
- 用户画像构建
- 服务质量评估
7.2 系统增强方案
- 分布式爬虫架构(Scrapy + Redis)
- 自动化监控告警系统
- 增量爬取机制
- 数据可视化展示
8. 法律与道德注意事项
- 严格遵守robots.txt协议
- 控制请求频率,避免对目标网站造成负担
- 仅将数据用于个人学习研究
- 不爬取用户隐私信息
- 考虑设置数据采集时间间隔(如每天仅爬取一次)
重要提示:在实际应用中,建议先获取目标网站的爬虫政策许可,并严格遵守相关法律法规。
