后端基于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()