ARTICLE DETAIL

资讯详情

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

基于Python的乐高玩具销售数据分析系统实战

基于Python的乐高玩具销售数据分析系统实战 1. 项目概况与动手前的思考1.1 为什么偏偏拿乐高玩具练手先说结论乐高玩具这个品类天生就是做销售数据分析的绝佳样本。我一开始并不是为了做项目而做项目而是自己确实想买几款乐高结果发现一个问题——同一个型号在不同渠道的价格能差出三成而所谓“热门款”“绝版款”到底谁在涨价、谁在清仓光靠肉眼翻网页根本看不出来。于是我就想与其被别人种草不如自己把数据拉下来看看。这个项目就是在这样的动机下诞生的。标题里写的“基于Python的乐高玩具数据销售分析系统”本质上做的事情是把电商平台上的乐高玩具销售数据抓下来做清洗、聚合、分析最后用图表把“哪些款式卖得好、价格怎么波动、什么系列最受欢迎”这些信息讲清楚。为什么说乐高适合做分析样本因为它有几个数据特点SKU够多全球在售型号常年保持在几百到上千个样本量可观系列分层明显科技、城市、创意、超级英雄、迪士尼等系列价格带差异大价格体系复杂有定价、折扣价、二手溢价、绝版涨价等多种情况有利于做多维度分析用户画像清晰购买者既有给孩子买玩具的家长也有成人玩家收藏党消费动机差异大分析起来有意思。如果你是一个刚学完Python基础、正愁不知道拿什么练手的人这个项目的难度梯度也很友好。它不要求你会深度学习不涉及复杂的数学推导只要你对 pandas、requests、pyecharts 这几样工具熟悉就能完整做下来。而做完之后你对“怎么把一个原始需求变成一套能用的数据系统”会有一个整体认知这个认知比语法本身值钱得多。1.2 这套系统的“输入”和“输出”到底是什么先不急着写代码咱们把一个分析系统的边界画清楚。我做的这套系统输入是电商平台的公开商品页面数据包括商品标题、型号、系列、价格、销量、评价数、上架时间等。输出是一套可视化的分析报表能回答下面几类问题整体销售大盘什么样——总销售额、总销量、平均客单价哪些系列贡献了主要收入——按系列聚合的销售额占比哪些单品是爆款——销量排名和销售额排名 Top 榜单价格带分布——不同价位区间的商品数量和销售贡献折扣和促销对销量的影响——打折款和非打折款的销量差异价格波动趋势——某款热门型号的价格随时间的变化曲线。整个系统的技术链路也不复杂就是数据采集 → 数据清洗 → 入库存储 → 聚合分析 → 可视化展示。每个环节都有独立模块单独拆出来也可以复用。后面我在做代码重构的时候把每个模块都设计成函数式调用方便单独调试这个习惯在项目后期帮我省了很多事。说句实在话这个系统的代码量并不大核心代码加起来也就几百行但它把数据分析项目最常见的完整流程走了一遍。你想明白它就等于把 Python 数据处理这条线串起来了。2. 技术选型与工程结构2.1 为什么用 Python 而不是 Excel 或 BI 工具可能有人会问拿 Excel 透视表也能做销售分析Tableau 拖拽一下也能出图何必用 Python 写一套系统这个问题我在做项目之前也想了一阵。Excel 和 BI 工具确实能解决“单次分析”的问题但它们有三个短板第一数据获取依赖手工导出每次都得重复操作。我要分析的是电商平台上的数据平台不会直接给你一个 Excel 文件你得自己想办法拿数据而 Python 的 requests 和 scrapy 天然就是干这个的。第二清洗逻辑不可复用。今天你发现价格字段里有“¥899.00”这种带货币符号的字符串手动删一下就行。但明天数据量变成几千条后天要分析历史趋势你再手工处理一遍试试Python 写一次清洗函数以后跑一遍就完事。第三分析维度扩展困难。Excel 透视表虽然灵活但要同时做多个维度交叉分析、计算环比增长、追踪价格历史波动步骤非常繁琐。pandas 里一个 groupby 加 agg 就能搞定的事情在 Excel 里你得折腾半天。所以我的结论是如果你只是做一次性的小数据分析Excel 就够但如果你要做的是一套“可以反复运行、持续追踪”的分析系统Python 是性价比最高的选择。这个项目本质上不是要做一个“一次性的报告”而是要做一个“可以每个星期跑一遍的系统”Python 的脚本化优势在这里体现得特别明显。2.2 核心依赖库与它们的职责边界这个项目用到 Python 生态里几个非常经典的库我按它们在项目里的作用简单梳理一遍requests负责发送 HTTP 请求从电商页面获取 HTML 数据。它只负责“把数据拿回来”不负责“读懂数据”。parsel 或 BeautifulSoup负责从 HTML 中解析出商品名称、价格、销量等字段。两者选一个顺手就行我用的 parsel因为它的 xpath 语法写起来更快。pandas数据分析阶段的核心库负责数据清洗、字段重命名、缺失值处理、分组聚合等。项目里 70% 的分析逻辑都建立在 pandas 之上。numpy主要用它在计算均值、百分比、分位数等数值操作时提供支撑。pyecharts负责把分析结果渲染成交互式图表支持鼠标悬停查看数据、缩放等操作。它生成的是 HTML 图表文件不需要额外搭建前端。openpyxl用于把最终结果导出到 Excel 报表方便给不懂 Python 的人查看。sqlite3Python 内置负责数据的持久化存储。有人可能觉得小题大做但用它比直接存 CSV 文件更规范而且查询的时候能直接用 SQL 做筛选。安装方式很简单直接一行命令搞定pip install requests parsel pandas numpy pyecharts openpyxl如果你用的是 Anaconda 环境pandas 和 numpy 通常已经装好了不需要重复安装。这里有个小建议千万别在全局 Python 环境里直接装这些库最好单独建一个虚拟环境。我一开始图省事直接装在全局环境里后来装 pyecharts 的时候把某个依赖库的版本给覆盖了导致另一个项目跑不起来花了一下午才排查清楚。用python -m venv lego_analysis建一个独立环境从源头避免这种问题。2.3 目录结构怎么设计才不混乱很多刚入门的朋友写代码喜欢把所有的逻辑都堆在一个文件里结果项目写到一半文件变得又臭又长想改个采集逻辑还得在一堆代码中间找位置。我这个项目的目录结构参考了小型数据工程项目的标准姿势每个职责一个文件维护起来很清晰lego_sales_analysis/ │ ├── config.py # 全局配置数据库路径、请求头、目标URL ├── database.py # 数据库初始化与连接工具 ├── spider/ │ ├── __init__.py │ ├── fetcher.py # 发送请求获取页面HTML │ └── parser.py # 解析HTML提取商品字段 ├── analysis/ │ ├── __init__.py │ ├── cleaner.py # 数据清洗函数 │ ├── aggregator.py # 聚合分析函数 │ └── visualizer.py # 图表生成函数 ├── main.py # 主入口串联整个流程 ├── output/ # 存放生成的图表和报表 │ └── *.html / *.xlsx └── data/ └── lego_sales.db # SQLite数据库文件这个结构的好处是“关注点分离”以后想换数据源只改 spider 目录想换分析维度只改 analysis 目录main.py 保持稳定不会被频繁改动。3. 数据采集与处理模块详解3.1 爬虫模块的目标网站与合规边界做数据采集之前必须先把合规问题说清楚。我选择的数据源是一家公开电商平台的搜索结果页面采集的是页面上公开展示的商品信息——标题、价格、销量、店铺名等。这种公开数据的采集在法律上有一定争议空间但只要遵守几个基本原则做个人学习用途问题不大不采集用户的个人隐私数据不绕过登录验证、不破解验证码、不攻击服务器控制请求频率不给目标网站造成访问压力只用于个人学习和研究不用于商业用途。我在代码里特意把请求间隔设置成了 3 到 5 秒的随机值并且每次请求都会更换 User-Agent模拟一个正常用户的访问行为。这不是鼓励你去钻空子而是技术人的基本素养——你对别人服务器的尊重也是在保护自己的合规边界。再补充一点如果你的目标是某个特定的电商平台最好先看一下对方的 robots.txt 以及平台的服务条款。有些平台明确禁止爬虫采集那最好换一个数据源。3.2 抓取到的原始数据长什么样因为电商网站的结构经常改版我不建议把采集逻辑写得太“死”。我当时的做法是先把页面保存成 HTML 文件再用解析库提取关键字段。这样就算页面样式变了我只需要调整解析规则不用重写整个爬虫。从搜索结果页面我提取的字段包括商品标题主要用来提取型号和系列信息价格页面上展示的当前售价原价如果有划线价的话顺便记录月销量直接展示的销量数据评价数买家评价总量店铺名称判断是官方旗舰店还是第三方卖家商品链接方便后续回溯查看详情页。把这些数据直接存成 CSV 的话大概长这样标题,价格,原价,月销量,评价数,店铺,链接 乐高City城市系列60283假日野营车积木玩具,269,299,2000,15000,乐高官方旗舰店,https://... 乐高科技系列42115兰博基尼FKP积木,2599,3199,300,4800,乐高官方旗舰店,https://...这些原始数据问题很多比如标题里混了不少和商品无关的营销词汇价格字段带“¥”符号销量字段可能是“2000”这种带加号的文本。这些脏数据如果不清洗后面计算平均值的时候会直接报错。所以处理是必须的。3.3 数据清洗的完整流程与关键操作数据清洗是整套系统里最枯燥但最重要的部分“脏数据进、干净数据出”是目标。我按照下面几步来做清洗每一步都有明确的处理逻辑。第一步处理缺失值。有些商品没有原价有些没有销量这些数据如果直接丢弃样本量会减少很多。我的处理策略是销量缺失的直接删除因为这是核心分析字段原价缺失的用折扣价填充表示无折扣评价数缺失的填 0。第二步统一数据类型。价格字段从字符串“¥269.00”转成浮点数 269.0销量字段从“2000”去掉加号转成整数。这一步用 pandas 的str.replace()加astype()方法就能完成但要注意处理“万”这个单位——有些商品月销量是“1.2万”需要先换算成 12000否则直接转数字会报错。第三步从标题中提取型号和系列。乐高产品的标题通常有规律比如“乐高 City 城市系列 60283 假日野营车”。我是用正则表达式匹配标题里的“系列”关键词和 4 到 6 位数字型号来提取的。这一步比较繁琐但做好了后面的系列分析就有数据基础了。第四步处理重复数据。同一款商品可能会在搜索结果中出现多次但来自不同店铺价格也不同。我的策略是保留每个型号在各店铺的记录不做去重因为分析“同款不同渠道的价格差异”本身就是有价值的信息。清洗完之后原始数据大概会缩水 10% 到 20%——主要是一些无效记录和无法解析的脏数据被过滤掉了。这是正常的别心疼。import pandas as pd df pd.read_csv(raw_sales.csv) # 统一价格字段去掉货币符号转为浮点数 df[price] df[price].str.replace(¥, ).str.replace(,, ).astype(float) # 处理“万”单位的销量 def parse_sales(text): text str(text).replace(, ) if 万 in text: return float(text.replace(万, )) * 10000 return float(text) df[month_sales] df[month_sales].apply(parse_sales) # 提取型号标题中连续4-6位数字 df[model] df[title].str.extract(r(\d{4,6}))3.4 数据入库SQLite 建表与索引设计清洗好的数据要有地方存。我用的是 Python 内置的 sqlite3 库不需要额外安装数据库服务非常适合这种小规模数据项目。建表语句如下CREATE TABLE IF NOT EXISTS lego_products ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT, model TEXT, series TEXT, price REAL, original_price REAL, month_sales INTEGER, comment_count INTEGER, shop_name TEXT, product_url TEXT, crawl_date TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );我建了一个crawl_date字段用来记录每次采集的日期。这样同一个型号在不同日期抓到的价格都会保留下来后续可以直接画价格随时间变化的趋势线。为了查询效率我在model和series字段上建了索引。数据量只有几千条的时候可能感觉不到区别但如果你是做大范围的采集索引能明显加快分组查询的速度。4. 销售数据分析与可视化实现4.1 整体销售大盘三个核心指标数据分析不是上来就画图表而是先想清楚要回答什么问题。我首先关注的是“大盘”情况——这个市场整体有多大。计算三个指标总销售额所有商品的price * month_sales之和总销量所有商品的month_sales之和平均客单价总销售额除以总销量。用 pandas 实现非常直接df[sales_amount] df[price] * df[month_sales] total_sales df[sales_amount].sum() total_units df[month_sales].sum() avg_price df[sales_amount].sum() / df[month_sales].sum()这三个数字能让你一眼看出市场的体量级。我当时算出来的平均客单价在 400 到 600 元之间这符合乐高定价偏高的定位。客单价高意味着消费者下单前会比较仔细折扣对销售的影响也会更敏感。这就引出了后面两个分析方向。4.2 系列销售结构与爆款识别乐高产品线是按系列划分的比如 City城市、Technic科技、Creator创意、Harry Potter哈利波特、Star Wars星球大战等。不同系列的受众、价格带、销售表现差异非常大。我按系列做了分组聚合计算每个系列的销售额占比和平均价格series_stats df.groupby(series).agg( total_sales(sales_amount, sum), total_units(month_sales, sum), avg_price(price, mean), product_count(title, count) ).sort_values(total_sales, ascendingFalse)分析结果很有意思贡献销售额最高的往往不是销量最大的系列而是那些均价高的系列。比如科技系列的单品价格高虽然销量不如 City 系列但销售额常常反超。这就是数据分析里常说的“销售额 销量 × 客单价”两个因子要拆开看不能只看单一指标。爆款识别相对简单按销量排序取 Top 10按销售额排序取 Top 10两者交叉的部分就是“既叫好又叫座”的明星产品。我当时发现有一两款城市系列的小套装价格不到 100 元销量却碾压所有产品典型的“引流款”。4.3 价格带分析与促销效果评估价格带分析是把商品价格切成几个区间看每个区间内的商品数量和销售额贡献。区间划分可以用 pandas 的cut()方法bins [0, 100, 300, 500, 1000, 5000, float(inf)] labels [0-100, 100-300, 300-500, 500-1000, 1000-5000, 5000] df[price_band] pd.cut(df[price], binsbins, labelslabels)分析发现100-300 元这个价格带是销量主力而 1000 元以上的高端产品虽然数量少但贡献了相当比例的销售额。这说明乐高产品线的“金字塔结构”非常明显——用低价产品保市场覆盖用高价产品赚利润。促销效果评估这块我用“是否有原价标记”作为是否打折的判断依据对比打折商品和非打折商品的平均月销量打折商品的平均销量大约是非打折商品的 2.3 倍但打折商品的客单价明显更低所以对销售额的带动并没有销量那么夸张。这说明促销带来的更多是“流量效应”而不是“利润效应”。如果你想做更深入的评估还可以算折扣力度和销量增幅之间的相关性看看是不是折扣越大销量越高——答案不一定是线性的有的品类折扣过大反而让消费者怀疑产品有问题。4.4 可视化报表用 pyecharts 输出交互图表分析结果最后要给人看。我选择了 pyecharts因为它的图表是 HTML 格式可以在浏览器中交互查看不需要搭前端服务很适合个人项目。我做了四类图表第一销售额系列分布饼图。一眼看过去哪个系列占比最大视觉冲击力最强。from pyecharts.charts import Pie from pyecharts import options as opts pie Pie() pie.add( series_name销售额占比, data_pair[list(z) for z in zip(series_stats.index, series_stats[total_sales])], radius[40%, 70%] ) pie.set_global_opts(title_optsopts.TitleOpts(title乐高系列销售额占比)) pie.render(output/series_pie.html)第二价格带分布柱状图。横轴是价格区间纵轴是商品数量或销售额用柱子的高度对比不同价格带的承载能力。第三销量 Top 10 商品横向条形图。采用的是商品标题中提取出来的“系列 型号”标签而不是完整标题不然图表上会挤满一大串文字。第四价格波动趋势折线图。选取几款热门型号按采集日期画价格折线直观展示价格变动。这个图表需要多次采集数据才能画出来所以我的建议是——系统的采集功能最好设计成“可重复运行”的模式隔一段时间跑一次积累数据趋势分析才有意义。最终的 HTML 图表彼此独立但我会在 main.py 里写一个简单的组合页面把图表通过iframe嵌套到一个总览页面里用的时候翻一个页面就够。5. 典型问题与避坑经验5.1 新手最容易翻车的三个地方这个项目做完我总结了几个自己踩过的坑写出来给大家避雷。第一个坑是解析 HTML 时不先查看页面结构。很多人拿到网页第一件事就是写解析代码结果发现提取出来的全是空值然后怀疑是反爬。其实大部分时候是选择器写错了。正确的做法是先保存一份 HTML 文件到本地用浏览器开发者工具仔细确认目标元素的 XPath再开始写代码。先把解析逻辑调通再接入网络请求。第二个坑是编码问题。部分电商页面返回的编码不是 UTF-8而是 GBK 或 GB2312。如果你直接用response.text拿到的字符串会乱码。正确做法是先检查response.encoding或者直接使用response.content然后通过response.apparent_encoding来解码。这个细节我当时查了一晚上。第三个坑是忽略请求频率控制。刚开始写爬虫的时候很多人喜欢用循环快速抓取几千条数据结果把目标服务器压力搞大自己的 IP 被临时封禁。控制请求间隔是对别人负责也是对自己负责。我在 fetcher 模块里设置了一个随机间隔的函数每次请求之间 sleep 3 到 5 秒宁可慢一点也不要给自己找麻烦。5.2 数据分析阶段的逻辑陷阱数据清洗和分析阶段也有一些容易犯的逻辑错误。第一个是“幸存者偏差”——只分析当前在售的商品而忽略了下架商品。但下架商品里可能有大量历史爆款不看它们你对市场的理解就不完整。解决办法是定期把每次采集的数据都存下来不要把上个月的数据覆盖掉。第二个是“口径不一致”——比如有的商品月销量是整数有的显示的区间“500”有的显示“1.2万”。如果不用统一的口径做清洗后面计算平均值会偏差很大。这类问题必须在清洗阶段处理干净。第三个是“忽略时间因素”——销量是一个累计概念但如果采集周期过短看不到趋势变化。我对这块的反思是初版分析只用了单次采集的快照数据结论停留在“静态分析”层面。后来坚持每周采集一次攒了两个月数据才真正看到价格波动和销售变化的趋势。5.3 系统扩展方向这套方案还能往哪儿走项目做到当前版本其实只是完成了基础框架。如果你想把它扩展成更完整的数据分析系统几个方向供参考增加多平台对比分析。目前只采了一个平台的数据你可以把另外两三家主流电商平台的数据也接进来做渠道价格对比。接入自动化定时任务。用系统自带的计划任务程序比如 Windows 的任务计划程序或 Linux 的 cron让采集脚本每周自动运行一次数据积累越来越厚。增加预测模型。用历史销量数据训练一个简单的时间序列模型比如 ARIMA 或 Prophet预测未来一段时间的销量走势。这一步有难度但做出来很有意思。做一个简单的 Web 展示界面。可以把 pyecharts 生成的 HTML 图表整合到一个 Flask 服务里让用户在线查看分析结果不再依赖本地文件。不过这些都是“锦上添花”。核心还是先把基本链路跑通让数据从“原始网页”到“可视化报表”的流程形成闭环。6. 最终成果与实用建议6.1 项目跑通后的效果长什么样整个项目完成之后最直观的成果是一个可视化总览页面。打开之后你能看到最上面一行是核心指标卡片显示总销售额、总商品数、平均客单价中间是系列销售占比饼图和价格带分布柱状图下面紧接着是销量 Top 10 榜单和促销效果对比图最后是几款重点型号的价格走势折线图。整个页面所有图表都可以鼠标悬停看具体数值比静态图片好用得多。我把这个页面发给几个同样玩乐高的朋友看他们的第一反应都是“这个型号我买贵了”。这算是项目最有成就感的一刻吧。技术层面整个系统跑一次大约需要十几分钟因为爬虫设置了请求间隔分析计算只需要几秒钟。对于个人学习研究来说这个效率完全够了。6.2 给想复刻这个项目的人几条建议如果你也想做一套类似的销售分析系统我建议从这几点入手第一不要急着选复杂的框架。初学者把 requests 和 pandas 用熟比一上来就学 scrapy 和 Spark 更实际。项目最难的地方不是“用什么工具”而是“怎么把一个模糊的问题拆解成清晰的步骤”。第二先做一个最小可用版本。第一版哪怕只采集 50 条数据、只分析一个维度也比踌躇满志地规划半年再动手强。我自己的项目也是这样先跑通一条数据从采集到图表展示的链路再逐步增加功能。第三一定要保留原始数据。不论清洗后的数据多规整原始数据都是你的“底稿”出了问题还能回溯。数据库里的数据也不要只存最终清洗结果最好把采集时间、原始标题和原始价格也存一份。第四别怕报错。报错是学习过程中最正常的反馈不要一看到 Traceback 就慌。学会读报错信息、定位到具体模块这个能力比记住任何库的 API 都有用。这个项目做完之后我对“销售数据分析”这套流程有了整体印象数据采集是基础数据清洗是重点分析思路是灵魂可视化是表达。四者缺一不可。而 Python 在整个链路里都提供了灵活的工具支持这也是它成为数据分析领域主流语言的原因。如果你想找一个既有挑战性又能学到真东西的项目乐高玩具销售分析这条路值得走一遍。
返回列表