做电商数据分析时大家经常遇到一个问题数据拿到了报表也做出来了但下一步该怎么办销量为什么波动哪些商品值得补货下个月大概能卖多少这些问题光靠 Excel 透视表已经很难回答。本文结合实际项目经验讲清楚一条完整的链路Python 爬虫采集数据 - pandas 清洗处理 - 可视化分析与词云图 - 机器学习销量预测 - Django 框架整合展示。整个过程会给出可直接运行的代码并说明每一步的思考方式和常见坑点适合想系统掌握电商数据分析全流程的开发者参考。1. 项目背景为什么把 Django、爬虫、机器学习放在一起1.1 电商数据分析的核心诉求电商数据分析通常可以分为三个层次描述性分析过去卖得怎么样。比如销售额趋势、地区销量分布、Top 商品排名。诊断性分析为什么卖得好或不好。比如价格变动、促销活动、用户评价关键词。预测性分析接下来会怎么样。比如未来一周的销量区间、滞销品预警、安全库存建议。很多初学者只停留在第一层会画几个柱状图和折线图就觉得任务完成。但在真实业务中真正有价值的是从“描述过去”走向“预测未来”。本文要做的就是打通这三个层次。1.2 技术选型思路技术栈的选型原则是“每个环节用最合适的工具”Python数据分析生态最完善pandas、scikit-learn、matplotlib 都是成熟库。Django自带 ORM、模板引擎、Admin 后台适合把分析结果封装成 Web 应用让运营人员通过浏览器查看而不是每次跑脚本。爬虫电商数据通常分散在页面和接口中用 requests BeautifulSoup 可以按需采集。机器学习销量预测本质上是一个回归问题scikit-learn 中的线性回归、随机森林、梯度提升树都可以作为基线模型。词云图把用户评论、商品标题中的高频词可视化快速理解用户关注点。这套组合有一个明显优势从数据采集到模型部署全部使用 Python 完成中间环节不需要切换语言降低了维护成本。1.3 项目整体流程整个项目的流程可以拆成下面几步数据采集编写爬虫获取商品信息、评论数据或使用模拟数据兜底。数据清洗处理缺失值、重复值、异常值统一日期和数值格式。特征工程从日期中提取星期、月份、是否节假日等特征。数据分析统计销量趋势、商品贡献度、价格区间分布。词云图对评论或商品标题做分词和词频统计。模型训练训练销量预测模型评估误差并保存模型。Web 集成通过 Django 展示数据分析图表和预测结果。下面从环境准备开始逐步实现。2. 环境准备与项目初始化2.1 环境说明本文示例在 Windows 11 下完成Python 版本为 3.10。不同操作系统和 Python 版本的命令略有差异但整体流程一致。如果你是 Mac 或 Linux 用户把虚拟环境激活命令改成source venv/bin/activate即可。版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。2.2 创建虚拟环境与安装依赖Django 项目依赖较多强烈建议使用虚拟环境避免污染全局 Python 环境。mkdir ecommerce-analysis cd ecommerce-analysis python -m venv venv venv\Scripts\activate激活虚拟环境后安装依赖pip install django pandas numpy matplotlib seaborn scikit-learn wordcloud jieba requests beautifulsoup4这里简单说明每个库的用途djangoWeb 框架负责页面展示和路由。pandas / numpy数据处理和数值计算。matplotlib / seaborn绘制图表。scikit-learn机器学习模型训练与评估。wordcloud / jieba生成中文词云图。requests / beautifulsoup4爬虫请求与解析。如果安装 wordcloud 时提示缺少 VC 编译环境可以到 PyPI 上下载对应 Python 版本的 whl 文件离线安装。2.3 创建 Django 项目与 App依赖安装完成后创建 Django 项目和子应用django-admin startproject ecommerce_project cd ecommerce_project python manage.py startapp analysis然后修改ecommerce_project/settings.py在INSTALLED_APPS中注册 analysisINSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, analysis, ]2.4 项目目录结构完成初始化后目录结构大致如下ecommerce-analysis/ ├── venv/ ├── ecommerce_project/ │ ├── ecommerce_project/ │ │ ├── __init__.py │ │ ├── settings.py │ │ ├── urls.py │ │ └── wsgi.py │ └── analysis/ │ ├── migrations/ │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── tests.py │ └── views.py ├── data/ ├── scripts/ ├── static/ └── templates/后续的数据文件统一放在data目录分析脚本放在scripts目录图表和词云图输出到static目录。3. 数据采集爬虫模块设计3.1 爬虫的合法性与边界在编写爬虫之前必须先明确几个原则只能采集公开数据不能绕过登录、验证码等访问控制机制。遵守目标网站的 robots.txt 协议。控制请求频率不要对目标服务器造成压力。采集到的数据只能用于学习研究或个人项目不能用于商业用途或侵犯用户隐私。如果你只是学习技术更推荐使用公开数据集或自己构造模拟数据。本文后面的演示会同时提供爬虫示例和模拟数据生成代码方便你切换数据源。3.2 基础爬虫示例下面的代码演示如何抓取一个商品列表页的标题和价格。注意这里用占位 URL 代替真实网站实际使用时请替换成你有权采集的目标地址。# scripts/spider.py import requests from bs4 import BeautifulSoup import pandas as pd def fetch_product_list(url): headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36 } resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() resp.encoding resp.apparent_encoding soup BeautifulSoup(resp.text, html.parser) products [] # 这里的选择器需要根据目标页面结构调整 for item in soup.select(.product-item): title item.select_one(.title) price item.select_one(.price) products.append({ title: title.get_text(stripTrue) if title else , price: float(price.get_text(stripTrue).replace(¥, )) if price else None }) return pd.DataFrame(products) if __name__ __main__: # 仅作为示例请替换为你有权采集的地址 df fetch_product_list(https://example.com/products) print(df.head())这个示例的核心逻辑是先用 requests 获取页面内容再用 BeautifulSoup 解析 HTML 结构最后把数据整理成 DataFrame。3.3 构造模拟数据兜底真实项目中爬虫经常会因为页面改版、反爬策略调整而失效。为了保证后续分析和模型训练不中断我习惯准备一份模拟数据生成脚本。以电商订单数据为例# scripts/generate_data.py import pandas as pd import numpy as np from datetime import datetime, timedelta np.random.seed(42) start_date datetime(2024, 1, 1) dates [start_date timedelta(daysi) for i in range(365)] products { A001: {name: 无线耳机, price: 199}, A002: {name: 智能手环, price: 149}, A003: {name: 便携充电宝, price: 89}, A004: {name: 蓝牙音箱, price: 259}, A005: {name: 运动水杯, price: 59}, } records [] for date in dates: for pid, info in products.items(): # 模拟销量周末销量更高产品基础销量不同 base {A001: 120, A002: 80, A003: 60, A004: 45, A005: 100}[pid] weekend_factor 1.3 if date.weekday() 5 else 1.0 random_factor np.random.uniform(0.85, 1.15) sales int(base * weekend_factor * random_factor) records.append({ date: date.strftime(%Y-%m-%d), product_id: pid, product_name: info[name], price: info[price], sales: sales, revenue: sales * info[price], }) df pd.DataFrame(records) df.to_csv(data/order_sales.csv, indexFalse, encodingutf-8-sig) print(df.head())生成的数据包含 365 天、5 个商品的日销量和销售额这个数据规模足够完成趋势分析、特征工程和模型训练。4. 数据清洗与预处理4.1 读取与查看数据无论是爬虫结果还是模拟数据拿到手后的第一步都是先读入并检查数据情况。import pandas as pd df pd.read_csv(data/order_sales.csv) print(df.shape) print(df.dtypes) print(df.head())运行后可以看到(1825, 6) date object product_id object product_name object price int64 sales int64 revenue int64 dtype: object4.2 缺失值与重复值处理真实数据通常存在缺失和重复问题。建议按下面的顺序处理# 查看缺失值 print(df.isnull().sum()) # 查看重复值 print(df.duplicated().sum()) # 删除完全重复的行 df df.drop_duplicates() # 删除关键字段为空的记录 df df.dropna(subset[date, product_id, sales]) # 数值字段缺失用中位数填充 df[sales].fillna(df[sales].median(), inplaceTrue) df[price].fillna(df[price].median(), inplaceTrue)这里要注意删除重复行时建议先确认哪些字段的组合算作“唯一记录”。对于订单明细数据通常是“订单号 商品编码”对于日销量汇总数据则是“日期 商品编码”。如果只看整行是否重复可能漏掉部分错误数据。4.3 类型转换与特征构造日期字段需要从字符串转成 datetime 类型方便后续按时间统计df[date] pd.to_datetime(df[date]) # 提取日期特征 df[year] df[date].dt.year df[month] df[date].dt.month df[weekday] df[date].dt.weekday df[is_weekend] df[weekday].isin([5, 6]).astype(int) df[day_of_month] df[date].dt.day这些日期特征在后面的机器学习模型中非常有用尤其“是否周末”对电商销量有明显影响。5. 数据分析与可视化5.1 销量趋势分析数据清洗完成后先做整体趋势分析。按日期汇总全店销量和销售额import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False daily df.groupby(date, as_indexFalse).agg( total_sales(sales, sum), total_revenue(revenue, sum) ) # 绘制销量趋势图 plt.figure(figsize(12, 5)) sns.lineplot(datadaily, xdate, ytotal_sales) plt.title(全店日销量趋势) plt.xlabel(日期) plt.ylabel(销量) plt.tight_layout() plt.savefig(static/sales_trend.png, dpi150) plt.show()从趋势图中可以看出是否存在明显的周期波动。通常电商数据会有两个特征一是周末销量高于工作日二是如果存在大促节点会出现尖峰。后续建模时要把这些周期特征纳入考虑。5.2 商品维度分析再看商品维度的对比。计算每个商品的总销量、总销售额和平均日销量product_summary df.groupby(product_id).agg( total_sales(sales, sum), total_revenue(revenue, sum), avg_sales(sales, mean) ).reset_index() print(product_summary.sort_values(total_sales, ascendingFalse))为了更直观可以用柱状图展示商品销量对比plt.figure(figsize(10, 5)) sns.barplot(dataproduct_summary, xproduct_id, ytotal_sales) plt.title(各商品总销量对比) plt.tight_layout() plt.savefig(static/product_sales_bar.png, dpi150) plt.show()这一步的分析价值在于识别主力商品和长尾商品。主力商品需要保证库存充足长尾商品可以适当减少采购降低库存成本。5.3 词云图生成词云图适合展示商品标题、用户评论中的高频词。先准备一段文本来源可以是爬虫抓取的商品描述也可以是用户评论。下面是基于模拟评论数据的示例# scripts/wordcloud_demo.py import jieba import matplotlib.pyplot as plt from wordcloud import WordCloud comments [ 音质很好无线连接稳定佩戴舒适, 续航能力强充电速度快性价比高, 外观设计好看运动时佩戴不容易掉落, 降噪效果不错通勤路上很实用, 包装精美客服态度好物流很快, 操作简单连接手机很方便信号稳定, ] # 使用 jieba 分词 text .join(comments) words jieba.lcut(text) filtered_words .join( [w for w in words if len(w) 1 and w not in [很好, 不错, 可以]] ) # 设置中文字体路径Windows 使用 SimHei font_path C:/Windows/Fonts/simhei.ttf wc WordCloud( font_pathfont_path, width800, height600, background_colorwhite, max_words100, ).generate(filtered_words) plt.figure(figsize(10, 8)) plt.imshow(wc, interpolationbilinear) plt.axis(off) plt.tight_layout() plt.savefig(static/comment_wordcloud.png, dpi150) plt.show()如果你的系统没有 SimHei 字体可以换成其他中文字体路径或者在 Linux 服务器上先安装中文字体包。词云图的价值不是“好看”而是快速发现用户评价中集中的关键词。例如“音质”“续航”“舒适”出现频率高说明这些是用户最在意的卖点。6. 销量预测模型6.1 特征工程销量预测的输入特征需要从日期和商品属性中提取。这里以单个商品为例构建一个以“日期特征 商品价格”为输入、销量为输出的回归模型。# scripts/train_model.py import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, r2_score import joblib df pd.read_csv(data/order_sales.csv) df[date] pd.to_datetime(df[date]) # 只取一个商品做演示 one_product df[df[product_id] A001].copy() # 构造特征 one_product[year] one_product[date].dt.year one_product[month] one_product[date].dt.month one_product[weekday] one_product[date].dt.weekday one_product[is_weekend] one_product[weekday].isin([5, 6]).astype(int) one_product[day_of_month] one_product[date].dt.day # 添加滞后特征前一天的销量用于捕捉近期趋势 one_product one_product.sort_values(date) one_product[lag_1] one_product[sales].shift(1) one_product one_product.dropna() features [month, weekday, is_weekend, day_of_month, price, lag_1] X one_product[features] y one_product[sales] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, shuffleFalse )这里使用shuffleFalse因为时间序列数据不能随机打乱否则会引入未来信息泄漏导致评估结果虚高。6.2 模型选择与训练随机森林对表格数据的拟合能力较强不需要做太多数据标准化适合作为基线模型。model RandomForestRegressor( n_estimators200, max_depth8, random_state42 ) model.fit(X_train, y_train) y_pred model.predict(X_test) print(fMAE: {mean_absolute_error(y_test, y_pred):.2f}) print(fR2: {r2_score(y_test, y_pred):.4f})输出示例MAE: 18.36 R2: 0.8732MAE 表示平均绝对误差为 18 件左右。对于日销量在 100 到 160 之间的商品来说这个误差是可接受的。如果误差过大可以考虑增加更多特征比如 7 天滑动平均、节假日标记、促销标记等。6.3 模型评估与保存为了检查模型是否学到了趋势可以把预测值和真实值画在同一张图上import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) plt.plot(y_test.values, label真实值) plt.plot(y_pred, label预测值) plt.legend() plt.title(销量预测结果对比) plt.tight_layout() plt.savefig(static/prediction_compare.png, dpi150) plt.show()模型训练完成后使用 joblib 保存之后 Django 就可以直接加载模型joblib.dump(model, data/sales_model.joblib)同时保存特征列表方便预测时保持一致import json with open(data/feature_names.json, w, encodingutf-8) as f: json.dump(features, f, ensure_asciiFalse, indent2)7. Django 集成与页面展示7.1 配置静态文件与模板在settings.py中设置静态文件目录和模板目录import os BASE_DIR os.path.dirname(os.path.dirname(os.path.abspath(__file__))) STATICFILES_DIRS [ os.path.join(BASE_DIR, static), ] TEMPLATES [ { BACKEND: django.template.backends.django.DjangoTemplates, DIRS: [os.path.join(BASE_DIR, templates)], APP_DIRS: True, OPTIONS: { context_processors: [ django.template.context_processors.debug, django.template.context_processors.request, django.contrib.auth.context_processors.auth, django.contrib.messages.context_processors.messages, ], }, }, ]在前面的步骤中图表已经保存到static目录模板中可以直接引用。7.2 设计视图函数views.py中编写一个聚合页面把静态图表和模型预测结果展示出来。# analysis/views.py import json import joblib import pandas as pd from django.shortcuts import render def load_model(): model joblib.load(data/sales_model.joblib) with open(data/feature_names.json, r, encodingutf-8) as f: features json.load(f) return model, features def index(request): return render(request, analysis/index.html) def report_view(request): model, features load_model() # 构造未来 7 天的特征数据 import datetime today datetime.date.today() future_dates [today datetime.timedelta(daysi) for i in range(1, 8)] predict_data [] for d in future_dates: sample pd.DataFrame([{ month: d.month, weekday: d.weekday(), is_weekend: 1 if d.weekday() 5 else 0, day_of_month: d.day, price: 199, lag_1: 120, }]) pred model.predict(sample[features])[0] predict_data.append({ date: d.strftime(%Y-%m-%d), pred_sales: round(pred, 1), }) context { predict_data: predict_data, sales_trend_chart: /static/sales_trend.png, product_bar_chart: /static/product_sales_bar.png, wordcloud_chart: /static/comment_wordcloud.png, prediction_chart: /static/prediction_compare.png, } return render(request, analysis/report.html, context)这里要注意模型训练时使用了“滞后1天销量”作为特征真实预测未来时第一天的滞后值需要手动指定或用最近一天的真实销量替代后续天数的滞后值可以用前一天的预测值填充。示例代码为了演示逻辑简洁手动填了 120实际项目中需要封装一个滚动预测函数。7.3 页面模板示例创建templates/analysis/report.html!DOCTYPE html html langzh-CN head meta charsetUTF-8 title电商数据分析报告/title style body { font-family: Microsoft YaHei, sans-serif; margin: 40px; } .chart-item { margin-bottom: 40px; } .chart-item img { max-width: 100%; border: 1px solid #eee; border-radius: 8px; } table { border-collapse: collapse; width: 60%; } th, td { border: 1px solid #ddd; padding: 8px 16px; text-align: center; } /style /head body h2电商数据分析报告/h2 h3未来 7 天销量预测/h3 table tr th日期/th th预测销量/th /tr {% for item in predict_data %} tr td{{ item.date }}/td td{{ item.pred_sales }}/td /tr {% endfor %} /table div classchart-item h3全店销量趋势/h3 img src{{ sales_trend_chart }} alt销量趋势 /div div classchart-item h3各商品总销量对比/h3 img src{{ product_bar_chart }} alt商品销量对比 /div div classchart-item h3评论词云图/h3 img src{{ wordcloud_chart }} alt评论词云图 /div div classchart-item h3预测结果对比/h3 img src{{ prediction_chart }} alt预测结果对比 /div /body /html7.4 路由配置与运行在ecommerce_project/urls.py中配置路由from django.contrib import admin from django.urls import path from analysis import views urlpatterns [ path(admin/, admin.site.urls), path(, views.index), path(report/, views.report_view), ]运行开发服务器python manage.py runserver浏览器访问http://127.0.0.1:8000/report/即可看到包含预测表格和各类图表的数据分析报告页面。8. 常见问题与排查思路问题现象常见原因解决思路中文图表显示方块matplotlib 或 seaborn 未配置中文字体设置plt.rcParams[font.sans-serif] [SimHei]并配置axes.unicode_minus False词云图中文乱码WordCloud 未指定中文字体路径设置font_pathC:/Windows/Fonts/simhei.ttfLinux 可指定其他中文字体路径Django 页面看不到图表静态文件目录配置错误检查STATICFILES_DIRS是否指向正确目录确认图片实际存在模型预测结果偏差大特征泄漏或滞后特征使用不当时间序列切分时使用shuffleFalse预测未来时需滚动填充滞后值爬虫请求被拒绝请求头缺少 User-Agent或请求频率过高补充请求头、降低请求频率、增加随机延时安装 wordcloud 失败缺少 VC 编译环境下载对应 Python 版本的 whl 文件离线安装pandas 读 CSV 日期变成字符串未使用parse_dates参数或未执行pd.to_datetime读取时指定parse_dates[date]9. 最佳实践与工程建议9.1 爬虫合规与数据安全采集电商数据前先确认目标网站的服务条款和 robots.txt。不要把爬虫请求频率设得过高建议在两次请求之间加入随机延时。对于包含用户个人信息的数据采集后要做脱敏处理不能把原数据直接展示到页面或提交到公开仓库。9.2 模型版本管理模型不是训练一次就结束的。电商数据会随着季节、促销、竞争环境变化而漂移建议定期用最近数据重新训练模型并把模型文件按版本命名保存data/ ├── sales_model_v1.joblib ├── sales_model_v2.joblib └── sales_model_v3.joblib每次重新训练后用相同测试集对比新旧模型的 MAE确保新模型没有退化再切换到线上。9.3 Django 生产部署注意事项开发服务器runserver只适合本地调试。部署到生产环境时推荐使用 Gunicorn Nginx 的组合并且注意三点关闭 DEBUG 模式DEBUG False否则会暴露详细报错信息。使用环境变量管理数据库密码、SECRET_KEY 等敏感配置。静态文件使用 Nginx 直接托管不经过 Django减少应用层压力。9.4 可扩展方向本文实现的是一个最小可用闭环实际项目中还可以扩展以下方向接入数据库替代 CSV 文件Django ORM 天然支持 MySQL、PostgreSQL。增加更丰富的时间特征节假日、大促日、气温等外部变量。尝试 LightGBM、XGBoost 等梯度提升模型对比随机森林的效果。用 Prophet 或 ARIMA 做时间序列基线模型。增加用户画像分析和复购预测模型把分析从商品维度扩展到用户维度。动手实践时建议先把模拟数据链路跑通再逐步替换成真实数据。这样既能验证每个环节的代码逻辑又能避免在数据质量问题上卡住。如果你在跑代码时遇到其他报错欢迎对照上面的排查思路逐项检查大部分问题都出在中文编码、静态文件路径和特征顺序这三个环节上。