资讯详情

资讯详情

电商销量预测:Python爬虫+Django+Transformer数据链路实践

你拿到一个电商销量预测任务时第一反应是什么我见过不少开发者被 Transformer 几个词吸引上来就翻论文、找 PyTorch 代码然后跑出一张漂亮的 loss 下降曲线。但真正要把模型放进 Django 后端接上爬虫采集的数据在页面里画出预测结果很多人会卡住。不是模型精度不够而是数据链断了。一套完整的 Python 电商数据分析与销量预测项目远不止训练一个 Transformer 模型那么简单。爬虫怎么拿数据、数据怎么清洗、特征怎么构造、Django 怎么承接模型、结果怎么可视化这些环节共同决定了一套方案最终能不能用。很多教程把每个技术栈单独讲得很细但项目实际落地时真正的难点恰恰是它们之间的连接。所以这篇内容我想从一个“项目视角”而不是“模型视角”来拆这件事。主判断是Transformer 只是系统中的一环真正有价值的是把 Python、爬虫、Django、深度学习、可视化串成一条能跑通、能维护、能持续迭代的数据链路。1. 先搞清楚你要做的是“销量预测”还是要搭一套电商数据分析系统1.1 为什么很多项目最后会停在模型训练这一步如果你在 GitHub 或博客里搜“销量预测”会看到大量 Transformer、LSTM、XGBoost 预测代码。拿公开数据集跑通一个模型并不难难的是把模型放进真实业务里。真实业务里数据不是现成的。你要先从商品页面或后端接口采集销量、价格、评价再考虑缺失值、异常值、促销活动、口径变化。等数据能进模型了你还要考虑模型文件怎么加载、接口怎么设计、前端怎么展示。任何一个环节断掉整个项目就停在“notebook 里能用”的状态。这不是代码技巧问题而是系统设计问题。我见过一个项目里Transformer 训练部分只占了代码量的 10%剩下 90% 都是在处理数据采集、数据校验、格式转换、接口通信和日志。如果一开始只盯着模型很容易忽略其他 90%。1.2 一条完整链路应该怎么拆从零到一做电商销量预测常见的链路至少包括六层数据采集层用 Python 爬虫或电商开放平台接口获取商品历史销量、价格、评论数、收藏数等公开数据。存储层把原始数据保存成 CSV、SQLite、MySQL 或对象存储为后续清洗留底。数据清洗与特征层处理缺失、异常、重复数据构造时间特征和业务特征。建模层使用深度学习模型或传统模型例如 Transformer、LSTM、LightGBM完成销量预测。后端服务层使用 Django 加载训练好的模型提供接口让前端和其他系统能调用。可视化层把历史销量、预测销量、误差情况用图表展示帮助人工确认效果。很多人在第 3 步和第 4 步之间反复横跳。比如花大量时间调 Transformer 的注意力头数却忽略了一个很基础的问题你喂给模型的销量序列到底是不是连续的日期有没有缺大促产生的异常值有没有被单独标记如果数据质量不可控再复杂的模型也只是在放大错误。1.3 技术选型图谱每个技术栈到底负责什么从项目标题里的关键词看Python、爬虫、Django、深度学习、Transformer 都是这套系统的一部分。它们不是同层技术不能直接比较。更合理的方式是看它们在一个链路中扮演什么角色。模块推荐的方案主要用途落地时最容易忽略的问题数据采集Python requests / httpx BeautifulSoup获取页面或接口公开数据合规边界、频率控制、数据格式数据存储CSV、SQLite、MySQL留存原始数据和清洗后数据没有留原始数据后续口径追查困难数据分析pandas、NumPy清洗、聚合、探索日期索引不连续、销量口径不一致特征工程pandas、dateutil构造时间特征、业务特征、滞后特征使用未来信息造成特征泄露深度学习建模PyTorch Transformer / LSTM学习销量序列的周期和趋势数据量不足时效果反而不如简单模型后端服务Django Django REST Framework部署模型提供预测接口模型每次请求重复加载性能很差可视化ECharts、Chart.js、Django 模板展示实际值和预测值接口字段与前端约定不一致这套选型图谱不是唯一答案。如果你只需要做内部数据分析可以不上 Django如果只是学习 Transformer可以不写爬虫。但如果你想做的是一个“从数据到产品”的完整项目这些模块早晚都要出现。2. 从数据源开始爬虫不是“反爬对抗”而是稳定地采集合规公开数据2.1 先确认数据边界API 优先公开页面其次robots 协议要读电商领域涉及爬虫时第一要务不是写代码而是确认数据边界。很多教程喜欢把“风控对抗”当卖点但这类内容既不适合公开博客传播也不适合作为学习路径。如果你想长期做数据分析项目更应该关注的是合规、稳定和可持续。合规采集的优先级大概是这样官方开放平台 API如果平台提供了商品、销量或评价接口优先使用。这是数据最稳定、最合规的来源。页面公开数据没有 API 时只采集不需要登录就能看到的公开字段。正式采集前先查看页面的 robots 协议和服务条款。已公开的数据集Kaggle、天池、公开仓库里有很多脱敏或模拟的销量数据做算法验证完全够用。如果你的数据源需要登录、需要破解验证码、需要模拟复杂请求参数那这个数据源本身就不可持续。建议换一个方向而不是把精力花在“对抗”上。注意写爬虫的目的是获取数据不是测试网站的防御能力。遇到限制时先检查请求头、访问频率和用户代理是否合理如果仍然被拒绝应当更换数据源而不是继续尝试绕过限制。2.2 一个最小采集流程应该怎么设计假设你已经确认某个公开接口允许获取商品详情一个最小化的 Python 采集脚本通常会做四件事请求数据检查响应状态解析需要的字段存储原始结果下面是一个示意结构。示例地址不是真实站点实际落地时你需要替换成自己确认过合规的数据来源。import json import time import requests # 示例公开接口字段结构需要根据实际响应调整 url https://example.com/api/products/1001 headers { User-Agent: Mozilla/5.0 (course demo) } resp requests.get(url, headersheaders, timeout10) print(resp.status_code) if resp.status_code 200: data resp.json() record { product_id: data.get(product_id), price: data.get(price), sales: data.get(sales), comment_count: data.get(comment_count), crawled_at: time.strftime(%Y-%m-%d %H:%M:%S) } print(record) # 建议先保存原始 JSON再做解析 with open(raw_product.json, w, encodingutf-8) as f: json.dump(data, f, ensure_asciiFalse, indent2) else: print(请求失败请检查 URL、请求头或访问频率)这个脚本的作用不是直接给出生产代码而是让你看到最小流程中的关键点状态码、响应结构、字段解析、原始数据保存。如果发现价格字段是字符串、销量字段缺失、日期变了格式这些都应该在采集层先记录而不是等进入 DataFrame 后再猜测。2.3 爬虫“没有输出但退出码 0”是一个很常见的问题在相关搜索里很多人会遇到“爬虫程序运行不出内容只显示 exited with code 0”。这个现象很典型程序没有报错也没有输出说明进程正常结束只是没有执行到你希望看到的代码路径。排查顺序可以先这样来检查入口函数是否被调用。如果你把主要逻辑写在了main()里而最后没有写main()程序运行完定义就直接退出。检查请求是否成功。如果requests.get抛异常通常会有 traceback但如果异常被 try 吞掉了又没有打印日志进程就会静默退出。检查解析逻辑是否得到空值。比如网页结构里根本没有div.product-sales你用find().text会得到 None随后如果赋值或保存失败也可能不打印。检查重定向或验证页。有的页面会返回一个“安全验证”页面状态码 200但里面没有商品数据。从经验看最容易出问题的不是请求本身而是你只看了状态码没有看响应内容里的实际结构。建议每次请求后先把resp.text[:500]或resp.json()打印出来确认再写下一步。这个习惯还能帮你少踩一个大坑把解析逻辑建立在“你以为的字段结构”上而不是真实返回结构上。3. Transformer 再醒目也处理不了脏数据清洗和特征设计要先行3.1 电商销量数据里最常见的三类坑进入建模前数据清洗是必过的一关。常见的电商销量数据坑有三种。第一销量口径不一致。有的商品页面展示“月销 1000”有的展示“累计销量 5000”有的展示“近 30 天付款人数”。如果把这些字段混成一个sales模型会被完全误导。处理方式是先明确你预测的目标口径然后只保留一种口径或者把不同口径映射到统一口径。第二日期不连续。很多电商历史数据只能按天抓取而不是后台导出的全量明细。遇到网站改版、抓取中断、平台活动期间字段异常日期就会缺失。处理时不能直接删除缺失日期要先把日期范围补全再决定对销量填充 0 还是用前后均值。第三大促异常值。双十一、618 这类日期的销量可能比平时高几十倍。这不是“噪声”不能简单当成异常值删除。更好的做法是打一个促销标记字段让模型知道这一天发生了特殊事件。3.2 构造时间特征和业务特征而不是只把日期塞给模型Transformer 本身能够学习序列之间的依赖但它不能替你创造业务含义。你需要在输入序列里显式告诉模型今天是星期几、是否周末、是否临近大促。拿 pandas 举例常见的时间特征和业务特征包括data[date] pd.to_datetime(data[date]) data[weekday] data[date].dt.weekday data[is_weekend] data[weekday].isin([5, 6]).astype(int) data[day_of_month] data[date].dt.day data[month] data[date].dt.month data[is_promotion] data[promotion_tag].fillna(0).astype(int) # 滞后特征用过去第7天和第14天的销量注意不要引入未来信息 data[sales_lag7] data[sales].shift(7) data[sales_lag14] data[sales].shift(14) # 滚动特征过去7天销量均值 data[sales_rolling7] data[sales].rolling(7).mean()这些特征不是越多越好但可以明显提高序列预测的稳定性。滞后特征和滚动特征尤其适合电商这种有周期性、有连续性的数据。需要注意shift(7)会让前 7 行产生缺失值。训练前要统一丢弃这些行否则模型会学到“用缺失值预测缺失值”。3.3 警惕特征泄露别让模型“作弊”特征泄露是销量预测里最容易犯的错误也是最难排查的问题。假设你要预测第 30 天的销量并且用第 30 天到第 35 天的平均销量作为特征那模型在训练时表现会非常好但上线后完全无法使用因为第 30 天到第 35 天的数据在第 30 天还没发生。更隐蔽的情况是你在做数据清洗时用了整段历史的均值去填充缺失值。对于某一天 t 来说这个均值可能包含了 t 之后才出现的数据。虽然初看只是一个小细节但在验证阶段很容易让你高估模型效果。判断方法也很简单构造每个样本时只能使用该时间点之前已经存在的信息。如果你在做任何滚动均值、滞后特征、缺失值填充时发现它使用了当前日期之后的记录就要重新调整逻辑。4. Transformer 在销量预测里的真实角色能建模长序列但数据量要撑得起4.1 Transformer 为什么会进入销量预测领域很多人第一次接触 Transformer是在 NLP 和视觉任务里。把 Transformer 用在销量预测本质上是把它当作一个“序列到序列”的模型使用输入过去一段时间的销量和特征输出未来一天的销量或未来若干天的销量。Transformer 的核心是自注意力机制。它可以同时看到输入序列中任意两个时间点的关系。比如第 1 天的销量可能和第 14 天的销量存在某种联系传统 RNN 要经过很多步才能把这种远距离信息传递过来Transformer 可以用注意力直接关联。但这里有一个容易误判的地方销量序列通常不是长文本很多商品的历史数据也就两三百天。如果历史很短Transformer 的长距离建模优势并不明显。它更擅长的是在大规模数据、长序列、多种特征并行输入的场景中发挥作用。4.2 一个教学用的 Transformer 销量预测骨架下面这段代码是一个典型的 PyTorch 教学骨架用来展示结构输入序列、位置编码、TransformerEncoder、输出层。import math import torch from torch import nn class PositionalEncoding(nn.Module): 向输入向量中加入位置信息Transformer 本身没有顺序概念。 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() * (-math.log(10000.0) / d_model) ) pe[:, 0::2] torch.sin(position * div_term) pe[:, 1::2] torch.cos(position * div_term) self.register_buffer(pe, pe) def forward(self, x): # x shape: [batch, seq_len, d_model] return x self.pe[: x.size(1)] class TransformerSales(nn.Module): 一个简化后的销量预测模型骨架落地前需要结合特征维度和验证方案调整。 def __init__(self, d_model32, nhead4, num_layers2, dropout0.1): super().__init__() self.input_proj nn.Linear(1, d_model) self.positional_encoding PositionalEncoding(d_model) encoder_layer nn.TransformerEncoderLayer( d_modeld_model, nheadnhead, batch_firstTrue, dropoutdropout, ) self.encoder nn.TransformerEncoder(encoder_layer, num_layersnum_layers) self.output_proj nn.Linear(d_model, 1) def forward(self, x): # x 的形状一般是 [batch, seq_len, feature_dim] # 特征维度为 1 时先用一个线性层映射到 d_model x self.input_proj(x) x self.positional_encoding(x) x self.encoder(x) # 取最后一个时间步的输出做预测 last_hidden x[:, -1, :] pred self.output_proj(last_hidden) return pred这里需要理解两个关键点第一input_proj把每个时间点的特征从 1 维变成d_model维目的是让模型有一个统一的向量空间。第二PositionalEncoding使用 sin 和 cos 函数生成位置编码。原因在于 Transformer 里的自注意力本身不包含位置信息。如果不加位置编码模型会把“第 1 天”和“第 100 天”看成一样的输入顺序。实际项目中输入特征往往不止 1 维。除了销量还有价格、促销标记、星期几等。这时需要把input_proj的输入维度改为特征总数而不只是 1。4.3 什么时候不该用 Transformer如果历史数据只有几百条并且单条序列很短Transformer 不一定是最后的选择。数据量少的时候模型训练容易过拟合预测波动也会很大。用 LightGBM、随机森林或更简单的 ARIMA、Prophet往往能获得更稳定的结果。可以做一个粗略判断场景使用建议单品历史数据不到 100 天优先考虑传统模型或简单深度学习模型同时预测数百个商品历史长度很长可以考虑 Transformer便于统一建模输入特征包含文本、类别等多维信息Transformer 的 embedding 结构更灵活需要部署到低配服务器先跑简单模型避免为 1% 精度增加大量维护成本我的建议是先跑一个线性模型或随机森林作为基准再用 Transformer 对比。如果 Transformer 在验证集上的提升不明显就不要硬上。4.4 评估预测效果不能只看训练集精度销量预测中常用三个指标MAE绝对误差均值直观反映平均差多少个销量单位。RMSE会放大较大误差适合评估大偏差。MAPE百分比误差适合不同量级商品的横向比较。评估方法也很关键。销量序列有很强的时间前后关系不能简单用随机 K 折交叉验证。如果训练集里混入了未来数据验证结果会虚高。更实用的做法是按时间顺序切分。比如用前 70% 作为训练集中间 10% 作为验证集最后 20% 作为测试集。在验证模型时要模拟“用昨天及之前的数据预测今天”的真实使用方式。5. Django 不是只用来做 CRUD它负责把预测模型“变成服务”5.1 Django 项目结构设计避免模型加载进每个请求如果你已经训练好了模型下一步就是把它接进 Django。很多初学者会在视图函数里写模型加载代码导致每一次预测请求都重新读一次权重文件。这样做有两个问题速度慢且可能引发内存抖动。更合理的做法是在 Django 进程启动后把模型加载到内存中后续请求直接复用。假设项目叫sales_forecast应用叫analysis模型文件放在ml/transformer_sales.pt视图写法可以是这样# analysis/views.py import torch from django.http import JsonResponse # 避免每次请求都加载模型 _model None def get_model(): global _model if _model is None: # 这里需要导入你的模型类 from .model_utils import TransformerSales _model TransformerSales(d_model32, nhead4, num_layers2) _model.load_state_dict( torch.load(ml/transformer_sales.pt, map_locationcpu) ) _model.eval() return _model这样的写法可以避免频繁加载模型。但它也有并发隐患Django 默认是多进程部署每个进程中都会保留一份_model全局变量。如果模型很大内存会成倍增加。更稳妥的做法是在正式项目里使用独立推理服务或 Redis 队列把 Django 和模型推理分离。对于学习和中小型项目全局加载已经足够。5.2 用接口返回预测结果用图表验证曲线为了让可视化层能使用预测结果后端最好提供一个 JSON 接口而不是直接返回渲染好的 HTML。接口逻辑大致是接收商品 ID。从数据库或缓存里读取历史销量序列。按训练时的特征处理流程生成模型输入。调用模型获取预测值。返回历史序列和预测值。下面是一个接口骨架def forecast_product(request): product_id request.GET.get(product_id) # 实际项目中需要根据 product_id 从库里查最近 N 天销量 history { date: [2024-01-01, 2024-01-02, 2024-01-03], sales: [120, 118, 135], } # 转换特征和模型推理 model get_model() # tensor build_model_input_from_history(history) # with torch.no_grad(): # pred model(tensor).item() pred 136.5 # 示例预测值 return JsonResponse({ product_id: product_id, history: history, prediction: pred, })这里有一个很容易踩的坑模型训练时的特征处理和后端推理时的特征处理不一致。比如训练时对销量做了一阶差分、归一化、对数变换后端推理前也必须做相同的变换否则预测结果可能完全不对。注意模型训练代码与后端接口代码最好共用同一个特征处理函数。不要训练时写一遍后端接口里再复制粘贴一遍。一旦两边有偏差问题会非常难查。5.3 静态文件与前端资源常见坑Django 页面要显示图表时通常会引入 ECharts 或 Chart.js。这里最常见的问题不是图表不会画而是静态文件加载不出来。解决这个问题得先区分两件事本地开发时要在settings.py里配置STATIC_URL和STATICFILES_DIRS。上线部署时需要使用collectstatic收集所有静态文件再由 Nginx 或云存储托管。如果图表只出现了数据、没有出现图形优先打开浏览器开发者工具看 Console 和 Network检查 JS 文件是否 404检查接口返回的 JSON 字段是否和前端代码一致。6. 从最小可用到持续迭代执行顺序、边界和长期维护6.1 正确顺序是先闭环再优化很多项目的失败不是因为技术不够而是因为一开始就铺得太大。做这个主题的项目我建议按以下顺序推进第一阶段单商品最小闭环选一个商品先用已有数据或手动采集的公开数据得到一份干净的 CSV。接着用最简单的方法做销量预测比如线性回归或随机森林。最后通过 Django 的简单视图把结果输出到页面。这个阶段的目标不是精度而是把整条链路跑通。链路通了你才会知道哪里会断。第二阶段引入更复杂的数据采集和特征在第一阶段基础上加入爬虫或 API 采集增加多商品数据构造价格、促销、评论等特征。第三阶段引入 Transformer 模型先跑好一个基准模型再用 Transformer 对比。如果 Transformer 确实在测试集上更好再进入参数调优。第四阶段工程化补充服务日志、定时任务、异常重试、数据库、监控和权限控制。到这个阶段项目才接近可长期维护的状态。6.2 一套实用的排查链路当销量预测项目跑出“看似错误”的结果时不要急着调模型。先沿着链路逐层排查。排查层先看什么常见原因输入数据层日期是否连续、销量是否含负值、字段是否混入口径爬虫中断、字段映射错误清洗与特征层特征是否包含 NaN、是否包含未来信息滚动窗口写错、shift 方向反了模型训练层训练集和验证集是否时间顺序切分随机 K 折导致数据泄露模型服务层模型结构、权重路径、输入维度是否一致特征变换不统一后端接口层接口是否返回 JSON、是否跨域、是否日志报错CORS 配置、字段名不匹配可视化层JS 文件是否 404、字段是否 undefined静态文件路径、接口字段大小写排查的关键原则是先确定是哪一层坏了再决定修哪里。如果你连”模型输入长什么样“都没确认就直接调注意力头数往往只是在浪费时间。6.3 什么时候选择这套方案什么时候绕开它这套 Python 爬虫 Django 深度学习 Transformer 的方案并不适合所有场景。如果你只是想快速分析某几个商品的销量趋势用 Excel 或 pandas 画图就够了。如果你的核心诉求是拿到高精度预测而不是锻炼全栈能力那可以考虑直接使用企业级商业软件或云厂商的预测服务。如果数据量特别少也不需要上一个完整 Django 系统。但如果你是以下这些情况这套链路很值得做想系统学习 Python 数据分析及后端部署而不是只停留在算法示例。需要为一个真实业务搭建可复用的商品销量预测流程。想把爬虫采集、数据清洗、深度学习和 Web 可视化结合起来形成自己的项目作品。需要在多种商品、多维特征的长周期场景下做预测验证。一旦决定走这条路就要接受一个现实维护一套从采集到可视化的系统成本一定会高于只训练一个模型。日志、调度、异常处理、特征版本管理都会逐渐出现。刚开始可以从最简闭环开始但心里要留着工程化的地图。电商销量预测的价值不只是“算出一个未来数字”而是把分散的取数、分析、建模、展示能力沉淀成一套可持续运行的工作流。Transformer 解决的是序列建模问题Django 解决的是部署问题爬虫和数据分析解决的是输入问题。把这些问题全部接起来之后你的项目才会真正走出 notebook成为一个可以被使用、被验证、被迭代的产品。如果你现在正卡在“模型训练完了但项目没做完”这个状态我的建议很简单先别急着调参试着把一个商品从公开数据采集一路做到 Django 页面上的预测曲线。等这条线完整跑通你会更清楚每一个技术栈的边界在哪儿也知道下一步最该解决什么问题。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →