ARTICLE DETAIL

资讯详情

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

电商数据分析与销量预测:从爬虫到Django看板的完整工程实践

电商数据分析与销量预测:从爬虫到Django看板的完整工程实践 电商数据分析和销量预测常常被误以为只是训练一个机器学习模型。实际落地时数据从哪来、清洗后如何存储、模型如何嵌入 Web 系统、图表怎么呈现给运营每一环都可能成为瓶颈。本文以 Python 为核心语言使用 Django 搭建 Web 框架利用爬虫获取商品数据借助 pandas 完成数据清洗与特征工程训练销量预测模型并输出数据看板和词云图完整走通一条从数据采集到业务展示的链路。文章面向的读者是已经掌握 Python 基础、了解 Django 基本用法但还没有把一个数据分析项目完整工程化的开发者。读完本文后你可以得到一套可复用的项目骨架用 Django 管理数据表用爬虫或模拟数据灌入数据用 pandas 做特征工程用 scikit-learn 训练预测模型再用 matplotlib 和 wordcloud 生成可视化素材最后通过网页展示。1. 项目整体架构与技术选型1.1 为什么用 Django 作为数据展示层销量预测项目如果只是停留在 Jupyter Notebook 里业务人员无法使用。实际项目需要一个 Web 系统来承载数据查询、图表展示和预测结果输出。Django 的优点是自带 ORM、Admin 后台和模板引擎不需要额外搭建前端服务非常适合做内部数据看板或中小型分析平台。用 Django 承接这个项目的另一个原因是它的数据库迁移和管理命令机制非常成熟。数据采集之后往往要清洗、聚合、保存Django ORM 可以先把原始数据落库再通过自定义 management command 触发分析任务这样每一步都能留痕后续排查也方便。项目整体的数据流是爬虫采集商品和评论数据 - 写入 Django 模型 - pandas 读取并清洗 - 特征工程 - 训练预测模型 - 模型文件保存 - 视图加载模型和图表 - 网页呈现。1.2 核心依赖和版本约束下表是本文案例使用到的主要依赖版本只给出常见组合。实际项目落地前要结合 Python 版本和操作系统确认依赖兼容性尤其是 wordcloud 在部分 Linux 环境需要编译依赖。依赖库主要用途建议版本区间说明DjangoWeb 框架、ORM、模板4.2.x稳定长期支持版本pandas数据清洗、聚合、特征工程2.0.x依赖 numpyscikit-learn训练分类回归模型1.3.x提供随机森林、线性回归requests发送 HTTP 请求抓取数据2.31.x配合 BeautifulSoupbeautifulsoup4解析 HTML 页面4.12.x解析爬虫结果matplotlib绘制趋势图和柱状图3.7.x中文字体需要配置wordcloud生成评论词云图1.8.x中文需要指定字体numpy数值计算1.24.x自动被 pandas 安装如果使用 Python 3.11 或 3.12部分旧版本依赖可能编译失败。建议先创建一个全新虚拟环境再逐项安装避免和系统 Python 环境互相污染。1.3 项目目录结构设计考虑到这是一篇教程项目结构需要兼顾可读性和工程性。建议按 Django 默认结构再加一个analysisapp专门负责数据分析、模型训练和可视化任务。ecommerce_analysis/ ├── manage.py ├── config/ # Django 项目配置 │ ├── __init__.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── shop/ # 商城数据 app │ ├── __init__.py │ ├── models.py │ ├── views.py │ ├── urls.py │ ├── management/ │ │ └── commands/ │ │ ├── import_sales.py │ │ ├── crawl_products.py │ │ └── train_model.py │ └── templates/ │ └── shop/ │ └── dashboard.html ├── analysis/ # 分析和模型代码 │ ├── data_processor.py │ ├── feature_engineering.py │ ├── model_trainer.py │ └── visualizer.py ├── static/ │ ├── images/ │ └── css/ └── media/ ├── charts/ └── wordcloud/这里的核心思想是shop这个 app 负责数据模型和 Web 展示analysis作为独立 Python 模块不依赖于 Django 的请求生命周期方便在 Jupyter Notebook 或命令行中单独调试。2. 环境准备与 Django 项目初始化2.1 创建虚拟环境并安装依赖环境准备这一步最重要的不是安装命令本身而是保证安装结果可复现。建议先创建requirements.txt再通过 pip 安装。python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate pip install django pandas scikit-learn matplotlib wordcloud requests beautifulsoup4 pip freeze requirements.txt安装完成后可以用下面命令确认 Django 和 scikit-learn 版本python -c import django, sklearn, pandas; print(django.get_version(), sklearn.__version__, pandas.__version__)如果 wordcloud 安装失败在 Linux 上经常是因为缺少 libjpeg 或 freetype 开发头文件可以先安装系统包。在 Windows 上建议使用预编译的 whl 文件或者把 Python 降到 3.9 至 3.11 之间。2.2 创建 Django 项目和应用使用 Django 的管理命令创建项目和 appdjango-admin startproject config . python manage.py startapp shop python manage.py startapp analysis项目名使用config是为了避免和后面的analysis模块混淆。analysis既可以作为一个 Django app 存在也可以只是一个普通 Python 包。本文为了让pandas代码保持独立把它作为普通模块不注册到INSTALLED_APPS只有shop需要注册。在config/settings.py中把shop加入INSTALLED_APPSINSTALLED_APPS [ # Django 自带应用 django.contrib.admin, django.contrib.auth, django.contrib.contenttypes, django.contrib.sessions, django.contrib.messages, django.contrib.staticfiles, # 自定义应用 shop, ]这一步如果不做后续python manage.py makemigrations会提示没有变化因为 Django 只会感知到INSTALLED_APPS中的模型。2.3 配置数据库和时区默认开发环境使用 SQLite不需要额外安装数据库适合快速验证。生产环境建议切换成 MySQL 或 PostgreSQL并做数据备份。settings.py中有两个关键配置需要调整LANGUAGE_CODE zh-hans TIME_ZONE Asia/Shanghai USE_TZ True设置中文时区之后Django 时间字段会自动按上海时区处理但在写日期聚合统计时要小心时区转换带来的偏移。如果数据量不大也可以在业务代码中统一使用datetime.date避免时区干扰。3. 数据采集与数据建模3.1 数据来源和合规说明电商数据采集有两类方式第一类是使用平台 Open API 获取授权数据第二类是爬虫抓取公开页面。本文以爬虫为例但要求在目标网站robots.txt允许的范围内抓取并控制请求频率不要对目标服务器造成压力。在本地演示场景下为了避免依赖外部网站导致复现失败本文会提供一个“模拟数据生成”的管理命令让读者先跑通整个流程。同时保留一个最小爬虫示例说明如何抓取商品标题和销量实际使用时按目标站点结构调整。3.2 Django 模型设计数据建模是后续分析的基础。这里设计三张表商品表、销量表和评论表。商品表保存基础属性销量表保存每日销量评论表保存用户评论文本供词云图使用。在shop/models.py中写入from django.db import models class Product(models.Model): sku models.CharField(商品SKU, max_length64, uniqueTrue) name models.CharField(商品名称, max_length255) category models.CharField(类目, max_length128) price models.DecimalField(价格, max_digits10, decimal_places2) class Meta: ordering [-id] verbose_name 商品 verbose_name_plural 商品 def __str__(self): return self.name class SaleRecord(models.Model): product models.ForeignKey(Product, on_deletemodels.CASCADE, related_namesales, verbose_name商品) date models.DateField(销售日期, db_indexTrue) sales_volume models.PositiveIntegerField(销量) class Meta: constraints [ models.UniqueConstraint(fields[product, date], nameunique_product_date) ] ordering [date] verbose_name 销量记录 verbose_name_plural 销量记录评论表用于词云图class Comment(models.Model): product models.ForeignKey(Product, on_deletemodels.CASCADE, related_namecomments, verbose_name商品) content models.TextField(评论内容) created_at models.DateTimeField(评论时间, auto_now_addTrue) class Meta: ordering [-created_at] verbose_name 评论 verbose_name_plural 评论商品和日期组合上的唯一约束很重要可以防止重复导入。如果不加约束后续pandas做透视表时可能出现重复数据影响预测质量。执行数据库迁移python manage.py makemigrations shop python manage.py migrate迁移成功后可看到 Django 生成的迁移文件这些文件要纳入版本管理保证不同环境的表结构一致。3.3 模拟数据生成管理命令为了让教程不依赖外部网络实现一个管理命令向数据库写入 180 天的销量数据和一批评论。在shop/management/commands/import_sales.py中写入import random from datetime import timedelta from django.core.management.base import BaseCommand from django.utils import timezone from shop.models import Product, SaleRecord, Comment class Command(BaseCommand): help 生成模拟电商销售数据和评论文本 def handle(self, *args, **options): products [ {sku: SKU001, name: 无线蓝牙耳机, category: 数码, price: 199.00}, {sku: SKU002, name: 智能手环, category: 数码, price: 259.00}, {sku: SKU003, name: 保温杯, category: 家居, price: 89.00}, {sku: SKU004, name: 运动鞋, category: 服饰, price: 399.00}, ] for item in products: Product.objects.update_or_create( skuitem[sku], defaults{ name: item[name], category: item[category], price: item[price], } ) end_date timezone.localdate() start_date end_date - timedelta(days180) current_date start_date while current_date end_date: for product in Product.objects.all(): # 简单的季节和趋势模拟周末销量高一点整体略有增长 weekend_boost 1.5 if current_date.weekday() 5 else 1.0 trend 1 (current_date - start_date).days / 180 baseline 30 if product.category 数码 else 20 volume int(baseline * weekend_boost * trend random.randint(-5, 15)) volume max(volume, 1) SaleRecord.objects.update_or_create( productproduct, datecurrent_date, defaults{sales_volume: volume}, ) current_date timedelta(days1) comments [ 质量很好非常满意, 物流很快价格实惠, 包装完整客服态度好, 使用方便推荐购买, 性价比高超出预期, 外观漂亮手感不错, 音质清晰续航满意, 尺码合适穿着舒服, 保温效果很好冬天必备, 戴上去很轻运动方便, ] for product in Product.objects.all(): for _ in range(30): Comment.objects.create( productproduct, contentrandom.choice(comments), ) self.stdout.write(self.style.SUCCESS(模拟数据生成完成))运行命令python manage.py import_sales模拟数据生成后可以用 Django shell 快速检查python manage.py shell -c from shop.models import Product, SaleRecord, Comment; print(Product.objects.count(), SaleRecord.objects.count(), Comment.objects.count())正常会输出4 724 120左右的数据量。这个量级足够跑通训练和可视化流程。3.4 爬虫最小示例如果需要抓取公开网站数据可以用requests和BeautifulSoup。下面是一个示例框架实际抓取前必须确认目标网站允许采集import requests from bs4 import BeautifulSoup def crawl_product_page(url): headers { User-Agent: Mozilla/5.0 (compatible; learning-project) } response requests.get(url, headersheaders, timeout10) response.raise_for_status() soup BeautifulSoup(response.text, html.parser) # 示例假设页面中存在 class 为 product-title 的标题 title soup.select_one(.product-title) if title: return title.get_text(stripTrue) return None这段代码的重点不是选择器而是requests和BeautifulSoup协作的逻辑先发请求拿到 HTML再解析目标节点。爬虫抓下来的数据最好先清理再入库例如去除空白字符、统一日期格式、处理价格单位等。4. 使用 pandas 完成数据清洗与特征工程4.1 从 Django ORM 读取数据转为 DataFrameDjango ORM 返回的是 QuerySet要交给 pandas 处理最稳妥的方式是用values()转成列表再构造 DataFrame。这样逻辑清晰也不会因为 ORM 懒加载引入性能问题。在analysis/data_processor.py中写import pandas as pd from django.utils import timezone from shop.models import SaleRecord, Product, Comment def load_sales_data(): sales list( SaleRecord.objects.select_related(product).values( product__sku, product__name, product__category, product__price, date, sales_volume, ) ) df pd.DataFrame(sales) if not df.empty: df.columns [sku, product_name, category, price, date, sales_volume] df[date] pd.to_datetime(df[date]) return df def load_comment_texts(): comments list(Comment.objects.values_list(content, flatTrue)) return comments这里使用select_related是为了减少查询次数。虽然示例数据量小感受不到差别但真实项目数据量增大后这个习惯能避免 N1 查询。4.2 缺失值、重复值和异常值处理数据清洗通常按“缺失值 - 重复值 - 异常值”的顺序处理。在analysis/data_processor.py中增加清洗函数def clean_sales_data(df: pd.DataFrame) - pd.DataFrame: if df.empty: return df # 去除重复行 df df.drop_duplicates(subset[sku, date], keeplast) # 价格转数值 df[price] pd.to_numeric(df[price], errorscoerce) # 销量小于等于0的行如果是模拟数据可以删除真实数据需要结合业务判断 df df[df[sales_volume] 0] # 日期升序排列 df df.sort_values([sku, date]).reset_index(dropTrue) return df说明缺失值不一定都要删除有时可以填充。比如价格缺失可以用同类目均价填充销量缺失可以用前后日期的均值填充。但填充不能盲目必须结合业务语义。使用errorscoerce把无法转换的价格转成NaN后续统一处理。4.3 构造销量预测特征预测销量时不能直接把日期字符串喂给模型要把日期拆成可计算的特征。常见特征包括星期几、是否周末、月份、距数据起始日期的天数以及商品价格和类目编码。在analysis/feature_engineering.py中写import pandas as pd from sklearn.preprocessing import LabelEncoder def build_features(df: pd.DataFrame) - pd.DataFrame: if df.empty: return df df df.copy() df[weekday] df[date].dt.weekday df[is_weekend] df[weekday].apply(lambda x: 1 if x 5 else 0) df[month] df[date].dt.month df[day_of_month] df[date].dt.day df[days_from_start] (df[date] - df[date].min()).dt.days # 类目使用标签编码 le LabelEncoder() df[category_code] le.fit_transform(df[category]) # 商品价格转浮点数 df[price] df[price].astype(float) feature_cols [ sku, date, sales_volume, category_code, price, weekday, is_weekend, month, day_of_month, days_from_start ] return df[feature_cols]特征工程的目标是让模型能够学习到“哪类商品在哪些时间点销量高”。这里把date作为辅助列保留便于后面对齐预测日期但不作为模型输入。5. 训练销量预测模型5.1 数据划分和数据集准备模型训练要避免“用未来数据预测过去”的泄漏。时间序列数据不能随机切分训练集和测试集应该按时间顺序切分。例如用前 150 天训练后 30 天验证。在analysis/model_trainer.py中写import joblib import pandas as pd from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_absolute_error, r2_score from analysis.data_processor import clean_sales_data, load_sales_data from analysis.feature_engineering import build_features def train_model(): df load_sales_data() df clean_sales_data(df) features build_features(df) features features.sort_values([sku, date]) # 每个商品按日期排序后取最后30天作为验证集 split_date features[date].max() - pd.Timedelta(days30) train features[features[date] split_date] test features[features[date] split_date] feature_cols [category_code, price, weekday, is_weekend, month, day_of_month, days_from_start] X_train train[feature_cols] y_train train[sales_volume] X_test test[feature_cols] y_test test[sales_volume] model RandomForestRegressor( n_estimators200, max_depth10, random_state42, n_jobs-1, ) model.fit(X_train, y_train) y_pred model.predict(X_test) mae mean_absolute_error(y_test, y_pred) r2 r2_score(y_test, y_pred) print(fMAE: {mae:.2f}, R2: {r2:.3f}) joblib.dump(model, media/models/sales_model.pkl) return model, mae, r2这里选择了随机森林回归器而不是线性回归是因为销量数据通常存在非线性关系和特征交互。随机森林对异常值容忍度更高也无需做特征归一化适合作为第一个稳定基线模型。5.2 训练命令和模型保存为了让模型训练可以重复执行把它封装成 Django 管理命令。在shop/management/commands/train_model.py中写from django.core.management.base import BaseCommand from analysis.model_trainer import train_model class Command(BaseCommand): help 训练销量预测模型 def handle(self, *args, **options): _, mae, r2 train_model() self.stdout.write(self.style.SUCCESS(f训练完成 MAE{mae:.2f} R2{r2:.3f}))运行python manage.py train_model训练完成后模型文件会被保存到media/models/sales_model.pkl。如果media/models目录不存在需要先创建或者在train_model中增加os.makedirs(..., exist_okTrue)。生产环境保存模型后需要定期重训不能一次训练永久使用。5.3 评估指标如何解读指标含义参考判断MAE预测值和真实值的平均绝对误差越小越好单位是销量RMSE均方根误差对较大误差敏感适合发现异常预测R2决定系数最大是 1越接近 1 越好在销量预测场景中R2 即使只有 0.6 也可能具备业务参考价值因为销量受到促销、库存、竞品等大量外部因素影响。重点要看的指标是 MAE因为它直接反映平均每天差多少件。6. 数据可视化与词云图生成6.1 生成销量趋势图和 Top 商品图可视化代码要解决两个问题一是图片保存到哪二是 Django 模板如何引用。这里把图片统一保存到media/charts/通过 Django 的静态文件服务访问。在analysis/visualizer.py中写import matplotlib.pyplot as plt import pandas as pd from django.conf import settings from wordcloud import WordCloud plt.rcParams[font.sans-serif] [SimHei, Arial Unicode MS] plt.rcParams[axes.unicode_minus] False def create_trend_chart(df: pd.DataFrame, file_path: str): daily df.groupby(date)[sales_volume].sum().reset_index() plt.figure(figsize(12, 6)) plt.plot(daily[date], daily[sales_volume]) plt.title(每日总销量趋势) plt.xlabel(日期) plt.ylabel(销量) plt.xticks(rotation45) plt.tight_layout() plt.savefig(file_path, dpi100) plt.close() def create_top_products_chart(df: pd.DataFrame, file_path: str): top df.groupby(product_name)[sales_volume].sum().nlargest(10) plt.figure(figsize(10, 6)) top.plot(kindbar) plt.title(销量 Top 商品) plt.xlabel(商品名称) plt.ylabel(总销量) plt.tight_layout() plt.savefig(file_path, dpi100) plt.close()中文字体是关键坑。SimHei在 Windows 常见Linux 服务器可能没有该字体需要安装fonts-wqy-zenhei或使用其他中文字体否则图表会出现方框。6.2 生成评论词云图词云图需要先加载评论数据再用空格拼接所有文本。wordcloud 默认字体对中文支持不好必须指定一个支持中文的字体路径。def create_comment_wordcloud(comments, file_path): text .join(comments) font_path C:/Windows/Fonts/simhei.ttf # Windows 默认黑体路径 wordcloud WordCloud( font_pathfont_path, width800, height400, background_colorwhite, max_words100, ).generate(text) plt.figure(figsize(10, 5)) plt.imshow(wordcloud, interpolationbilinear) plt.axis(off) plt.tight_layout() plt.savefig(file_path, dpi100) plt.close()如果评论数据只有少量词语词云图效果可能不明显。可以适当增加评论量或者使用jieba分词后过滤停用词。这里不引入 jieba是为了保持最小案例可运行真实项目建议加入分词避免词云变成整句。6.3 静态文件与 media 目录配置在settings.py中配置 media 路径import os MEDIA_URL /media/ MEDIA_ROOT os.path.join(BASE_DIR, media)在开发环境中为了让 Django 直接提供 media 文件需要在config/urls.py中追加from django.conf import settings from django.conf.urls.static import static urlpatterns [ # 已有路由 ] if settings.DEBUG: urlpatterns static(settings.MEDIA_URL, document_rootsettings.MEDIA_ROOT)生产环境不能依赖 Django 提供静态文件应该交给 Nginx 或 CDN。但这个配置在开发调试阶段足够。7. Django 集成与页面展示7.1 视图函数加载模型和图表图表生成后页面要展示趋势图、Top 商品图、词云图和预测结果。视图函数负责调用分析模块并把图片路径和预测结果传入模板。在shop/views.py中写import os import joblib import pandas as pd from django.shortcuts import render from django.conf import settings from analysis.data_processor import load_sales_data, clean_sales_data, load_comment_texts from analysis.visualizer import create_trend_chart, create_top_products_chart, create_comment_wordcloud def dashboard(request): df load_sales_data() df clean_sales_data(df) chart_dir os.path.join(settings.MEDIA_ROOT, charts) wordcloud_dir os.path.join(settings.MEDIA_ROOT, wordcloud) os.makedirs(chart_dir, exist_okTrue) os.makedirs(wordcloud_dir, exist_okTrue) trend_path os.path.join(chart_dir, trend.png) top_path os.path.join(chart_dir, top.png) wc_path os.path.join(wordcloud_dir, comments.png) create_trend_chart(df, trend_path) create_top_products_chart(df, top_path) comments load_comment_texts() create_comment_wordcloud(comments, wc_path) # 加载模型并预测下一个30天 model_path os.path.join(settings.MEDIA_ROOT, models, sales_model.pkl) next_30_prediction 0 if os.path.exists(model_path): model joblib.load(model_path) # 构造简化特征实际项目中需要从数据库提取最后日期 last_date df[date].max() future_dates pd.date_range(startlast_date pd.Timedelta(days1), periods30) # 这里只做汇总展示实际应按每个商品分别预测 next_30_prediction round(future_dates.size * 50) # 示例占位 context { trend_chart_url: settings.MEDIA_URL charts/trend.png, top_chart_url: settings.MEDIA_URL charts/top.png, wordcloud_url: settings.MEDIA_URL wordcloud/comments.png, total_sales: int(df[sales_volume].sum()), product_count: df[sku].nunique(), next_30_prediction: next_30_prediction, } return render(request, shop/dashboard.html, context)上面代码中next_30_prediction部分用了简化占位逻辑。真实项目中应该按商品逐一构造未来特征再通过model.predict()得到每个商品的预测销量并求和。这里保留占位是为了让页面先跑通避免因特征构造不完整导致报错。7.2 模板渲染数据面板创建shop/templates/shop/dashboard.html!DOCTYPE html html langzh-hans head meta charsetUTF-8 title电商数据看板/title /head body h1电商销量预测数据看板/h1 div p总销量{{ total_sales }}/p p商品数{{ product_count }}/p p未来30天预测销量{{ next_30_prediction }}/p /div div h2每日销量趋势/h2 img src{{ trend_chart_url }} alt趋势图 stylemax-width: 100%; /div div h2Top 商品/h2 img src{{ top_chart_url }} altTop商品图 stylemax-width: 100%; /div div h2评论词云/h2 img src{{ wordcloud_url }} alt词云图 stylemax-width: 100%; /div /body /html创建shop/urls.pyfrom django.urls import path from . import views urlpatterns [ path(dashboard/, views.dashboard, namedashboard), ]在config/urls.py中把shop.urls挂载到根路径from django.contrib import admin from django.urls import include, path urlpatterns [ path(admin/, admin.site.urls), path(, include(shop.urls)), ]然后启动开发服务器python manage.py runserver浏览器访问http://127.0.0.1:8000/dashboard/如果看到三张图和统计数字说明整条链路已经跑通。7.3 提供预测 API 接口除了页面展示还可以提供一个 JSON 接口方便其他系统调用预测结果。在shop/views.py中再写一个视图import json from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt csrf_exempt def predict_api(request): if request.method POST: body json.loads(request.body or b{}) sku body.get(sku) days int(body.get(days, 30)) # 真实项目中按 SKU 构造特征并调用模型 return JsonResponse({sku: sku, predicted_days: days, prediction: placeholder}) return JsonResponse({error: method not allowed}, status405)API 接口是生产环境常见的扩展点。预测服务通常不会直接在 Web 请求里训练模型而是提前训练好模型接口只负责加载模型并返回预测结果。这样既保证响应速度也便于把预测服务单独部署。8. 常见问题排查电商数据分析项目在本地复现时最容易遇到的问题集中在依赖、中文、路径和模型加载四个方面。下表整理了常见的现象和排查路径。问题现象常见原因检查方式解决方案pip install wordcloud报错缺少编译依赖或 Python 版本过高查看报错日志中的缺失头文件安装系统依赖或使用预编译 whl或改用其他分词词云库图表中文显示为方框matplotlib 未配置中文字体或系统无字体打印plt.rcParams[font.sans-serif]设置字体路径安装中文字体词云图中文不显示wordcloud 默认字体不支持中文查看词云图是否只有乱码指定font_path为中文字体文件预测模型加载很慢模型文件过大或特征列不一致检查 pkl 文件大小和特征列顺序压缩模型、裁剪特征、使用缓存数据库迁移失败模型字段变更或表已存在运行python manage.py makemigrations --check根据报错重新生成迁移文件或备份后重建表爬虫抓不到数据页面结构变化或请求被限制先单独运行爬虫脚本打印 HTML 片段更新选择器增加请求头降低频率manage.py train_model报错数据为空或特征列缺失在训练前打印 DataFrame 的列名和行数回到数据导入步骤确认import_sales已运行其中模型特征列不一致是很容易被忽略的坑。如果在 Jupyter Notebook 里训练时使用了不同的列名保存模型后再用 Django 加载model.predict()会因为特征数量不一致而报错。避免方式是在训练脚本和预测脚本中使用同一个特征列表常量例如抽到analysis/feature_engineering.py中统一维护。9. 最佳实践与扩展方向9.1 发布前检查清单项目并不是能显示图表就结束了。要部署到生产环境至少还要完成下面几项检查。数据库从 SQLite 切换为 MySQL 或 PostgreSQL并配置连接池。设置DEBUGFalse配置ALLOWED_HOSTS。静态文件和 media 文件交给 Nginx 或对象存储。模型文件加入版本号例如sales_model_20240101.pkl避免覆盖丢失。爬虫任务要增加频率控制和异常告警。Django 日志要记录数据导入、模型训练和 API 请求关键步骤。模型训练任务建议通过定时任务执行例如使用 Celery Beat 或系统 crontab避免手动触发。预测接口要增加鉴权和限流防止被外部任意调用。9.2 模型更新机制销量预测模型不是一次性训练完就能长期使用。商品销售会随季节、促销和市场竞争变化模型效果会逐渐下降。推荐的做法是每周或每天增量重训一次并记录每次训练的评估指标。当指标明显下降时回滚到上一版模型。实现增量重训不难但要注意数据划分。从上次训练截止日期之后的数据作为新数据不要和历史数据混在一起随机切分否则会发生时间泄漏。9.3 性能优化方向当前示例数据量很小性能问题不明显。真实项目中可能会出现以下瓶颈。爬虫数据量很大直接写入 Django ORM 较慢应该先批量聚合再入库或使用 bulk_create。pandas 读取全部数据可能占用大量内存可以只读取最近 N 天数据用于训练。图表生成是 CPU 密集操作建议使用缓存例如按天缓存图片数据未更新就不重新生成。模型预测接口如果并发高可以把模型加载到内存后复用而不是每次请求都joblib.load。9.4 对新手的学习建议如果第一次接触这个项目可以先不碰爬虫直接用管理命令生成模拟数据把 Django pandas sklearn 的链路跑通。然后再尝试替换成真实爬虫数据。这样遇到问题时就容易定位是哪一层出错。后续可以继续扩展的方向包括使用 Prophet 或 LightGBM 提升预测效果加入促销活动、天气、节假日等外部特征使用 ECharts 替换 matplotlib 做交互式图表以及把预测结果通过定时任务推送企业微信或邮件。每一步扩展都会让项目更接近生产形态但核心的数据链路和工程规范不会变。回到本文最开始的问题销量预测项目最难的不是训练模型而是把数据采集、存储、清洗、特征工程、模型训练和 Web 展示稳定地串起来。建议先跑通最小案例再逐步加入真实数据、监控和模型更新机制。这条链路一旦稳定后续扩展任何模型或图表都只是替换其中一环。
返回列表