后端基于Python 开源的 Web 框架 Flask,前端页面采用 LayUI 框架以及 Echarts 图表,数据库为sqlite。系统的功能模块分为数据采集和存储模块、数据处理和分析模块、可视化展示模块和系统管理模块。情感分析方面使用LDA等主题建模技术,结合领域特定词汇进行优化。有可视化大屏。
实现的结果如图所示:
项目工程目录:
具体实现步骤:
一、app.py 后端核心代码
# app.py 后端核心代码
from flask import Flask, render_template, jsonify
import sqlite3
from collections import defaultdict
import jieba
import re
app = Flask(__name__)
# 自定义情感词典(示例)
sentiment_words = {
'好': 'positive', '不错': 'positive', '推荐': 'positive',
'差': 'negative', '难吃': 'negative', '投诉': 'negative'
}
# 数据库连接
def get_db():
conn = sqlite3.connect('reviews.db')
conn.row_factory = sqlite3.Row
return conn
# 情感分析函数
def analyze_sentiment(text):
positive = negative = 0
words = jieba.lcut(text)
for word in words:
if word in sentiment_words:
if sentiment_words[word] == 'positive':
positive += 1
else:
negative += 1
if positive > negative:
return 'positive'
elif negative > positive:
return 'negative'
else:
return 'neutral'
# 路由定义
@app.route('/')
def dashboard():
return render_template('dashboard.html')
# 情感分布数据接口
@app.route('/api/sentiment')
def sentiment_data():
conn = get_db()
cursor = conn.cursor()
cursor.execute('SELECT sentiment, COUNT(*) FROM reviews GROUP BY sentiment')
data = {row[0]: row[1] for row in cursor.fetchall()}
conn.close()
return jsonify(data)
# 评分分布接口
@app.route('/api/score_dist')
def score_dist():
conn = get_db()
cursor = conn.execute('''
SELECT score, COUNT(*) as count
FROM reviews
GROUP BY score ORDER BY score
''')
result = [{'score': row[0], 'count': row[1]} for row in cursor]
conn.close()
return jsonify(result)
# 分类统计接口
@app.route('/api/category_stats')
def category_stats():
conn = get_db()
cursor = conn.execute('''
SELECT category, COUNT(*) as count, AVG(score) as avg_score
FROM reviews
GROUP BY category
''')
result = [{
'category': row[0],
'count': row[1],
'avg_score': round(row[2], 1)
} for row in cursor]
conn.close()
return jsonify(result)
# 关键词提取接口
@app.route('/api/keywords/<type>')
def keywords(type):
conn = get_db()
cursor = conn.execute('SELECT content FROM reviews')
texts = [row[0] for row in cursor.fetchall()]
# 关键词提取逻辑
keywords = []
pattern = re.compile(r'服务|态度|热情' if type == 'service' else r'味道|口感|食材')
for text in texts:
words = jieba.lcut(text)
keywords.extend([w for w in words if pattern.search(w)])
# 统计词频
freq = defaultdict(int)
for word in keywords:
freq[word] += 1
return jsonify([{'name': k, 'value': v} for k, v in freq.items()])
if __name__ == '__main__':
app.run(debug=True)
二、前端代码
<!-- templates/dashboard.html 前端页面 -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>数据可视化分析系统</title>
<link rel="stylesheet" href="/static/layui/css/layui.css">
<script src="/static/echarts.min.js"></script>
<script src="/static/layui/layui.js"></script>
</head>
<body>
<div class="layui-container">
<!-- 情感分布 -->
<div class="layui-row">
<div class="layui-col-md6">
<div id="sentimentChart" style="height:400px"></div>
</div>
<div class="layui-col-md6">
<div id="scoreChart" style="height:400px"></div>
</div>
</div>
<!-- 分类统计 -->
<div class="layui-row">
<div id="categoryChart" style="height:400px"></div>
</div>
<!-- 关键词云 -->
<div class="layui-row">
<div class="layui-col-md6">
<div id="serviceWordcloud" style="height:300px"></div>
</div>
<div class="layui-col-md6">
<div id="tasteWordcloud" style="height:300px"></div>
</div>
</div>
</div>
<script>
layui.use(function(){
const $ = layui.$;
// 情感分布饼图
const sentimentChart = echarts.init(document.getElementById('sentimentChart'));
$.get('/api/sentiment', function(data){
sentimentChart.setOption({
title: { text: '评论情感分布' },
series: [{
type: 'pie',
data: Object.entries(data).map(([name, value]) => ({name, value}))
}]
});
});
// 评分分布直方图
const scoreChart = echarts.init(document.getElementById('scoreChart'));
$.get('/api/score_dist', function(data){
scoreChart.setOption({
title: { text: '评分分布' },
xAxis: { data: data.map(d => d.score) },
yAxis: { type: 'value' },
series: [{
type: 'bar',
data: data.map(d => d.count)
}]
});
});
// 分类统计柱状图
const categoryChart = echarts.init(document.getElementById('categoryChart'));
$.get('/api/category_stats', function(data){
categoryChart.setOption({
title: { text: '店铺分类统计' },
tooltip: { trigger: 'axis' },
xAxis: { data: data.map(d => d.category) },
yAxis: [{ type: 'value', name: '评论量' }],
series: [{
name: '评论量',
type: 'bar',
data: data.map(d => d.count)
}]
});
});
// 服务态度词云
const serviceWC = echarts.init(document.getElementById('serviceWordcloud'));
$.get('/api/keywords/service', function(data){
serviceWC.setOption({
title: { text: '服务态度关键词' },
series: [{
type: 'wordCloud',
data: data
}]
});
});
// 菜品口味词云
const tasteWC = echarts.init(document.getElementById('tasteWordcloud'));
$.get('/api/keywords/taste', function(data){
tasteWC.setOption({
title: { text: '菜品口味关键词' },
series: [{
type: 'wordCloud',
data: data
}]
});
});
});
</script>
</body>
</html>
三、系统运行说明:
-
需要安装的依赖:
bash
pip install flask jieba
-
目录结构:
├── app.py ├── templates │ └── dashboard.html └── static├── layui│ ├── css│ └── js└── echarts.min.js
四、创建DB,插入数据:
import sqlite3 from flask import jsonify#insert data to DB. def get_db():conn = sqlite3.connect('reviews.db')cursor = conn.cursor()# 创建表create_table_sql = """CREATE TABLE IF NOT EXISTS reviews (id INTEGER PRIMARY KEY,content TEXT,score INTEGER,category TEXT,region TEXT,sentiment TEXT);"""cursor.execute(create_table_sql)conn.commit() # 提交事务# 插入一些示例数据insert_data_sql = """INSERT INTO reviews (id,content, score, category, region, sentiment)VALUES (1,'这家店的环境非常好,服务也很周到,菜品味道更是一流!', 5, '中餐', '北京', '正面'),(2,'菜品口味太一般了,没什么特色,价格还贵。', 2, '西餐', '上海', '负面');"""cursor.execute(insert_data_sql)conn.commit() # 提交事务cursor.execute('SELECT sentiment, COUNT(*) FROM reviews GROUP BY sentiment')data = {row[0]: row[1] for row in cursor.fetchall()}print("这是output: "+jsonify(data))conn.row_factory = sqlite3.Rowreturn conn def main():conn = get_db()cursor = conn.cursor()print("这是主函数的内容。")if __name__ == "__main__":main()