做电商数据分析的人,迟早会撞上同一个问题:订单表、评论表、流量报表堆在眼前,但真正要回答的往往是“下一步怎么办”。库存要补多少,下一轮活动的主力品放哪几个,差评里集中暴露的问题是什么……如果只靠 Excel 手动透视,不是算不出来,而是每一次复盘都要把同样的清洗、统计、画图重复一遍。
Python、Django、数据分析、爬虫、机器学习这组词放在一起,很多人第一反应是“我要做一个大而全的电商数据中台”。但我的判断是:这个组合的真正价值,不是做出某个漂亮大屏,而是帮你把一条从数据采集、清洗、可视化到销量预测的完整流程真正跑通,并且下一次可以直接复用。
这篇文章不是要把 Django 当 Web 开发框架重新讲一遍,而是把它放进一条完整的数据链路里,看它如何扮演“项目骨架”的角色。
1. 先搞清楚:这串工具组合到底解决哪类问题
1.1 电商数据分析的三个层次,别一上来就追算法
很多初学者拿到一个电商数据集,第一反应是“我要上一个很厉害的预测模型”。这个方向容易让人忽略一个前提:预测只是整条数据链路的最后一环,前面还有两层更基础的内容。
我把电商数据分析通常按三个层次理解:
| 层次 | 要回答的问题 | 典型产物 |
|---|---|---|
| 第一层:发生了什么 | 昨天的销量是多少?哪个品类卖得最好? | 报表、趋势图、排行榜 |
| 第二层:为什么会发生 | 差评集中在什么问题上?活动带来的变化有多大? | 归因分析、词云、漏斗分析 |
| 第三层:接下来会发生什么 | 下周哪个 SKU 可能缺货?下个周期的销量区间是多少? | 预测结果、补货建议 |
爬虫负责把第一层的数据源补齐,Django 负责把这些数据完整地存下来,词云和可视化负责解释第二层,机器学习模型负责回答第三层。
如果一上来就写预测代码,结果往往是:数据只有几百行,字段还缺一半,模型训练完也没法解释。更常见的情况是,数据源本身不稳定,今天跑通明天又断了。所以我觉得,把第一层和第二层先做扎实,比单独追求算法复杂度更重要。
1.2 真正的难点不在单个工具,而在把流程固定下来
你单独看这几个工具,每一个都不算新鲜。
- Python 做数据清洗,pandas 一套组合拳。
- Django 做 Web 后台和接口,社区文档非常成熟。
- 爬虫用 requests + BeautifulSoup,或者直接调公开 API。
- 词云用 jieba + wordcloud。
- 销量预测用 scikit-learn 的回归模型,或者试试 Prophet。
真正的难点是:这些工具如何在同一个项目里协作?爬虫抓下来的数据存在哪?Django 如何读取?训练好的模型怎么被页面调用?定时更新任务怎么跑?失败之后怎么重试?
如果这些环节全部靠临时脚本手动跑,那这个项目就永远是“一次性项目”。今天拿到一份 CSV,跑一遍;明天数据更新了,再改一次脚本。时间一长,你维护的不是一套系统,而是几十个不知道能不能跑的脚本。
所以这个组合的核心判断是:Python 负责数据能力,Django 负责把所有环节串成可持续使用的系统。电商数据分析的真正产出,不是某一张图,而是一套从原始数据进入系统到预测结果输出的完整流程。
2. 一条电商数据分析链路,应该怎么设计才不只是玩具
2.1 数据来源:先想清楚哪些数据能要,哪些不能碰
爬虫是这个项目里最容易出问题的环节,不是技术上的问题,而是边界问题。
做学习和个人项目时,我通常建议优先确认三个事情:
- 数据源是否有公开 API。如果有,优先用 API,而不是解析 HTML 页面。
- 数据源是否在自己的店铺后台、自有数据库,或明确开放的测试数据内。
- 请求频率是否足够克制。无论目标站点是否限制,个人练习都应该把请求间隔设得保守一些,不要给对方服务器造成压力。
对于你自己的电商店铺,最稳妥的数据来源其实是后台导出:订单明细、商品明细、售后记录、评价文本。Django 完全可以承担把这些数据导入、存储、建模和展示的工作。
如果你确实要练习爬虫,建议只在公开测试站点、自己搭建的页面、或明确允许抓取的数据源上操作。用爬虫去绕过登录、模拟身份、批量抓取受保护数据,这些事情放在个人博客和技术练习里都不合适。我在项目里一般会把“数据来源是否合规”放在整个链路的第一位,数据来源不干净,后面所有分析结果都不值得信任。
2.2 数据表结构:不要按报表设计,要按业务事实设计
很多新手喜欢把数据设计成一张大宽表:商品名称、销量、销售额、评论内容全放在一个表里。这样做在导入 Excel 时很省事,但后面做预测和归因时会非常痛苦。
我更建议按业务事实拆成几张基础表。比如商品、订单、评论各一张表,订单通过外键关联商品,评论也通过外键关联商品。
# shop/models.py from django.db import models class Product(models.Model): sku = models.CharField(max_length=64, unique=True) name = models.CharField(max_length=128) category = models.CharField(max_length=64, blank=True) class Order(models.Model): order_no = models.CharField(max_length=64, unique=True) product = models.ForeignKey( Product, on_delete=models.CASCADE, related_name="orders" ) quantity = models.PositiveIntegerField() amount = models.DecimalField(max_digits=10, decimal_places=2) order_time = models.DateTimeField(db_index=True) status = models.CharField(max_length=16, default="paid") class Review(models.Model): product = models.ForeignKey( Product, on_delete=models.CASCADE, related_name="reviews" ) content = models.TextField() rating = models.PositiveSmallIntegerField() created_at = models.DateTimeField(auto_now_add=True)这套结构至少有三个好处:
- 订单和评论是独立增长的事实数据,不会互相污染。
- 查询某品类销量时,可以直接通过商品外键关联,而不用在一张宽表里筛字段。
- 后续做预测时,可以按商品维度聚合出日销量表,模型输入更干净。
如果原始数据已经埋点或者导出了 CSV,可以在 Django 里写一个管理命令,把 CSV 解析后逐行插入模型。最好不要直接在数据库里手动粘贴,因为后续更新时会失控。
2.3 Django 在这条链路里不是后台管理,而是“编排层”
很多人对 Django 的第一印象是“后台管理 + 登录注册”。但在电商数据分析项目里,Django 的职责更接近一个系统的中枢:
- 用 Django ORM 管理商品、订单、评论数据。
- 用 Django Command 封装爬虫、清洗、模型训练等定时任务。
- 用 Django View 或 Django REST Framework 对外提供查询接口。
- 用 Django Admin 做简单的数据校正和人工核对。
- 用模板渲染出趋势图和预测结果页面。
这样设计之后,数据分析不会停留在 Jupyter Notebook 里。Notebook 适合探索,但不适合长期运行。Django 则能让“探索结果”变成“可重复执行的流程”。
3. 最小可用方案:从爬虫入库到词云图,再到预测接口
3.1 环境准备
先创建一个虚拟环境,避免依赖冲突。
mkdir ecommerce-analysis cd ecommerce-analysis python -m venv venv source venv/bin/activate # Windows 下是 venv\Scripts\activate建议安装的依赖大致如下:
Django>=4.2 requests beautifulsoup4 pandas jieba wordcloud matplotlib scikit-learn joblib djangorestframework然后初始化 Django 项目。
django-admin startproject config . python manage.py startapp shop我把项目命名为config,业务应用命名为shop。实际项目中你可以按自己的习惯命名,但尽量保持一个应用只做一类业务。
3.2 用管理命令封装爬虫:先跑通一条再扩大
不要直接把爬虫逻辑写在视图里。视图层要做的是接收请求、返回结果,而不是去抓页面。
爬虫逻辑应该放进 Django 的管理命令中,这样既可以在命令行手动触发,也可以被定时任务调用。
下面是一个结构示意:
# shop/management/commands/fetch_catalog.py import requests from bs4 import BeautifulSoup from django.core.management.base import BaseCommand from shop.models import Product class Command(BaseCommand): help = "抓取公开测试页面的商品信息示例" def handle(self, *args, **options): url = "https://example.com/test-shop/products" resp = requests.get(url, timeout=10) resp.raise_for_status() soup = BeautifulSoup(resp.text, "html.parser") # 这里只是结构示意,具体选择器要以页面实际结构为准 for card in soup.select(".card")[:50]: sku = card.get("data-sku") name = card.select_one(".name").get_text(strip=True) category = card.select_one(".category").get_text(strip=True) Product.objects.update_or_create( sku=sku, defaults={"name": name, "category": category}, ) self.stdout.write(self.style.SUCCESS("商品数据已更新"))执行时只需要:
python manage.py fetch_catalog这里有一个经验:不要一上来就抓全量数据。先抓 50 条,确认字段解析正确,再逐步放开。如果页面结构发生变化,你只需要调整选择器,而不是重写整个流程。
如果数据源提供了 JSON 接口,那更简单,直接用resp.json()解析字段就可以了。优先用接口解析,能少踩很多 HTML 结构变化的坑。
3.3 从订单表到词云图:把评论文本变成洞察
评论分析是电商项目里投入产出比很高的功能。用户不一定看得懂复杂的预测模型,但一个商品的核心槽点词云,几乎一眼就能看懂。
先从 Django ORM 中取出评论数据,转成 pandas DataFrame:
import pandas as pd from datetime import datetime, timedelta from django.db.models import Sum, Count from shop.models import Order start = datetime.now() - timedelta(days=90) daily = ( Order.objects .filter(order_time__gte=start, status="paid") .values("order_time__date") .annotate(sales=Sum("amount"), orders=Count("id")) .order_by("order_time__date") ) df = pd.DataFrame.from_records(daily) df.columns = ["date", "sales", "orders"] df["date"] = pd.to_datetime(df["date"])然后对评论内容做分词和词云:
import jieba from wordcloud import WordCloud from shop.models import Review text = " ".join(Review.objects.values_list("content", flat=True)[:1000]) words = " ".join( w for w in jieba.cut(text) if len(w.strip()) > 1 and w not in STOP_WORDS ) wc = WordCloud( font_path="/System/Library/Fonts/PingFang.ttc", # Windows 上换成中文字体路径 width=800, height=600, background_color="white", ).generate(words) wc.to_file("media/review_wordcloud.png")注意,词云图必须指定中文字体,否则中文会显示成方框。这是一个看起来小但实际上会卡住很多人的问题。
3.4 第一个可用的销量预测模型:先简单再复杂
销量预测不建议一上来就上深度学习。电商日销量数据通常量级不大,而且周期性明显,先用树模型或统计模型完全够用。
下面用历史订单记录生成每日销量,并构造几个基础特征:
import numpy as np import pandas as pd from sklearn.ensemble import GradientBoostingRegressor from sklearn.model_selection import train_test_split import joblib # 假设 df 已经包含 date, sales 两列 df = df.sort_values("date").reset_index(drop=True) df["weekday"] = df["date"].dt.weekday df["day_of_month"] = df["date"].dt.day df["lag_7"] = df["sales"].shift(7) df["rolling_mean_7"] = df["sales"].rolling(7).mean() df = df.dropna().reset_index(drop=True) feature_cols = ["weekday", "day_of_month", "lag_7", "rolling_mean_7"] X = df[feature_cols] y = df["sales"] X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, shuffle=False ) model = GradientBoostingRegressor(random_state=42) model.fit(X_train, y_train) joblib.dump(model, "models/sales_model.joblib")这个模型虽然简单,但已经包含了三个关键特征:
weekday捕获周一到周日的周期性差异。lag_7捕获七天前的同期销量。rolling_mean_7捕获最近一周的销量水平,用来平滑短期波动。
如果数据包含节假日、促销活动等明显特征,可以继续加对应的 0/1 特征。但核心思路仍然是从简单模型开始,先跑通流程,再观察误差,最后决定要不要升级模型。
3.5 怎么把预测结果交给 Django 页面
模型训练完成后,放在models/目录下。Django View 加载模型时,要注意加载时机。我一般会使用“懒加载”方式,避免每次请求都重新读取模型文件:
import joblib from django.views.decorators.cache import cache_page from django.http import JsonResponse _model = None def get_model(): global _model if _model is None: _model = joblib.load("models/sales_model.joblib") return _model def predict_api(request): # 实际使用时应从查询参数或数据库最新汇总中构造特征向量 features = [[2, 15, 3200, 3100]] pred = get_model().predict(features)[0] return JsonResponse({"predicted_sales": round(float(pred), 2)})这是一个非常小的接口,但已经具备生产线雏形:模型文件独立于 Web 代码,接口只负责预测,数据准备放在了更前面的环节。
如果你希望页面里展示历史趋势和预测曲线,可以在前端引入 ECharts 或 Plotly,通过接口拉取 JSON 数据后再渲染。Django Template 不是不能做,但复杂图表的开发效率可能不如前端图表库。
4. 从“能跑”到“能长期维护”,中间还差几块拼图
4.1 定时更新:让数据自己流进来
如果每天都要手动执行爬虫和模型训练,这套系统就不算真正落地。电商数据分析项目应该加一个定时任务。
Linux 服务器上最简单的做法是用 cron:
0 2 * * * cd /path/to/project && /path/to/venv/bin/python manage.py fetch_catalog 0 3 * * * cd /path/to/project && /path/to/venv/bin/python manage.py train_model如果任务之间有依赖,比如先抓订单再训练模型,可以把它们串成一个管理命令:
# shop/management/commands/update_dashboard.py from django.core.management.base import BaseCommand from django.core import management class Command(BaseCommand): help = "执行数据分析完整更新流程" def handle(self, *args, **options): management.call_command("fetch_catalog") management.call_command("fetch_orders") management.call_command("train_model")这样只需要一个 cron 入口,任务顺序在代码里可控。比在 cron 里写长串命令更清晰,也更容易排查。
4.2 日志、异常和重试
数据抓取和模型训练这两个环节是非常容易出现网络异常或数据格式变化的。在开发阶段,你可以接受程序报错;但部署后,任何一次未处理的异常都可能导致“看起来啥都没跑”。
我的建议是:
- 每个管理命令都写日志文件,至少记录开始时间、结束时间、处理行数。
- 网络请求需要设置超时时间,并对超时和连接错误做异常捕获。
- 爬虫命令要幂等。也就是说,同一个命令重复执行,不会产生重复数据。
- 模型训练命令要保留历史模型文件。如果新模型效果变差,可以快速回滚到上一个版本。
这几点不是花架子。它们决定你三个月后还愿不愿意继续打开这个项目。
4.3 部署时的隐藏坑:字符集、字体、环境变量
用 Django 部署数据分析项目,除了常规的 gunicorn + nginx 之外,还有几个容易被忽略的点。
- 中文乱码:数据库连接串要指定
charset,CSV 文件导入时要统一编码。 - 词云图字体:服务器上不一定有中文字体。部署前要确认系统字体目录,或者在项目里放一个开源中文字体文件。
- 模型路径:不要用相对路径相对当前工作目录,最好用
settings.BASE_DIR拼出绝对路径。 - 环境变量:数据库密码、API Token 等敏感信息不要写死在 settings.py,用环境变量管理。
这些坑单个看起来都不难,但叠加在一起会消耗大量排查时间。
5. 排查链路:预测不准、图表空白、任务失败,先查哪一层
5.1 按这个顺序排查,不要跳
遇到问题,我一般按下面这个顺序定位:
- 看现象:是任务没执行,还是执行了但数据没更新?是图表空白,还是预测结果偏离很大?
- 看输入:原始数据是否完整?日期字段是否有缺失?评论内容是否为空?请求返回的页面结构是否发生了变化?
- 看环境:虚拟环境是否激活?依赖版本是否一致?中文字体是否存在?数据库字符集是否正确?
- 看参数:批量导入的条数限制、模型特征列是否对齐、预测接口是否传入了错误的日期范围。
- 看工具边界:Django 版本和数据库版本是否兼容?wordcloud 是否支持当前 Python 版本?模型特征是否真的符合业务场景?
这个顺序的逻辑是:先把最简单、最容易复现的输入问题排除掉,再碰复杂的环境和参数问题。不要一上来就怀疑模型算法。
5.2 三个高频问题
问题一:词云图中文变成方框。
先检查font_path是否指向了服务器上真实存在的中文字体文件。可以先在命令行用 Python 直接生成一张测试图,排除 Django 上下文的影响。
问题二:模型预测结果非常离谱。
先看训练数据是否干净。常见原因包括:历史订单时间字段解析错误、订单状态没有过滤、存在重复导入导致销量翻倍。把训练集打印出来,先人工看一眼,再谈调参。
问题三:Django 页面加载很慢。
常见原因是每次请求都加载模型文件,或者数据库查询没有走索引。模型文件用懒加载和应用级缓存,复杂查询加select_related或prefetch_related,热点图表用cache_page缓存几分钟,响应速度会有非常明显的变化。
6. 这类项目的适用边界和我最后的建议
6.1 适合谁,不适合谁
| 适合的人群和场景 | 不适合的人群和场景 |
|---|---|
| 个人开发者想学习 Python 全栈数据流程 | 大厂或大型电商的实时百万级数据仓库 |
| 中小店铺想做销量预测和评论洞察 | 需要千亿级特征工程的推荐系统 |
| 团队需要把临时分析流程产品化 | 对延迟有严格要求的高并发在线服务 |
| 学生完成电商数据分析类课设或毕设 | 希望只用一个算法就解决所有业务问题 |
这套方案的数据规模上限,取决于你的 Postgres/MySQL 服务器资源和定时任务的频率。它更适合“每天更新一次、预测未来一周销量、给运营做参考”这样的场景。
如果你未来要处理更大量级的数据,可以先把 Django 里的数据同步到 Spark 或 ClickHouse,再在分析模块中做更重的计算。但现在这个阶段,Django + pandas + scikit-learn 的组合已经足够覆盖一个小团队的数据分析需求。
6.2 把它当成业务系统来养,而不是脚本仓库
最后我想回到开头的判断。做电商数据分析,最容易高估的是模型的复杂度,最容易低估的是整个流程的可维护性。
如果你问我什么是一个电商数据分析项目成功的标志,我的答案不是模型准确率多高,而是:当业务方提出“下周每个 SKU 的备货建议是什么”的时候,你不需要花两天重新导数据、写清洗脚本和训练模型。因为数据已经在系统里,指标口径已经固定,模型可以重新训练,结果能在几分钟内给出。
这才是从“会用 Python 做分析”到“能建设数据系统”的关键一步:你不再只交付结果,而是交付一条可重复运行的链路。而 Django 在这条链路里的角色,就是把那些松散的数据脚本,变成有结构、有边界、能被维护的系统。
如果你是从零开始,我的建议是:不要急着写爬虫,先用 Excel 或后台导出的订单表,建好 Django 数据模型,跑通销量趋势和词云图,再尝试加预测。把最小闭环跑起来,比一次设计出完美架构重要得多。