ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

从0搭建电商销量预测系统:Python爬虫+Django+Transformer

从0搭建电商销量预测系统:Python爬虫+Django+Transformer 开头可以根据实际项目经验自由发挥下面直接进入正文。1. 从零搭建一套电商销量预测系统技术选型背后的思考电商场景里“预测未来一段时间的销量”几乎是每个运营、产品和开发都会遇到的硬需求。无论是大促前的备货计划、日常补货策略还是活动期间的实时库存调度销量预测都直接影响资金占用和用户体验。但很多初学者在做这类项目时容易陷入两个极端只跑通一个深度学习模型数据从哪来、怎么落到数据库、怎么对外提供接口完全没有闭环只做爬虫和数据展示把页面做得很好看但预测能力很弱甚至没有。本文想分享的是一套完整的个人项目与技术学习路径Python 爬虫采集电商数据 → Django 后端开发 → 特征工程与销量预测 → 数据可视化大屏展示。其中预测部分会重点介绍如何从传统时序模型过渡到Transformer 架构帮助读者理解深度学习在销量预测场景中的真实定位。这套技术组合非常适合以下读者正在准备 Python 后端或数据分析相关岗位面试需要一个完整项目经验对电商数据分析感兴趣想自己动手从数据采集到建模走一遍全流程已经会基础的 Python 爬虫和 Django 开发想了解如何把两者结合成业务系统听说过 Transformer但不确定它如何应用于销量预测这类表格/时序数据。读完本文你会掌握电商销量预测项目的功能拆分和数据库表设计爬虫采集模块的编写规范和反爬应对思路Django 后端如何提供数据接口并能被前端调用从传统时序预测到深度学习预测的建模思路Transformer 销量预测模型的 PyTorch 实现核心数据可视化分析中应该关注哪些核心指标常见坑点与工程最佳实践。接下来我们先从整体架构讲起再逐步落地细节。2. 项目背景与核心概念销量预测到底在解决什么问题2.1 什么是电商销量预测电商销量预测指基于历史销售数据、商品信息、时间特征、营销活动等因素预测未来一段时间内商品的销售量。这里的“销量”可以是单 SKU 的日销量也可以是类目维度的周销量或月销量。从业务角度来看预测结果可以帮助企业回答几个关键问题未来 7 天某商品预计卖出多少件现有库存还能支撑几天大促活动前需要备多少货哪些商品可能会滞销需要提前做促销策略从技术角度来看销量预测本质上是一个回归问题也就是根据历史数据预测一个连续数值。它和分类问题不同分类预测的是离散标签而回归预测的是具体数值。2.2 销量预测的常见方法销量预测的技术方案从简单到复杂大致可以分为四代方法类型代表模型适用场景特点统计方法移动平均、指数平滑、ARIMA数据稳定、周期明显简单快速但难以捕捉复杂非线性机器学习线性回归、XGBoost、LightGBM有丰富特征时效果较好需要人工特征工程深度学习RNN、LSTM、Transformer数据量大、模式复杂自动提取时序特征训练成本高业务规则人工经验 库存阈值冷启动、新品依赖业务经验难以规模化很多刚接触预测的同学会有一个误解深度学习一定比传统模型好。真实业务中其实不一定。如果只有三个月的历史数据、SKU 数量不多、促销规则稳定简单的时间序列模型往往就够用了。深度学习更大的优势体现在数据量充足、特征维度高、周期模式复杂的时候。本文会以“先跑通传统模型再引入 Transformer”的方式组织实战内容帮助读者理解不同方法的适用边界。2.3 为什么选择这四种核心技术这套系统采用的技术栈每一层都有明确目的爬虫解决数据来源问题。电商销量数据通常没有公开数据集自己爬取或构造数据是常见做法。Django解决数据管理和接口服务问题。Django 自带 ORM、Admin、认证机制和 REST Framework 扩展很适合快速搭建一个后端服务。深度学习Transformer解决预测建模问题。相比传统模型Transformer 能同时建模多个商品的时间序列并捕捉长期依赖关系。数据可视化解决结果落地问题。预测结果如果只停留在训练集准确率上业务价值有限。通过可视化可以直观看到预测曲线、库存预警、商品排行等信息。需要注意的是本文更强调“完整链路打通”和“技术理解”而不是要求你训练出一个能直接商用、精度极高的模型。作为个人项目和入门实战链路完整性比单点精度更值得投入。3. 环境准备与项目整体设计3.1 开发环境建议版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。建议环境如下操作系统Windows / macOS / Linux 均可Python3.8 或更高版本Django建议使用 4.x LTS 版本数据库SQLite开发/ MySQL生产深度学习框架PyTorch开发工具VS Code 或 PyCharm安装核心依赖pip install django pip install djangorestframework pip install requests pip install beautifulsoup4 pip install pandas pip install numpy pip install matplotlib pip install scikit-learn pip install torch如果你的网络环境下载 PyTorch 较慢可以前往 PyTorch 官网根据系统和 CUDA 版本选择对应的安装命令。CPU 版本在学习和入门阶段完全够用。3.2 功能模块划分整个项目按功能可以拆成四个模块电商销量预测系统 ├── 数据采集模块spider ├── 后端服务模块backend ├── 预测建模模块forecast └── 数据可视化模块visualization这样的拆分方式既方便单独调试也为以后替换算法或更换数据源留好了空间。3.3 数据库表设计销量预测离不开两类数据商品基本信息和每日销售数据。我们用 Django 的 ORM 来设计两个核心模型。# 文件路径backend/sales/models.py from django.db import models class Product(models.Model): 商品信息表 sku_id models.CharField(max_length64, uniqueTrue, verbose_nameSKU编码) name models.CharField(max_length255, verbose_name商品名称) category models.CharField(max_length128, verbose_name商品类目) brand models.CharField(max_length128, blankTrue, verbose_name品牌) price models.DecimalField(max_digits10, decimal_places2, verbose_name售价) class Meta: db_table product verbose_name 商品信息 def __str__(self): return self.name class SaleRecord(models.Model): 每日销量记录表 product models.ForeignKey(Product, on_deletemodels.CASCADE, related_namesales, verbose_name所属商品) record_date models.DateField(verbose_name销售日期) sales_volume models.IntegerField(verbose_name销量) stock models.IntegerField(default0, verbose_name当日库存) created_at models.DateTimeField(auto_now_addTrue, verbose_name创建时间) class Meta: db_table sale_record verbose_name 每日销量记录 constraints [ models.UniqueConstraint(fields[product, record_date], nameunique_product_date) ] def __str__(self): return f{self.product.name}-{self.record_date}关键设计说明sku_id用uniqueTrue保证商品不会重复录入销量表通过外键product关联商品唯一约束unique_product_date防止同一天同一商品出现两条销量记录用DecimalField存储价格避免浮点数精度问题。设计表时还要考虑一个常见问题如果多个来源的数据要合并比如爬虫数据 手工导入的线下数据就需要在销量表里预留一个数据来源字段。否则后期数据清洗会很难受。3.4 执行数据库迁移创建好 Django 工程和 app 后执行迁移命令python manage.py makemigrations python manage.py migrate然后创建超级用户方便进入 Django Admin 管理数据python manage.py createsuperuser4. 数据获取Python 爬虫采集销量数据4.1 爬虫的定位与合规边界在学习项目中很多同学会去爬京东、淘宝、拼多多等真实电商平台。这里必须先强调真实电商平台通常有严格的反爬限制和 robots 协议数据也涉及商业竞争和用户隐私。个人爬虫大量采集真实平台数据轻则 IP 被封重则牵扯法律风险。所以本项目建议用两种安全的办法在合法的公开数据集上做实验自己搭建一个模拟电商页面爬虫只采集自己的测试数据。这样既能练习爬虫技术又不触碰合规红线。4.2 使用 Requests BeautifulSoup 编写商品信息爬虫假设我们有一个测试页面http://127.0.0.1:8000/test_shop/页面结构包含商品名称、价格和销量信息。参考代码如下# 文件路径spider/jd_spider.py import csv import requests from bs4 import BeautifulSoup def fetch_shop_data(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.encoding utf-8 soup BeautifulSoup(resp.text, html.parser) product_list [] items soup.select(.product-item) for item in items: name_node item.select_one(.product-name) price_node item.select_one(.product-price) sales_node item.select_one(.product-sales) if not name_node: continue product_list.append({ name: name_node.text.strip(), price: price_node.text.strip() if price_node else 0, sales: sales_node.text.strip() if sales_node else 0 }) return product_list if __name__ __main__: data fetch_shop_data(http://127.0.0.1:8000/test_shop/) print(f抓取到 {len(data)} 条商品数据) for p in data[:5]: print(p)代码中需要注意几个点headers里的 User-Agent 是模拟浏览器访问的常见做法timeout10避免请求卡死.strip()去除 HTML 文本两侧空白先判断节点是否存在避免因为某个字段缺失导致程序报错。4.3 模拟登录与动态页面思考真实电商网站的数据很大一部分是 JavaScript 异步渲染的。此时 Requests 直接请求 HTML 拿到的是空壳页面。常用方案有分析接口直接请求 JSON 数据接口使用 Selenium 或 Playwright 驱动真实浏览器渲染页面使用抓包工具分析 XHR 请求复制请求参数。作为学习项目我们不需要把所有方案都实现但要理解它们的思路。搜索热词中出现的“jd 爬虫风控对抗”、“大模型逆向爬虫”等本质上都是围绕上述思路展开的攻防问题。初学者不建议一上来就碰高强度反爬网站先在自己的测试环境把流程跑通更重要。4.4 爬虫数据入库把爬虫采集的数据写入 Django 数据库可以直接通过 ORM 操作也可以先写 CSV 再导入。这里给出一个将 CSV 导入 Sales 模型的脚本# 文件路径spider/import_data.py import os import django os.environ.setdefault(DJANGO_SETTINGS_MODULE, config.settings) django.setup() import pandas as pd from sales.models import Product, SaleRecord def import_csv(file_path): df pd.read_csv(file_path) for _, row in df.iterrows(): product, _ Product.objects.get_or_create( sku_idrow[sku_id], defaults{ name: row[name], category: row[category], price: row[price] } ) SaleRecord.objects.update_or_create( productproduct, record_daterow[record_date], defaults{sales_volume: row[sales_volume]} ) print(f导入完成共处理 {len(df)} 条记录) if __name__ __main__: import_csv(data/sales_data.csv)这里使用get_or_create和update_or_create两个方法能让脚本具备幂等性。所谓幂等性就是重复执行脚本不会产生重复数据这个习惯在真实数据处理中非常重要。5. Django 后端框架开发实战5.1 创建项目与 Appdjango-admin startproject config . python manage.py startapp sales把sales注册到INSTALLED_APPS# 文件路径config/settings.py INSTALLED_APPS [ django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, rest_framework, sales, ]5.2 编写数据统计接口这里我们使用 Django REST Framework 写一个简单的统计接口返回商品的总销量、日均销量和最近 7 日趋势。先写序列化器# 文件路径sales/serializers.py from rest_framework import serializers from .models import Product class ProductSalesSerializer(serializers.ModelSerializer): total_sales serializers.IntegerField(read_onlyTrue) avg_sales serializers.FloatField(read_onlyTrue) class Meta: model Product fields [id, sku_id, name, category, price, total_sales, avg_sales]再写视图函数# 文件路径sales/views.py from django.db.models import Sum, Avg, F from django.db.models.functions import Coalesce from rest_framework.decorators import api_view from rest_framework.response import Response from .models import Product, SaleRecord from .serializers import ProductSalesSerializer api_view([GET]) def product_statistics(request): 统计每个商品的总销量和日均销量 products Product.objects.annotate( total_salesCoalesce(Sum(sales__sales_volume), 0), avg_salesCoalesce(Avg(sales__sales_volume), 0) ) serializer ProductSalesSerializer(products, manyTrue) return Response(serializer.data)配置 URL 路由# 文件路径config/urls.py from django.contrib import admin from django.urls import path from sales.views import product_statistics urlpatterns [ path(admin/, admin.site.urls), path(api/products/statistics/, product_statistics, nameproduct_statistics), ]启动服务python manage.py runserver 8000访问http://127.0.0.1:8000/api/products/statistics/即可看到 JSON 数据。5.3 Django ORM 执行查询的注意事项销量预测项目里最常犯的错误是 N1 查询问题。例如# 不推荐遍历商品时查询销量产生大量 SQL products Product.objects.all() for p in products: # 每次循环都会查询一次数据库 total p.sales.aggregate(totalSum(sales_volume))推荐使用annotate一次查出聚合结果products Product.objects.annotate( totalCoalesce(Sum(sales__sales_volume), 0) )这样 Django 只会执行一条 SQL性能差别在数据量变大后非常明显。5.4 Django Admin 数据查看功能在sales/admin.py中注册模型方便在 Admin 后台管理数据# 文件路径sales/admin.py from django.contrib import admin from .models import Product, SaleRecord admin.register(Product) class ProductAdmin(admin.ModelAdmin): list_display (sku_id, name, category, brand, price) search_fields (name, sku_id) admin.register(SaleRecord) class SaleRecordAdmin(admin.ModelAdmin): list_display (product, record_date, sales_volume, stock) list_filter (record_date,)6. 数据分析与特征工程6.1 数据探索先看分布再建模拿到销量数据后不要立刻训练模型。先做数据探索了解数据质量。常见步骤有检查缺失值统计销量分布按商品、类目、时间维度做汇总查看是否存在异常值比如单日销量为负或突增。示例import pandas as pd df pd.read_csv(data/sales_data.csv) df[record_date] pd.to_datetime(df[record_date]) # 缺失值检查 print(df.isnull().sum()) # 按商品统计销量 product_summary df.groupby(sku_id)[sales_volume].agg([sum, mean, max, min]) print(product_summary.head()) # 按日期汇总 daily_sales df.groupby(record_date)[sales_volume].sum() daily_sales.plot()6.2 特征工程有哪些常用特征销量预测的特征可以分成四类时间特征星期几、是否周末、是否月初/月末、节假日、促销日。历史统计特征过去 7 天均值、过去 14 天销量、上周同期销量。商品特征价格、类目、品牌、上架时长。外部特征温度、天气、活动力度、竞品价格。构建训练集时一个重要原则是不能使用未来信息。比如你要预测第 t 天的销量就不能用第 t 天之后的数据做特征。这也是时序预测和普通机器学习最大的区别。特征示例def build_features(df): df df.sort_values([sku_id, record_date]).copy() # 星期特征 df[weekday] df[record_date].dt.dayofweek df[is_weekend] df[weekday].isin([5, 6]).astype(int) # 历史 7 日均值注意 shift 避免用到当天未来值 df[sales_lag1] df.groupby(sku_id)[sales_volume].shift(1) df[sales_lag7] df.groupby(sku_id)[sales_volume].shift(7) df[sales_rolling7_mean] df.groupby(sku_id)[sales_volume].transform( lambda x: x.shift(1).rolling(7).mean() ) return df6.3 传统机器学习与深度学习的选择很多项目把深度学习当成默认选择但传统机器学习模型在销量预测领域依然有很强竞争力。尤其是 XGBoost 和 LightGBM它们对表格数据非常友好训练速度快特征工程灵活适合中小规模数据。深度学习方法更适合数据量大、时间序列长、商品维度多的场景。例如我们要预测上百个 SKU 的未来销量Transformer 可以一次性对多个 SKU 建模而不必为每个 SKU 单独训练一个模型。7. 基于 Transformer 的销量预测模型实战7.1 为什么把 Transformer 引入时序预测Transformer 最早出现在自然语言处理领域代表作是 Google 的论文《Attention Is All You Need》。它的核心机制是 Self-Attention能够直接计算序列中任意两个位置之间的关联权重。相比 RNN/LSTMTransformer 有两个明显优势可以并行计算训练效率更高对长距离依赖的建模能力更强。在销量预测中今天的销量可能受到 30 天前活动效应的影响也可能受到去年同期的季节影响。Transformer 的自注意力机制理论上能捕捉这些长期模式。7.2 Transformer 网络结构简析上图是整个 Transformer 架构中相对简化的编码器-解码器结构。不过在实际销量预测任务中很多时候只使用 Transformer 的编码器部分把历史销量序列编码成特征向量再接一个全连接层输出未来销量。核心模块包括输入嵌入层将时间步数据映射到高维空间位置编码层给序列注入顺序信息多头自注意力层捕捉序列内部不同位置的依赖关系前馈神经网络层对特征做非线性变换残差连接与层归一化保证深层网络稳定训练。7.3 数据准备构造监督学习样本将销量序列转换成 Transformer 输入样本需要定义历史窗口长度和预测未来长度。比如用过去 30 天预测未来 7 天import numpy as np import torch from torch.utils.data import Dataset class SalesDataset(Dataset): def __init__(self, data, input_len30, output_len7): data: 某个商品的销量序列 self.data torch.FloatTensor(data).view(-1) self.input_len input_len self.output_len output_len def __len__(self): return len(self.data) - self.input_len - self.output_len 1 def __getitem__(self, idx): x self.data[idx: idx self.input_len] y self.data[idx self.input_len: idx self.input_len self.output_len] return x, y这里要注意输入输出均为连续时间窗口不能打乱顺序训练集和测试集要按时间切分不能随机切分不同商品的数据可以拼接成一个 batch但 batch 内部要按商品处理好边界。7.4 PyTorch 实现 Transformer 销量预测网络下面给出一个简化版实现核心思路是只使用 Transformer 编码器把历史销量序列编码成特征向量再通过全连接层预测未来值。# 文件路径forecast/transformer_model.py import torch import torch.nn as nn class PositionalEncoding(nn.Module): 位置编码为序列注入位置信息 def __init__(self, d_model, max_len5000): super().__init__() pe torch.zeros(max_len, d_model) position torch.arange(0, max_len, dtypetorch.float).unsqueeze(1) div_term torch.exp(torch.arange(0, d_model, 2).float() * (-np.log(10000.0) / d_model)) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) pe pe.unsqueeze(0) # shape: [1, max_len, d_model] self.register_buffer(pe, pe) def forward(self, x): return x self.pe[:, :x.size(1), :] class SalesTransformer(nn.Module): 使用 Transformer Encoder 预测销量 def __init__(self, d_model64, nhead4, num_layers2, input_len30, output_len7): super().__init__() self.input_proj nn.Linear(1, d_model) self.positional_encoding PositionalEncoding(d_model) encoder_layer nn.TransformerEncoderLayer( d_modeld_model, nheadnhead, dim_feedforward128, batch_firstTrue ) self.encoder nn.TransformerEncoder(encoder_layer, num_layersnum_layers) self.fc_out nn.Linear(d_model * input_len, output_len) self.input_len input_len self.output_len output_len def forward(self, x): # x shape: [batch, input_len] x x.unsqueeze(-1) # [batch, input_len, 1] x self.input_proj(x) # [batch, input_len, d_model] x self.positional_encoding(x) # 加位置编码 x self.encoder(x) # [batch, input_len, d_model] x x.reshape(x.size(0), -1) # 展平 out self.fc_out(x) # [batch, output_len] return out代码说明PositionalEncoding使用正余弦函数编码位置信息这是原版 Transformer 的做法。nn.TransformerEncoderLayer是 PyTorch 官方封装内部已经包含多头注意力、前馈网络、残差连接和层归一化。输入维度d_model、头数nhead、层数num_layers都可以根据数据规模调整。注意这里为了便于理解在展平后直接接全连接层。如果你的序列特别长可以改用全局平均池化或取最后一个时间步的特征。7.5 模型训练流程训练流程包含损失函数、优化器和训练循环三个部分。销量预测常用 MSE 作为损失函数因为它能衡量预测值与真实值之间的平方误差。# 文件路径forecast/train.py import torch import torch.nn as nn from torch.utils.data import DataLoader from transformer_model import SalesTransformer from dataset import SalesDataset def load_series(): 实际项目中这里应读取数据库或 CSV 中的销量序列 import pandas as pd df pd.read_csv(data/single_sku_sales.csv) values df[sales_volume].values.astype(float) return values def train_model(epochs30, batch_size16, lr1e-3): series load_series() train_len int(len(series) * 0.8) train_series series[:train_len] torch.manual_seed(42) dataset SalesDataset(train_series, input_len30, output_len7) loader DataLoader(dataset, batch_sizebatch_size, shuffleTrue) model SalesTransformer(input_len30, output_len7) criterion nn.MSELoss() optimizer torch.optim.Adam(model.parameters(), lrlr) for epoch in range(epochs): total_loss 0 for x_batch, y_batch in loader: optimizer.zero_grad() pred model(x_batch) loss criterion(pred, y_batch) loss.backward() optimizer.step() total_loss loss.item() if (epoch 1) % 5 0: print(fEpoch [{epoch 1}/{epochs}], Loss: {total_loss / len(loader):.4f}) if __name__ __main__: train_model()运行训练python forecast/train.py预期输出Epoch [5/30], Loss: 0.5231 Epoch [10/30], Loss: 0.3316 Epoch [15/30], Loss: 0.2894 ...需要说明的是这里的数据量很小loss 数值只是示意。实际使用时至少要保证单个商品的历史数据超过 200 天模型才能学到一定规律。7.6 模型预测与评估评估销量预测模型不能只看一个指标。常用的评估指标有MAE平均绝对误差MSE均方误差MAPE平均绝对百分比误差MAPE 更贴近业务理解比如预测误差 15%意味着平均偏差 15%。def evaluate_model(model, test_series): model.eval() dataset SalesDataset(test_series, input_len30, output_len7) loader DataLoader(dataset, batch_size16, shuffleFalse) preds [] trues [] with torch.no_grad(): for x_batch, y_batch in loader: pred model(x_batch) preds.append(pred.numpy()) trues.append(y_batch.numpy()) preds np.concatenate(preds, axis0) trues np.concatenate(trues, axis0) mae np.mean(np.abs(preds - trues)) mape np.mean(np.abs((preds - trues) / (trues 1e-6))) * 100 print(fMAE: {mae:.2f}, MAPE: {mape:.2f}%)注意测试集划分时要严格按照时间顺序。例如用前 80% 数据训练后 20% 数据测试。如果随机打乱就会引入未来信息导致评估结果虚高。8. 数据可视化分析8.1 可视化要回答什么问题数据可视化在电商分析项目中不是“画图好看”而是要辅助决策。销量预测系统常见的可视化需求包括整体销量趋势按日/周/月汇总的总销量曲线。商品排行榜哪些商品贡献了主要销量。类目占比不同类目在总销量中的比例。预测值与真实值对比直观查看模型误差水平。库存预警预测销量超过现有库存时高亮提示。8.2 使用 Matplotlib 绘制销量趋势与预测对比# 文件路径visualization/plot_forecast.py import matplotlib.pyplot as plt import pandas as pd def plot_forecast(history, actual, prediction): history: 历史销量序列 actual: 未来真实销量 prediction: 模型预测销量 plt.figure(figsize(12, 5)) x_history range(len(history)) x_future range(len(history), len(history) len(actual)) plt.plot(x_history, history, label历史销量, color#4472C4) plt.plot(x_future, actual, label真实销量, color#ED7D31) plt.plot(x_future, prediction, label预测销量, color#70AD47, linestyle--) plt.axvline(xlen(history) - 1, colorgray, linestyle:) plt.title(电商销量预测对比) plt.xlabel(时间天) plt.ylabel(销量) plt.legend() plt.grid(alpha0.3) plt.tight_layout() plt.savefig(visualization/forecast_result.png, dpi150) plt.show()8.3 Django 中集成静态图表或 Web 大屏如果要在 Django 页面直接展示图表常见做法有两种后端生成图片前端用img标签加载前端使用 ECharts 的 JavaScript 库异步请求数据并绘图。第二种方案在企业项目中更常见因为图表可以交互、更新方便。ECharts 是百度开源的可视化库支持折线图、柱状图、饼图等接入 Django REST Framework 数据接口非常流畅。前端核心思路如下script srchttps://cdn.jsdelivr.net/npm/echarts5/script div idchart stylewidth: 100%; height: 400px;/div script fetch(/api/products/statistics/) .then(response response.json()) .then(data { const chart echarts.init(document.getElementById(chart)); const names data.map(item item.name); const totals data.map(item item.total_sales); chart.setOption({ title: { text: 商品销量排行 }, xAxis: { type: category, data: names }, yAxis: { type: value }, series: [{ type: bar, data: totals }] }); }); /script9. 把预测能力作为 Django 接口暴露出去在实际项目中预测结果不应该只在训练脚本里出现而应该能被运营后台、数据大屏等系统调用。下面我们把训练好的 Transformer 模型封装成 Django 接口。9.1 保存模型为二进制文件训练完成后保存模型torch.save(model.state_dict(), forecast/saved_model/sales_transformer.pt)9.2 在 Django 视图里加载模型先定义模型结构和加载函数# 文件路径sales/ml_service.py import torch from forecast.transformer_model import SalesTransformer MODEL_PATH forecast/saved_model/sales_transformer.pt model None def load_model(): global model if model is None: model SalesTransformer(input_len30, output_len7) model.load_state_dict(torch.load(MODEL_PATH, map_locationcpu)) model.eval() return model def predict_next_sales(history_list): 输入最近 30 天的销量列表输出未来 7 天预测结果 model load_model() tensor torch.FloatTensor(history_list).view(1, -1) with torch.no_grad(): pred model(tensor) return pred.squeeze().tolist()然后写一个 Django 接口# 文件路径sales/views.py from rest_framework.decorators import api_view from rest_framework.response import Response from .ml_service import predict_next_sales api_view([GET]) def forecast_view(request): sku_id request.GET.get(sku_id, ) # 从数据库读取最近30天销量 record_list SaleRecord.objects.filter(product__sku_idsku_id).order_by(record_date)[:30] history [r.sales_volume for r in record_list] if len(history) 30: return Response({msg: 历史数据不足30天}, status400) pred predict_next_sales(history) return Response({sku_id: sku_id, forecast: pred})这里要注意模型文件路径问题。Django 启动时的工作目录可能和训练脚本不一致推荐使用Path(__file__).resolve().parent.parent来拼绝对路径避免因为路径问题找不到模型。10. 常见问题与排查思路10.1 爬虫问题问题现象常见原因解决思路跑完程序没有输出页面结构变化或者提取器未命中先打印响应内容检查 HTML 结构请求被限制缺少 User-Agent构造 headers 模拟浏览器降低请求频率返回内容为空页面为 JS 异步渲染分析 XHR 接口或改用 Selenium/Playwright中文乱码页面编码格式判断错误设置resp.encoding utf-8或根据页面 meta 声明调整关于“爬虫程序运行不出内容只显示 Process finished with exit code 0”这个现象很典型。它说明程序本身没有报错并且正常结束但没有任何数据输出。可能原因有三个代码里没有写打印语句提取的节点为空列表为空逻辑分支把数据处理结果放到了某个条件内部但条件不成立。排查时要先在fetch返回后打印resp.text[:500]确认请求成功并拿到了内容再去检查解析逻辑。10.2 Django 问题问题现象常见原因解决思路启动时模块报错INSTALLED_APPS 未注册检查 app 是否添加到 settings接口返回 404URL 配置错误确认路由路径和视图函数名迁移失败模型定义后未 makemigrations先执行 makemigrations 再 migrate查询数据很慢N1 查询或缺少索引使用 annotate、select_related、prefetch_related10.3 Transformer 训练问题问题现象常见原因解决思路Loss 不下降学习率过大或数据未归一化将销量做标准化/归一化调低学习率预测值全是平均值模型欠拟合或数据规律不强增加训练轮数检查特征与数据窗口训练慢序列长度过长或模型参数过大降低 d_model 和 num_layers过拟合严重模型复杂度高于数据量减少层数、加入 Dropout测试集结果虚高随机切分导致数据泄漏改用时间顺序切分保证测试样本在训练样本之后10.4 数据归一化常被忽略深度学习中销量数据通常存在较大波动。比如日销量几十件到几千件数量级差异会让 MSE 损失在数值较大的样本上占主导。常见的解决办法是使用 StandardScaler 或 MinMaxScaler 对销量序列归一化。from sklearn.preprocessing import StandardScaler scaler StandardScaler() series scaler.fit_transform(series.reshape(-1, 1)).flatten()最后预测出结果后记得用scaler.inverse_transform还原成真实销量值否则页面展示的数字是“标准化后”的没有业务含义。11. 最佳实践与工程建议11.1 爬虫模块的工程规范要设置请求间隔使用time.sleep(random.uniform(1, 3))降低访问频率。要做好异常捕获单条数据解析失败不能影响整体任务。要把采集配置目标 URL、请求头、字段映射和解析逻辑分开便于维护。明确合规边界不采集个人隐私数据、不突破登录权限、不抓取非授权商业数据。11.2 Django 后端的设计建议使用 Django REST Framework 时接口应返回结构化 JSON字段命名统一风格。所有数据库写操作尽量加权限校验使用 Django 自带认证或 JWT。不要把敏感配置数据库密码、密钥写在代码里使用环境变量管理。ORM 查询要遵循最小查询原则能用.only()减少字段加载能用select_related避免关联表反复查询。11.3 深度学习建模的工程建议先建立简单基线例如用“过去 7 天均值”作为预测结果再看深度学习模型有没有跑赢基线。数据版本要管理预测模型的结果与训练数据密切相关不要覆盖历史训练数据。保存训练曲线的 loss 图方便在后排错时确认是否存在欠拟合或过拟合。模型上线前要在验证集上计算 MAPE 等业务指标而不是只关心训练集 Loss。训练/验证/测试集的切分必须符合时间顺序避免未来数据泄漏。11.4 日志与监控真实系统中模型不会永远准确。建议在预测接口中记录以下日志请求的 SKU 和时间使用的模型版本预测结果后续真实销量回填后计算误差。这样我们就可以持续监控模型效果在误差超过阈值时触发告警或重训。12. 总结与下一步学习建议这套“爬虫 Django Transformer 数据可视化”的组合最常见的价值并不在于某一个模型跑出了多高的精度而在于它把电商数据分析的完整闭环打通了。你在学习过程中能真正体会到数据是如何从页面变成结构化记录的后端接口是如何把数据暴露给前端和数据建模脚本的特征工程在哪里影响模型效果Transformer 在时序问题里的实现与 NLP 里的实现有哪些异同预测结果如何最终变成大屏上的折线图和库存预警。从面试角度看这个项目可以体现你具备 Python 开发、后端框架、爬虫实战和深度学习建模的综合能力。回答时建议把“为什么选择技术栈”“预测链路如何设计”“如果数据量增加怎么扩展”作为亮点去准备。后面如果你想继续深入可以按下面的路径推进把预测目标从单商品 7 日预测扩展到多商品、多步预测使用 Prophet 或 LightGBM 构建一个基线模型和 Transformer 做对比实验引入店铺促销日历、节假日等外部特征观察是否有效提升精度用 Docker 部署 Django 服务接入 MySQL 和 Redis 构成生产级系统学习 Spark 或 Dask尝试处理更大规模的历史销量数据。不用急着追求最复杂的模型。先把自己手头的数据链路跑稳定再逐步优化每个环节是这类系统最稳妥的学习方式。如果本文对你有帮助可以收藏备用也欢迎在实际动手时多调试几轮把报错记录和解决思路整理成自己的踩坑笔记。
返回列表