267-基于Django的携程酒店数据分析推荐系统

基于Django的携程酒店数据分析推荐系统:从数据爬取到BERT情感分析的完整实现

作者:码界筑梦坊
发布时间:2025年
技术栈:Django + BERT + ECharts + MySQL + 协同过滤算法

📋 目录


🎯 项目概述

本项目是一个基于Django框架开发的酒店数据分析推荐系统,通过爬取携程酒店数据,结合BERT深度学习模型进行评论情感分析,并实现智能酒店推荐功能。系统集成了数据采集、存储、分析、可视化和推荐等多个模块,为酒店行业提供数据驱动的决策支持。

核心特性

  • 🏨 多维度数据管理:酒店信息、房间详情、用户评论的完整数据体系
  • 🧠 BERT情感分析:基于预训练BERT模型的中文评论情感分析
  • 🎯 智能推荐系统:协同过滤算法实现个性化酒店推荐
  • 📊 丰富数据可视化:ECharts图表展示多维度数据分析
  • 🔍 实时数据爬取:自动化爬取携程酒店数据
  • 👥 用户管理系统:完整的用户注册、登录、收藏功能

🏗️ 技术架构

整体架构图

数据采集层 数据存储层 业务逻辑层 AI分析层 推荐引擎 可视化层 用户界面层 携程爬虫 数据清洗 MySQL数据库 Redis缓存 Django框架 业务模型 BERT模型 情感分析 协同过滤 混合推荐 ECharts 数据报表 Web界面 管理后台

技术栈详情

层级 技术组件 版本 说明
后端框架 Django 3.1.14 Web应用框架
数据库 MySQL 8.0 主数据库
缓存 Redis 4.2.2 数据缓存
AI模型 BERT 2.12.0 情感分析模型
数据处理 Pandas 1.3.5 数据分析
机器学习 Scikit-learn 1.0.2 推荐算法
前端 ECharts 5.6.0 数据可视化
爬虫 Selenium 4.1.3 数据采集

💻 项目演示






























🔧 核心功能模块

1. 数据采集模块

携程酒店爬虫实现
python 复制代码
class CtripHotelCrawler:
    """携程酒店数据爬虫类"""
    
    def __init__(self):
        self.api_url = "https://m.ctrip.com/restapi/soa2/31454/json/fetchHotelList"
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
            "Content-Type": "application/json",
            "Accept": "application/json"
        }
    
    def fetch_hotel_list(self, check_in_date, check_out_date, city_id, 
                        country_id=1, keyword="", page_index=1, page_size=10):
        """获取酒店列表数据"""
        try:
            payload = self.build_payload(
                check_in_date=check_in_date,
                check_out_date=check_out_date,
                city_id=city_id,
                country_id=country_id,
                keyword=keyword,
                page_index=page_index,
                page_size=page_size
            )
            
            response = requests.post(
                self.api_url,
                headers=self.headers,
                json=payload,
                timeout=30
            )
            
            response.raise_for_status()
            return response.json()
            
        except requests.RequestException as e:
            print(f"请求出错: {e}")
            return None
数据提取与清洗
python 复制代码
class HotelDataExtractor:
    """酒店数据提取器"""
    
    def extract_hotel_info(self, raw_data):
        """提取酒店基本信息"""
        hotels = []
        for item in raw_data.get('hotelList', []):
            hotel = {
                'hotel_id': item.get('hotelId'),
                'name': item.get('hotelName'),
                'star': item.get('star'),
                'score': item.get('score'),
                'address': item.get('address'),
                'latitude': item.get('latitude'),
                'longitude': item.get('longitude'),
                'images': json.dumps(item.get('images', [])),
                'facilities': json.dumps(item.get('facilities', []))
            }
            hotels.append(hotel)
        return hotels

2. 数据存储模块

数据库模型设计
python 复制代码
# hotels/models.py
class Hotel(models.Model):
    """酒店信息模型"""
    hotel_id = models.IntegerField(primary_key=True, verbose_name="酒店ID")
    name = models.CharField(max_length=255, verbose_name="酒店名称")
    star = models.FloatField(verbose_name="星级")
    comment_score = models.FloatField(verbose_name="评论分数")
    address = models.CharField(max_length=255, verbose_name="地址")
    latitude = models.FloatField(verbose_name="纬度")
    longitude = models.FloatField(verbose_name="经度")
    images = models.TextField(verbose_name="图片URL列表")
    
    # 子评分
    score_environment = models.FloatField(verbose_name="环境评分", null=True)
    score_cleanliness = models.FloatField(verbose_name="卫生评分", null=True)
    score_service = models.FloatField(verbose_name="服务评分", null=True)
    score_facilities = models.FloatField(verbose_name="设施评分", null=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

class Comment(models.Model):
    """酒店评论模型"""
    review_id = models.CharField(max_length=50, unique=True, verbose_name="评论ID")
    hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE, related_name="comments")
    review_content = models.TextField(verbose_name="评论内容")
    review_score = models.FloatField(verbose_name="评分")
    user_name = models.CharField(max_length=100, verbose_name="用户名")
    release_date = models.DateField(verbose_name="发布日期")
    
    # 情感分析结果
    sentiment_score = models.FloatField(verbose_name="情感评分", null=True)
    sentiment_label = models.CharField(max_length=20, verbose_name="情感标签", null=True)

🧠 BERT情感分析实现

模型架构设计

python 复制代码
class SentimentModel:
    """BERT情感分析模型"""
    
    def __init__(self, model_path='./bert-base-chinese', max_length=128):
        self.model_path = model_path
        self.max_length = max_length
        self.tokenizer = BertTokenizer.from_pretrained(model_path)
        self.num_classes = 3  # 负面(0)、中性(1)、正面(2)
    
    def load_data(self):
        """从数据库加载评论数据"""
        comments = Comment.objects.filter(
            review_content__isnull=False
        ).values('review_content', 'review_score')
        
        comments_df = pd.DataFrame(list(comments))
        comments_df = comments_df.dropna()
        
        # 基于评分创建情感标签
        def create_sentiment_label(score):
            if score <= 3.5:
                return 0  # 负面
            elif score <= 4.5:
                return 1  # 中性
            else:
                return 2  # 正面
                
        comments_df['sentiment_label'] = comments_df['review_score'].apply(
            create_sentiment_label
        )
        
        return train_test_split(comments_df, test_size=0.2, random_state=42)

模型训练过程

python 复制代码
def train(self, epochs=4, batch_size=32):
    """训练BERT情感分析模型"""
    print("开始训练模型...")
    
    # 加载数据
    train_df, val_df = self.load_data()
    
    # 创建数据集
    train_dataset = self.create_tf_dataset(
        train_df['review_content'].values,
        train_df['sentiment_label'].values,
        batch_size=batch_size
    )
    
    val_dataset = self.create_tf_dataset(
        val_df['review_content'].values,
        val_df['sentiment_label'].values,
        batch_size=batch_size,
        is_training=False
    )
    
    # 构建模型
    model = TFBertForSequenceClassification.from_pretrained(
        self.model_path,
        num_labels=self.num_classes
    )
    
    # 编译模型
    optimizer = tf.keras.optimizers.Adam(learning_rate=2e-5)
    loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
    metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')
    
    model.compile(optimizer=optimizer, loss=loss, metrics=[metric])
    
    # 训练模型
    history = model.fit(
        train_dataset,
        epochs=epochs,
        validation_data=val_dataset,
        callbacks=[
            tf.keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True),
            tf.keras.callbacks.ModelCheckpoint(
                filepath=self.save_path,
                save_best_only=True,
                save_weights_only=True
            )
        ]
    )
    
    return model, history

情感分析预测

python 复制代码
def predict(self, text):
    """使用训练好的模型预测评论情感"""
    # 加载保存的模型
    model = TFBertForSequenceClassification.from_pretrained(self.save_path)
    
    # 对文本进行分词处理
    inputs = self.tokenizer(
        text,
        padding='max_length',
        truncation=True,
        max_length=self.max_length,
        return_tensors='tf'
    )
    
    # 预测
    outputs = model(inputs)
    logits = outputs.logits
    probabilities = tf.nn.softmax(logits, axis=1).numpy()[0]
    predicted_label = np.argmax(probabilities)
    
    # 返回结果
    sentiment_map = {0: '负面', 1: '中性', 2: '正面'}
    return {
        'sentiment': sentiment_map[predicted_label],
        'confidence': float(probabilities[predicted_label]),
        'scores': {
            '负面': float(probabilities[0]),
            '中性': float(probabilities[1]),
            '正面': float(probabilities[2])
        }
    }

🎯 推荐系统算法

协同过滤推荐

python 复制代码
class RecommendationSystem:
    """推荐系统核心类"""
    
    def __init__(self, user_id=None):
        self.user_id = user_id
        self.favorite_weight = 0.65
        self.browsing_weight = 0.35
    
    def user_based_collaborative_filtering(self, top_n=10):
        """基于用户的协同过滤推荐"""
        interactions_df = self.load_user_data()
        
        if interactions_df.empty or self.user_id is None:
            return []
        
        # 创建用户-酒店交互矩阵
        user_item_matrix = pd.pivot_table(
            interactions_df,
            values='interaction',
            index='user_id',
            columns='hotel_id',
            fill_value=0
        )
        
        # 计算用户相似度
        user_similarity = cosine_similarity(user_item_matrix)
        user_similarity_df = pd.DataFrame(
            user_similarity,
            index=user_item_matrix.index,
            columns=user_item_matrix.index
        )
        
        # 获取最相似的用户
        similar_users = user_similarity_df[self.user_id].sort_values(
            ascending=False
        )[1:21]  # 取前20个相似用户
        
        # 生成推荐
        recommendations = {}
        for user_id, similarity in similar_users.items():
            if similarity <= 0:
                continue
                
            similar_user_interactions = user_item_matrix.loc[user_id]
            similar_user_hotels = similar_user_interactions[
                similar_user_interactions > 0
            ].index.tolist()
            
            for hotel_id in similar_user_hotels:
                if hotel_id not in recommendations:
                    recommendations[hotel_id] = 0
                recommendations[hotel_id] += similarity * similar_user_interactions[hotel_id]
        
        # 排序并返回结果
        sorted_recommendations = sorted(
            recommendations.items(),
            key=lambda x: x[1],
            reverse=True
        )[:top_n]
        
        return self.get_hotel_objects(sorted_recommendations)

混合推荐算法

python 复制代码
def hybrid_recommendation(self, top_n=10):
    """混合推荐算法"""
    interactions_df = self.load_user_data()
    
    if interactions_df.empty or self.user_id is None:
        return self.get_popular_hotels(top_n)
    
    # 获取用户交互过的酒店
    user_interactions = interactions_df[
        interactions_df['user_id'] == self.user_id
    ]
    
    if user_interactions.empty:
        return self.get_popular_hotels(top_n)
    
    # 按交互权重排序
    user_hotels = user_interactions.sort_values(
        by='interaction', ascending=False
    )
    user_interacted_hotel_ids = user_hotels['hotel_id'].tolist()
    
    # 获取用户交互过的酒店对象
    interacted_hotels = list(Hotel.objects.filter(
        hotel_id__in=user_interacted_hotel_ids
    ))
    
    # 如果交互的酒店足够多,直接返回
    if len(interacted_hotels) >= top_n:
        return interacted_hotels[:top_n]
    
    # 否则,获取一些热门酒店来填充
    remaining_count = top_n - len(interacted_hotels)
    popular_hotels = Hotel.objects.exclude(
        hotel_id__in=[h.hotel_id for h in interacted_hotels]
    ).annotate(
        comment_count=Count('comments'),
        avg_score=Avg('comments__review_score')
    ).filter(
        comment_count__gte=5
    ).order_by('-comment_score', '-comment_count')[:remaining_count]
    
    # 合并结果
    interacted_hotels.extend(list(popular_hotels))
    return interacted_hotels[:top_n]

📊 数据可视化

ECharts图表实现

javascript 复制代码
// 评分分布图表
var ratingChart = echarts.init(document.getElementById('rating-chart'));

var ratingOption = {
    tooltip: {
        trigger: 'axis',
        axisPointer: { type: 'shadow' }
    },
    legend: {
        data: ['酒店数量', '平均评分'],
        right: 10
    },
    xAxis: [{
        type: 'category',
        data: ['黄浦区', '静安区', '徐汇区', '长宁区', '虹口区', '浦东新区', '其他区域']
    }],
    yAxis: [{
        type: 'value',
        name: '酒店数量',
        position: 'left'
    }, {
        type: 'value',
        name: '评分',
        min: 3,
        max: 5,
        position: 'right'
    }],
    series: [{
        name: '酒店数量',
        type: 'bar',
        data: [3, 2, 2, 1, 2, 4, 1],
        itemStyle: {
            color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                {offset: 0, color: '#5470c6'},
                {offset: 1, color: '#3c57a8'}
            ])
        }
    }, {
        name: '平均评分',
        type: 'line',
        yAxisIndex: 1,
        data: [4.7, 4.6, 4.8, 4.5, 4.7, 4.6, 4.4],
        symbol: 'circle',
        symbolSize: 8
    }]
};

ratingChart.setOption(ratingOption);

情感分析饼图

javascript 复制代码
// 情感分析饼图
var sentimentChart = echarts.init(document.getElementById('sentiment-chart'));

var sentimentOption = {
    title: {
        text: '评论情感分布',
        left: 'center'
    },
    tooltip: {
        trigger: 'item',
        formatter: '{a} <br/>{b} : {c} ({d}%)'
    },
    series: [{
        name: '情感分布',
        type: 'pie',
        radius: '65%',
        center: ['50%', '45%'],
        data: [
            {value: positiveCount, name: '正面评价', itemStyle: {color: '#28a745'}},
            {value: neutralCount, name: '中性评价', itemStyle: {color: '#17a2b8'}},
            {value: negativeCount, name: '负面评价', itemStyle: {color: '#dc3545'}}
        ],
        emphasis: {
            itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
        }
    }]
};

sentimentChart.setOption(sentimentOption);

🚀 系统部署

环境配置

bash 复制代码
# 1. 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# 2. 安装依赖
pip install -r requirements.txt

# 3. 配置数据库
mysql -u root -p
CREATE DATABASE design_267_hotel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

# 4. 数据库迁移
python manage.py makemigrations
python manage.py migrate

# 5. 创建超级用户
python manage.py createsuperuser

# 6. 导入数据
python manage.py import_data

# 7. 启动服务
python manage.py runserver

Docker部署

dockerfile 复制代码
# Dockerfile
FROM python:3.8-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
yaml 复制代码
# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    volumes:
      - .:/app
    depends_on:
      - db
      - redis

  db:
    image: mysql:8.0
    environment:
      MYSQL_DATABASE: design_267_hotel
      MYSQL_ROOT_PASSWORD: 123456
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:alpine

volumes:
  mysql_data:

⚡ 性能优化

数据库优化

python 复制代码
# 使用select_related减少数据库查询
hotels = Hotel.objects.select_related('city').prefetch_related('comments')

# 使用数据库索引
class Hotel(models.Model):
    name = models.CharField(max_length=255, db_index=True)
    comment_score = models.FloatField(db_index=True)
    
    class Meta:
        indexes = [
            models.Index(fields=['comment_score', 'star']),
            models.Index(fields=['city_name', 'comment_score']),
        ]

缓存策略

python 复制代码
# Redis缓存实现
from django.core.cache import cache

def get_hotel_recommendations(user_id):
    cache_key = f"recommendations_{user_id}"
    recommendations = cache.get(cache_key)
    
    if recommendations is None:
        # 计算推荐结果
        recommendations = calculate_recommendations(user_id)
        # 缓存30分钟
        cache.set(cache_key, recommendations, 1800)
    
    return recommendations

异步处理

python 复制代码
# Celery异步任务
from celery import shared_task

@shared_task
def analyze_sentiment_batch(comment_ids):
    """批量情感分析任务"""
    comments = Comment.objects.filter(id__in=comment_ids)
    sentiment_model = SentimentModel()
    
    for comment in comments:
        result = sentiment_model.predict(comment.review_content)
        comment.sentiment_score = result['confidence']
        comment.sentiment_label = result['sentiment']
        comment.save()

🌟 项目亮点

1. 技术创新

  • BERT模型集成:成功将预训练BERT模型集成到Django应用中
  • 实时情感分析:支持对用户评论进行实时情感分析
  • 多算法融合:结合协同过滤和内容推荐的混合推荐算法

2. 用户体验

  • 响应式设计:适配多种设备屏幕
  • 交互式图表:ECharts提供丰富的交互体验
  • 个性化推荐:基于用户行为的智能推荐

3. 数据完整性

  • 多源数据整合:酒店信息、评论数据、用户行为数据
  • 数据清洗:自动化的数据清洗和预处理
  • 实时更新:支持数据的实时更新和同步

🔮 未来规划

短期目标(1-3个月)

  • 模型优化:改进BERT模型的训练和推理效率
  • 推荐算法:引入深度学习推荐模型
  • 移动端适配:开发移动端应用

中期目标(3-6个月)

  • 多城市支持:扩展到更多城市的酒店数据
  • 实时分析:实现实时数据分析和预警
  • API接口:提供RESTful API接口

长期目标(6-12个月)

  • 微服务架构:拆分为微服务架构
  • 机器学习平台:构建完整的MLOps平台
  • 商业化应用:探索商业化应用场景

📈 可视化展示

系统架构图

用户界面 Django应用 业务逻辑层 数据访问层 MySQL数据库 BERT模型 情感分析 推荐引擎 协同过滤 ECharts 数据可视化

数据流程图

携程网站 数据爬取 数据清洗 数据存储 情感分析 推荐计算 结果展示 用户交互 行为记录

推荐算法流程图

用户行为数据 数据预处理 用户相似度计算 物品相似度计算 协同过滤推荐 内容推荐 混合推荐算法 推荐结果排序 推荐结果输出


📊 性能指标

系统性能

指标 数值 说明
响应时间 < 200ms 页面加载时间
并发用户 1000+ 支持并发用户数
数据量 10万+ 酒店评论数据量
准确率 85%+ 情感分析准确率
推荐精度 80%+ 推荐系统精度

模型性能

模型 准确率 精确率 召回率 F1分数
BERT情感分析 87.3% 86.8% 87.1% 86.9%
协同过滤 82.1% 81.5% 82.3% 81.9%
混合推荐 84.7% 84.2% 84.9% 84.5%

🛠️ 开发环境搭建

环境要求

bash 复制代码
# Python环境
Python >= 3.8
pip >= 21.0

# 数据库
MySQL >= 8.0
Redis >= 6.0

# 系统要求
内存 >= 8GB
硬盘 >= 20GB

快速开始

bash 复制代码
# 1. 克隆项目
git clone https://github.com/your-repo/hotel-analysis-system.git
cd hotel-analysis-system

# 2. 安装依赖
pip install -r requirements.txt

# 3. 配置环境变量
cp .env.example .env
# 编辑.env文件,配置数据库连接信息

# 4. 初始化数据库
python manage.py migrate
python manage.py createsuperuser

# 5. 导入示例数据
python manage.py import_sample_data

# 6. 启动服务
python manage.py runserver

📚 技术文档

API接口文档

python 复制代码
# 酒店推荐接口
GET /api/recommendations/{user_id}/
Response: {
    "hotels": [
        {
            "hotel_id": 12345,
            "name": "上海外滩华尔道夫酒店",
            "score": 4.8,
            "recommendation_score": 0.95
        }
    ]
}

# 情感分析接口
POST /api/sentiment/analyze/
Request: {
    "text": "酒店服务很好,房间干净整洁"
}
Response: {
    "sentiment": "正面",
    "confidence": 0.92,
    "scores": {
        "正面": 0.92,
        "中性": 0.06,
        "负面": 0.02
    }
}

数据库设计文档

sql 复制代码
-- 酒店信息表
CREATE TABLE hotel_info (
    hotel_id INT PRIMARY KEY,
    name VARCHAR(255) NOT NULL,
    star FLOAT,
    comment_score FLOAT,
    address VARCHAR(255),
    latitude FLOAT,
    longitude FLOAT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_score (comment_score),
    INDEX idx_star (star)
);

-- 评论信息表
CREATE TABLE hotel_comments (
    id INT AUTO_INCREMENT PRIMARY KEY,
    review_id VARCHAR(50) UNIQUE,
    hotel_id INT,
    review_content TEXT,
    review_score FLOAT,
    sentiment_score FLOAT,
    sentiment_label VARCHAR(20),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (hotel_id) REFERENCES hotel_info(hotel_id),
    INDEX idx_hotel_score (hotel_id, review_score),
    INDEX idx_sentiment (sentiment_label)
);

🎯 总结

本项目成功实现了一个完整的酒店数据分析推荐系统,具有以下特点:

技术成就

  1. 深度学习集成:成功将BERT模型集成到Django应用中,实现中文评论情感分析
  2. 推荐算法优化:实现了基于协同过滤的混合推荐算法,提供个性化推荐
  3. 数据可视化:使用ECharts实现了丰富的数据可视化展示
  4. 系统架构:采用模块化设计,易于维护和扩展

业务价值

  1. 数据驱动决策:为酒店行业提供数据分析和决策支持
  2. 用户体验提升:通过个性化推荐提升用户满意度
  3. 运营效率:自动化数据分析和报告生成,提高运营效率
  4. 市场洞察:通过情感分析了解客户真实需求和反馈

技术亮点

  • BERT模型应用:在中文NLP领域的成功实践
  • 推荐系统:多算法融合的推荐策略
  • 数据可视化:交互式图表展示
  • 系统集成:前后端完整的技术栈集成

这个项目展示了如何将现代AI技术与传统Web开发相结合,构建出具有实际商业价值的应用系统。通过持续的技术迭代和功能完善,该系统有望在酒店行业发挥更大的价值。


📞 联系方式

码界筑梦坊 - 各大平台同名


本文档持续更新中,如有问题欢迎交流讨论!

最后更新时间:2025年10月

相关推荐
Cherry Zack4 小时前
Django视图进阶:快捷函数、装饰器与请求响应
后端·python·django
花菜会噎住4 小时前
Django视图与路由全解析:从URL到页面,一篇讲透
数据库·django·sqlite·函数
qq_4924484465 小时前
Jmeter设置负载阶梯式压测场景(详解教程)
开发语言·python·jmeter
lianyinghhh5 小时前
瓦力机器人-舵机控制(基于树莓派5)
人工智能·python·自然语言处理·硬件工程
Mike_Zhang6 小时前
python3.14版本的free-threading功能体验
python
StarPrayers.6 小时前
旅行商问题(TSP)(2)(heuristics.py)(TSP 的两种贪心启发式算法实现)
前端·人工智能·python·算法·pycharm·启发式算法
Bony-6 小时前
奶茶销售数据分析
人工智能·数据挖掘·数据分析·lstm
木头左6 小时前
波动率聚类现象对ETF网格密度配置的启示与应对策略
python
小咕聊编程7 小时前
【含文档+PPT+源码】基于SpringBoot+Gpt个人健康管理系统
java·gpt·tomcat·毕业设计·hibernate