1. 项目概述:京东手机数据可视化与推荐系统
这个毕业设计项目完美结合了电商数据分析与Python技术栈,通过爬取京东手机商品数据,构建了一个完整的Flask Web应用。系统不仅能直观展示手机市场的价格分布、品牌占比等关键指标,还能基于用户行为数据实现个性化推荐。对于计算机专业的学生而言,这类项目既能展示扎实的编程功底,又体现了解决实际商业问题的能力。
我在实际开发中发现,这类电商数据分析系统最考验三个核心能力:一是高效稳定的数据采集(避免被封禁),二是清晰直观的可视化呈现,三是推荐算法的实用性与解释性。下面我就从技术选型到实现细节,完整拆解这个项目的开发全流程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体技术栈选择
前端部分:
- Flask框架:轻量级Web开发首选,模板渲染灵活
- PyEcharts:百度开源的动态可视化库,支持丰富的图表类型
- Bootstrap:快速构建响应式管理界面
后端部分:
- Requests+BeautifulSoup:处理京东页面数据抓取
- Pandas+Numpy:进行数据清洗与分析
- Scikit-learn:构建推荐算法模型
- SQLite/MySQL:数据存储方案
提示:初学者建议先用SQLite开发,后期再迁移到MySQL。我在第一次部署时就因为MySQL权限配置浪费了半天时间。
2.2 系统模块划分
-
数据采集模块:
- 手机商品信息爬虫
- 用户评论抓取子系统
- 反爬虫策略处理
-
数据分析模块:
- 价格区间分布统计
- 品牌市场占有率计算
- 商品参数关联分析
-
可视化模块:
- 动态仪表盘
- 多维筛选器
- 图表导出功能
-
推荐模块:
- 基于内容的推荐
- 协同过滤算法
- 混合推荐策略
3. 核心实现细节
3.1 京东数据爬虫开发
京东的反爬机制相当严格,直接请求商品页面很容易触发429错误。经过多次测试,我总结出这套稳定采集方案:
python复制import requests
from bs4 import BeautifulSoup
import random
import time
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Referer': 'https://www.jd.com/'
}
def crawl_jd_phones(page):
url = f'https://list.jd.com/list.html?cat=9987,653,655&page={page}'
try:
response = requests.get(url, headers=headers, timeout=10)
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
# 解析商品列表
items = soup.select('.gl-item')
for item in items:
# 提取价格、标题、评论数等数据
price = item.select('.p-price strong i')[0].text
title = item.select('.p-name em')[0].text.strip()
print(f'采集到:{title} - {price}元')
time.sleep(random.uniform(1, 3)) # 随机延迟防封禁
except Exception as e:
print(f'采集失败:{str(e)}')
关键注意事项:
- 必须设置随机延迟,单页采集后休眠1-3秒
- 使用真实浏览器UA头,定期更换代理IP
- 遇到验证码时自动暂停,改为手动处理
- 分批次存储数据,避免意外中断导致数据丢失
3.2 数据清洗与存储
原始采集的数据往往包含大量噪声,这是我在处理时建立的清洗规则:
python复制import pandas as pd
def clean_data(raw_df):
# 价格处理
raw_df['price'] = raw_df['price'].astype(float)
# 品牌提取(从标题中识别)
brands = ['华为', '小米', '苹果', 'OPPO', 'vivo', '荣耀']
raw_df['brand'] = raw_df['title'].apply(
lambda x: next((b for b in brands if b in x), '其他'))
# 内存规格提取(如8GB+128GB)
raw_df['memory'] = raw_df['title'].str.extract(r'(\d+GB\+\d+GB)')
return raw_df.drop_duplicates('product_id')
存储到数据库时建议采用这样的表结构设计:
sql复制CREATE TABLE phones (
id INTEGER PRIMARY KEY,
title TEXT NOT NULL,
price REAL,
brand TEXT,
memory TEXT,
comments INTEGER,
good_rate REAL,
update_time DATETIME DEFAULT CURRENT_TIMESTAMP
);
4. 可视化系统实现
4.1 Flask应用骨架
python复制from flask import Flask, render_template
import pandas as pd
from pyecharts import options as opts
from pyecharts.charts import Bar
app = Flask(__name__)
@app.route('/')
def dashboard():
# 从数据库加载数据
df = pd.read_sql('SELECT * FROM phones', con=db_engine)
# 生成品牌分布柱状图
brand_dist = df['brand'].value_counts()
bar = (
Bar()
.add_xaxis(brand_dist.index.tolist())
.add_yaxis("品牌分布", brand_dist.values.tolist())
.set_global_opts(title_opts=opts.TitleOpts(title="手机品牌分布"))
)
return render_template('index.html',
brand_dist=bar.dump_options())
if __name__ == '__main__':
app.run(debug=True)
4.2 前端模板集成
在templates/index.html中:
html复制<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>京东手机数据分析</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
</head>
<body>
<div id="brand-chart" style="width: 900px;height:400px;"></div>
<script>
var brandChart = echarts.init(document.getElementById('brand-chart'));
var option = {{ brand_dist|safe }};
brandChart.setOption(option);
</script>
</body>
</html>
4.3 高级可视化技巧
- 联动筛选:使用PyEcharts的connect()方法实现图表联动
- 数据下钻:点击品牌柱状图后显示该品牌各型号分布
- 动态更新:通过Flask-SocketIO实现实时数据推送
python复制# 价格分布玫瑰图示例
from pyecharts.charts import Pie
def price_rose(df):
bins = [0, 1000, 2000, 3000, 4000, 5000, float('inf')]
labels = ['千元机', '1000-2000', '2000-3000', '3000-4000', '4000-5000', '旗舰机']
df['price_group'] = pd.cut(df['price'], bins=bins, labels=labels)
pie = (
Pie()
.add("", [list(z) for z in zip(labels, df['price_group'].value_counts())])
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {c} ({d}%)"))
.set_global_opts(title_opts=opts.TitleOpts(title="价格区间分布"))
)
return pie
5. 推荐算法实现
5.1 基于内容的推荐
python复制from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import linear_kernel
def content_based_recommend(product_id, n=5):
# 从数据库加载所有商品数据
df = pd.read_sql('SELECT * FROM phones', con=db_engine)
# 构建特征矩阵
tfidf = TfidfVectorizer(stop_words=['手机'])
tfidf_matrix = tfidf.fit_transform(df['title'] + " " + df['brand'])
# 计算相似度
cosine_sim = linear_kernel(tfidf_matrix, tfidf_matrix)
idx = df[df['product_id']==product_id].index[0]
sim_scores = list(enumerate(cosine_sim[idx]))
sim_scores = sorted(sim_scores, key=lambda x: x[1], reverse=True)
# 返回TopN推荐
sim_scores = sim_scores[1:n+1]
product_indices = [i[0] for i in sim_scores]
return df.iloc[product_indices]
5.2 协同过滤改进
当积累足够用户行为数据后,可以升级为协同过滤算法:
python复制from surprise import Dataset, KNNBasic
from surprise.model_selection import train_test_split
def collab_filter(user_id):
# 加载评分数据
reader = Reader(line_format='user item rating', sep=',')
data = Dataset.load_from_file('ratings.csv', reader=reader)
# 训练模型
trainset, testset = train_test_split(data, test_size=0.25)
algo = KNNBasic(sim_options={'user_based': False})
algo.fit(trainset)
# 生成推荐
test_subject = user_id
predictions = algo.test(testset)
user_pred = [pred for pred in predictions if pred.uid == test_subject]
return sorted(user_pred, key=lambda x: x.est, reverse=True)[:5]
6. 部署与优化
6.1 性能优化技巧
-
数据库索引:为常用查询字段创建索引
sql复制CREATE INDEX idx_brand ON phones(brand); CREATE INDEX idx_price ON phones(price); -
缓存策略:对可视化结果进行缓存
python复制from flask_caching import Cache cache = Cache(config={'CACHE_TYPE': 'SimpleCache'}) cache.init_app(app) @app.route('/dashboard') @cache.cached(timeout=300) # 缓存5分钟 def dashboard(): # 生成可视化图表 -
异步任务:将爬虫任务放入Celery队列
python复制@celery.task def async_crawl(page): crawl_jd_phones(page)
6.2 常见问题解决
问题1:PyEcharts图表不显示
- 检查前端是否加载了正确版本的Echarts.js
- 确认dump_options()后的JSON数据格式正确
- 查看浏览器控制台是否有JavaScript错误
问题2:爬虫被封禁
- 增加代理IP池
- 降低请求频率
- 模拟鼠标移动等人类操作特征
问题3:推荐结果不合理
- 检查特征工程是否捕捉了关键属性
- 尝试调整相似度计算方式
- 收集更多用户反馈数据
这个项目最让我有成就感的部分是看到可视化图表真实反映市场规律的那一刻。比如通过价格分布图发现2000-3000元价位竞争最激烈,而各品牌在不同内存配置上的定价策略差异等。这些洞察如果结合商业分析,完全可以转化为实际的运营决策支持。
