尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python实战:从爬虫到可视化,构建乐高销售数据分析系统

发布时间:2026/9/24 19:24:13

资讯中心
01
ARTICLE

Python实战:从爬虫到可视化,构建乐高销售数据分析系统

Python实战:从爬虫到可视化,构建乐高销售数据分析系统
手头正好有一个做完了的Python项目代号hx2900主题是乐高玩具的销售数据分析。当时做这个项目的初衷很简单乐高产品线极多价格从几十到几千都有系列关键词明显评论数据量大非常适合拿来练手数据分析全流程。这个系统做的事情也不复杂自动抓取电商平台乐高玩具的公开商品数据清洗后分析价格分布、系列热度和评价情况最后用一个带界面的数据看板展示结果。如果你正在学Python爬虫、pandas数据处理或者可视化这个项目能帮你把零散的知识串成一条线。市面上的Python数据分析教程大多用titanic、iris这类经典数据集练完之后你对真实业务数据的处理仍然没有手感。乐高玩具数据不一样它带有明显的商品属性价格带分布、系列热度、评价数和销量的关系这些都是电商分析里真实存在的话题。把这个项目走通之后换一个类目比如毛绒玩具、积木桌、遥控车思路完全一致只改关键词和字段映射就行。这也是我想把整个过程整理成文章的原因。1. 项目思路与整体方案设计1.1 需求背景与项目目标先说清楚这个系统要解决什么问题。玩具类目在电商平台上的商品数量庞大一个品牌就能有上千个SKU手工整理价格、评论数、系列归属这些信息几乎不可能。乐高又是个特殊品类它的套装命名非常规律像机械组城市组星球大战这些关键词会直接出现在商品标题里这给后续的系列分类提供了很大便利。但便利归便利数据量一旦上来Excel就扛不住了。做这个系统之前我手动整理过一周的乐高销售数据光是去重和分类就花掉了大半天时间。而且手工整理出来的数据只能做静态报表换个维度重新分析又得从头再来。hx2900的目标就是把这套流程自动化采集层负责拿数据清洗层负责把脏数据变成干净的结构化数据分析层负责计算价格带宽、系列热度、评价分布这些指标展示层则提供一个可以点击、筛选、导出的可视化看板。我把它定位成一个轻量级的终端工具而不是一个大而全的平台所以技术方案尽量精简。整个项目大概一千多行Python代码单机能跑数据量在几万条以内完全不卡。如果你只是做单品分析或者小类目研究这个体量刚刚好。1.2 技术选型为什么要用 Python这个项目选用Python主要是因为数据分析生态太成熟了。采集可以用requests解析用parsel数据处理用pandas可视化可以用pyecharts界面用Flet整个链路不需要切语言。相比Node.js或者JavaPython在这些环节的代码量最少调试也最直接。界面部分我纠结过一阵子。最初考虑用PyQt或者Tkinter但它们写界面代码比较啰嗦而且图表嵌入麻烦。后来试了Flet它的思路是让你用Python写UI底层渲染交给Flutter界面在Windows、macOS、浏览器里都能跑。对数据分析这种内部工具来说Flet的开销比Electron小代码结构又比PyQt简洁最终就定它了。数据存储方面我没有上MySQL直接用CSV加SQLite的组合。采集阶段先落CSV方便随时用Excel检查数据长什么样分析阶段再把清洗后的数据写入SQLite这样在Flet界面里做筛选和聚合时查询速度有保证。这个选择完全基于项目规模如果后续数据量到百万级再考虑换MySQL也不迟。1.3 系统架构与数据流设计hx2900整体分成四层。第一层是采集层负责请求商品列表页解析商品卡片的标题、价格、评论数、店铺名这些字段。第二层是存储层原始数据按采集批次写入CSV文件文件按日期命名避免重复采集覆盖。第三层是分析层用pandas读入CSV完成去重、缺失值处理、类型转换、字段衍生然后按价格带、系列、评价维度做聚合统计。第四层是展示层Flet读取SQLite里的聚合结果渲染图表和数据表格并提供筛选控件。各层之间通过文件或数据库解耦这样有个好处某一天采集逻辑出问题不影响分析和展示模块的运行。我实际开发时就是先把采集和分析跑通最后才写界面中间调试省了很多事。数据流向大概是电商公开页面 - 爬虫解析 - 原始CSV - 清洗后的SQLite - 分析聚合结果 - Flet看板。流程看起来长但因为每一层都独立替换任何一层都很容易。这里额外提醒一句爬虫只是技术手段不是目的。我在项目里只采集商品标题、价格、评论数这些公开信息不碰用户昵称、收货地址、聊天记录等隐私内容请求频率也控制在合理范围确保不给目标网站造成压力。合规和数据伦理这个问题做任何采集项目都要放在第一位。2. 数据采集爬虫与数据合规2.1 数据源选择与采集范围数据源我选了某主流综合电商平台原因是它商品全、公开字段多而且列表页结构相对规整。搜索关键词就是乐高采集范围是搜索结果前50页每页约40个商品算下来大概2000条商品记录。对于分析一个类目的价格带和系列热度来说这个样本量足够了。采集字段上我只保留了分析真正需要的几个商品标题、价格、评论数、店铺名称、商品链接。标题是后续系列分类的核心输入价格和评论数是分析热度的重要指标店铺名称可以用于品牌集中度分析。其他像运费、库存、优惠券这些字段因为接口里经常变动而且跟初版分析目标关系不大暂时没纳入采集。做这个选择的时候我给自己定了个原则宁可字段少而准不要字段多而杂。爬虫一旦开跑字段越多清洗成本越高。很多刚入门的朋友喜欢把页面上所有信息都抓下来结果存了一堆用不上的数据分析时反而眼花缭乱。先想清楚要回答什么问题再倒推需要哪些字段效率会高很多。2.2 爬虫核心逻辑与防反爬处理采集层我是用requests加parsel实现的。请求列表页URL把返回的HTML交给parsel解析用CSS选择器提取商品卡片的各项信息。核心逻辑分三步构造请求头、发送请求并解析、翻页循环。为了不给对方服务器增加压力每次请求之间加了一个1到3秒的随机延迟同时设置了重试机制遇到网络波动自动重试三次。import time import random import requests from parsel import Selector HEADERS { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 } def fetch_page(keyword, page): url https://example.com/search params {q: keyword, page: page} for attempt in range(3): try: resp requests.get(url, paramsparams, headersHEADERS, timeout10) resp.raise_for_status() return resp.text except Exception as exc: print(f第{page}页第{attempt 1}次请求失败: {exc}) time.sleep(2) return None def parse_items(html): sel Selector(html) items [] for card in sel.css(.item-card): title card.css(.title::text).get() price card.css(.price::text).get() comment card.css(.comment-count::text).get() shop card.css(.shop-name::text).get() items.append({ title: title, price: price, comment: comment, shop: shop, }) return items def main(): all_items [] for page in range(1, 51): html fetch_page(乐高, page) if not html: continue items parse_items(html) all_items.extend(items) time.sleep(random.uniform(1, 3)) print(f共采集 {len(all_items)} 条数据)代码里的URL和选择器是示意写法实际项目里要根据目标站点的页面结构调整。采集过程中最常遇到的问题是反爬比如IP被临时限制、验证码、数据加密。我的处理策略是先降低请求频率观察是否恢复如果不行再考虑更换User-Agent或者用代理池。不过对于个人学习项目优先放宽频率限制不要一上来就上对抗手段那既没必要也不合规。2.3 数据落地存储格式与字段设计采集完成的数据我直接存成CSV文件名带时间戳方便回溯。CSV的列名在写爬虫时就要定好我用的字段是title、price、comment、shop、url后续所有分析都围绕这五列展开。为了让数据更干净采集时我就顺手做了初步处理价格去掉货币符号转成浮点数评论数里万的写法统一转成数字标题两端的空白字符去掉。存储之后我用pandas读一遍检查基本质量看看有没有明显异常比如价格为0、评论数缺失、标题重复率过高等。这一步相当于采集层的体检问题越早发现后面清洗越省力。import pandas as pd df pd.read_csv(lego_raw_20250101.csv) print(df.shape) print(df.isna().sum()) print(df.duplicated(subset[title]).sum())如果重复率超过5%我会考虑是不是翻页时采集到了重复商品这时候要回到解析逻辑里检查分页参数是否正确。数据落地这块没有太多高深技术但做扎实了后面分析会很顺畅。3. 数据清洗与销售分析实战3.1 数据清洗的几个关键步骤爬虫拿到的数据一定是不完美的这也是所有真实项目都躲不开的环节。hx2900里最典型的几个脏数据问题商品标题里混着[官方旗舰店]这类营销后缀、价格字段偶尔出现暂无报价、评论数有时连续多个零、同一个商品因为参与多个活动被重复采集。清洗逻辑就是围绕这些问题逐项处理。首先是去重。商品维度上两个商品只要标题完全一致就认为是同一个商品保留评论数最多的一条。标题清洗则要移除旗舰店自营正品这类跟产品本身无关的词汇保留核心名称。价格字段先统一类型把299或者299.00元清洗成浮点数。评论数如果为空我选择用该价格带下同系列商品的中位数填充而不是直接删除避免样本量缩水。df[title_clean] ( df[title] .str.replace(r\[.*?\], , regexTrue) .str.replace(r【.*?】, , regexTrue) .str.strip() ) df[price_num] ( df[price] .astype(str) .str.replace(r[^0-9.], , regexTrue) .pipe(pd.to_numeric, errorscoerce) ) df[comment_num] ( df[comment] .astype(str) .str.replace(万, 0000, regexFalse) .str.replace(r[^0-9], , regexTrue) .pipe(pd.to_numeric, errorscoerce) ) df df.dropna(subset[price_num]) df df.drop_duplicates(subset[title_clean], keeplast)清洗的每一步都应该能解释为什么。比如为什么评论数缺失用中位数填充而不是用0。因为0代表一条评论都没有和缺失是完全不同的业务含义如果用0填充分析时会低估该商品的实际热度。中位数则能保留价格带内的大致水平。这类判断没有标准答案但对分析结论影响很大。3.2 销售分析维度价格带、系列热度与评价分布清洗后的数据可以开始回答业务问题了。我设计的分析维度主要有三个。第一个是价格带分布把商品价格从0到2000元以上切成若干区间统计每个区间的商品数量和评论总数这样可以直观看出整个类目的主力价格区间在哪里。第二个是系列热度从清洗后的标题里提取乐高系列关键词比如机械城市星球大战创意百变好朋友哈利波特等统计每个系列的商品数和评论数。第三个是评价分布分析评论数高低的商品特征比如高评论商品的价格集中在哪个区间。这三个维度不是孤立的。实际操作中我会先看价格带分布确定中位价格再按系列交叉分析看看哪些系列覆盖了高价位和高质量评论。比如机械组通常定价偏高评论数也稳定那么它的系列热度背后是客单价驱动还是粉丝忠诚度驱动就可以结合价格和评论数的联合分布去猜。系列关键词提取我用了最简单的办法写一个关键词映射表遍历标题匹配。虽然也可以用分词加分类模型但对2000条数据来说规则法足够准确而且解释性强出问题好排查。关键词表需要反复迭代我第一版漏了科技这个旧称后来看数据时发现很多机械组商品被归到了其他补上之后分类准确率立刻上来了。3.3 核心指标计算与Python实现核心指标的计算我全部用pandas搞定。价格带我写了一个分组函数用pd.cut分段。系列热度则是把关键词匹配结果映射成一个新列再groupby聚合。import numpy as np import pandas as pd bins [0, 100, 200, 300, 500, 800, 1200, 2000, np.inf] labels [0-100, 100-200, 200-300, 300-500, 500-800, 800-1200, 1200-2000, 2000] df[price_band] pd.cut(df[price_num], binsbins, labelslabels, rightFalse) band_stats ( df.groupby(price_band, observedTrue) .agg(item_count(title_clean, count), total_comment(comment_num, sum)) .reset_index() ) series_keywords { 机械组: [机械, 科技, technic, 机械组], 城市组: [城市, city], 星球大战: [星球大战, star wars], 创意百变: [创意百变, creator], 好朋友: [好朋友, friends], 哈利波特: [哈利波特, harry potter], } def map_series(title): for series, keywords in series_keywords.items(): for kw in keywords: if kw.lower() in title.lower(): return series return 其他 df[series] df[title_clean].map(map_series) series_stats ( df.groupby(series) .agg(item_count(title_clean, count), avg_price(price_num, mean), total_comment(comment_num, sum)) .sort_values(item_count, ascendingFalse) .reset_index() )这段代码跑完之后基本分析表就出来了。再进一步我会计算相关系数看看价格和评论数之间的关系。乐高这个品类很有意思实测下来价格和评论数的相关性并不强说明高价套装未必评论多很多高价机械组是叫好不叫座而低价的小盒装才是评论量主力。这种洞察不是单看一张表能发现的必须靠多维交叉。4. 可视化与交互系统实现Flet界面4.1 为什么选择Flet做数据看板数据算出来了如果只是打印在终端里终究不够直观。hx2900的展示层我选了Flet这个库让我眼前一亮的地方在于它把Flutter的优秀控件搬到了Python里写界面像写布局代码一样自然同时不用处理HTML和CSS。对于我这种以数据处理为主、前端能力一般的开发者来说Flet的学习成本很低。相比Flask加ECharts的方案Flet省去了搭建Web服务、管理HTTP路由的步骤。相比PyQtFlet的布局控件更现代图表嵌入也更简单。界面做出来是一个左侧菜单、右侧内容区的经典看板结构在Windows桌面上直接运行也可以起一个Web服务在浏览器里打开。开发调试时我在浏览器里看效果最终给使用者推荐桌面模式体验更接近一个独立软件。有个小坑先提醒一下Flet的API版本更新比较快网上很多教程还是旧版本写法。我在项目里锁定了一个稳定版本并且在代码注释里标注了版本号。后续升级Flet时一些控件属性名可能会变比如部分组件的width和height参数调整。遇到问题优先看官方迁移文档不要盲目照搬老代码。4.2 系统界面布局与交互设计Flet界面我把它分成了三块。左侧是导航菜单包含数据总览价格分析系列热度评论分析四个页面。中间是主内容区根据菜单切换显示不同内容。顶部有一条工具栏显示当前选中的分析维度和数据更新批次。底部是数据表格和图表联动显示明细记录。以价格分析页面为例主内容区放一个柱状图横轴是价格带纵轴是商品数量图表下方放一个表格展示每个价格带的商品数、评论总数、平均价格和占比。用户在左侧选中价格分析后系统从SQLite里读取预计算的聚合结果生成图表和表格。为了提升响应速度聚合结果在程序启动时一次性加载到内存页面切换时不再查库。Flet里绘图我用了matplotlib先生成PNG图片再通过Image控件嵌入页面。这种方式虽然不如ECharts交互炫酷但胜在简单稳定图表样式完全可控。如果你希望图表可以悬停查看数值可以改用pyecharts生成HTML再用Flet的WebView控件嵌入但那会让打包体积变大我初版没有采用。import flet as ft import matplotlib.pyplot as plt def build_price_chart(band_stats): fig, ax plt.subplots(figsize(8, 4)) ax.bar(band_stats[price_band], band_stats[item_count]) ax.set_xlabel(价格带元) ax.set_ylabel(商品数量) ax.set_title(乐高玩具价格带分布) fig.tight_layout() fig.savefig(price_band.png, dpi150) plt.close(fig) def main(page: ft.Page): page.title 乐高玩具销售数据分析系统 hx2900 page.theme_mode ft.ThemeMode.LIGHT page.add(ft.Image(srcprice_band.png, width700, height400)) ft.app(targetmain)界面代码和数据分析代码我拆成了两个文件data_analysis.py负责计算和生成图表ui_main.py负责界面展示。这样改样式时不用重跑数据分析各自独立迭代。4.3 图表联动与导出功能看板如果只是静态展示价值会大打折扣。hx2900里我加了几个交互点顶部提供一个类目筛选下拉框可以按系列筛选商品选中后所有图表和表格同步刷新底部表格支持点击表头排序方便快速查看评论最多的商品每个分析页面都有一个导出Excel按钮把当前筛选结果保存成本地文件。筛选联动在实现上不复杂核心思路是所有页面组件共享同一个数据源。用户选择系列后程序更新一个全局筛选状态然后重新从内存中的DataFrame取出符合条件的子集刷新图表图片并更新表格数据。因为数据量不大整个过程控制在几百毫秒以内体感很流畅。导出功能我用了pandas的to_excel配合openpyxl引擎。导出文件里包含两部分一个汇总sheet一个明细sheet。汇总sheet放当前页面的聚合结果明细sheet放筛选后的商品原始字段。这样用户既能看到结论也能核对原始数据信任度会高很多。from openpyxl import Workbook def export_to_excel(summary_df, detail_df, path): with pd.ExcelWriter(path, engineopenpyxl) as writer: summary_df.to_excel(writer, sheet_name汇总, indexFalse) detail_df.to_excel(writer, sheet_name明细, indexFalse)导出的时候要注意数据类型pandas里的np.int64、np.float64在写Excel时可能会被openpyxl识别成不常见类型导致Excel打开时提示格式异常。稳妥的做法是在导出前把整型列转成Python原生int。这个问题我在测试时踩过后来加了一行类型转换全部解决。5. 常见问题与排查技巧实录5.1 爬虫采集阶段的坑采集最大的坑不是请求失败而是数据解析出来之后才发现字段位置变了。电商页面的HTML结构经常调整今天能抓到价格明天价格就变成动态加载的数据需要从接口里取。遇到这种情况我建议不要盯着HTML硬啃打开浏览器开发者工具切到Network面板刷新页面看XHR请求返回的JSON往往比解析HTML更稳定。还有一个高频坑就是中文乱码。requests拿到页面后如果编码识别错误解析出来全是乱码。处理方式是在拿到响应后先检查resp.encoding必要时手动指定为utf-8或gbk。不同网站的编码策略不一样需要针对目标站点配置。我这边的目标平台是utf-8所以没有遇到太多麻烦但这个方法还是值得记下来。请求频率这块新手最容易犯规。一开始我把延迟调到0.5秒结果跑了几十页就触发了验证码。后来改成随机1到3秒延迟并且增加了一个每页请求后检查响应长度的逻辑如果连续三页返回的HTML长度明显异常立刻停止爬虫并发送通知。这种自我保护机制既是为了稳定采集也是为了避免给目标站点造成困扰。5.2 数据分析与可视化阶段的坑数据分析阶段最常见的坑是类型错误。CSV读进来后价格列有时是object类型直接求和会报错或者结果诡异。我的排查习惯是读完数据先打印df.dtypes再针对object列逐个检查。另一个坑是pd.cut的分段边界right参数默认是True实际是左开右闭区间我一开始没注意导致价格刚好在边界上的商品被分到下一档后来显式设置了rightFalse才符合直觉。可视化阶段matplotlib中文乱码是个老大难问题。如果你直接在图里用中文标题默认字体下会出现方框。解决办法是提前设置中文字体比如SimHei或者Microsoft YaHei并在代码里通过plt.rcParams配置。这个设置必须在绘图前完成否则不会生效。另外保存图片时dpi不要设太高150足够清晰300会让界面加载明显变慢。Flet嵌入图片时还容易遇到路径问题。开发时用相对路径没问题打包成exe后工作目录变了图片可能找不到。我的处理方式是把所有图片统一放在项目根目录下的assets文件夹并在Flet里用完整路径拼接。如果要给别人用建议用PyInstaller打包时把assets目录一起带上。5.3 项目还能怎么扩展hx2900目前做到的是一个单机版分析看板但它可以扩展的方向非常多。如果你想继续深挖我建议从三个方向入手。第一个方向是增加时间序列分析每天采集一次数据积累一个月之后就能看价格波动和评论增速甚至可以预测哪些系列正在起量。第二个方向是引入更细的评论内容分析不只是评论数而是真正抓取评论文本做关键词提取和情感分析这样能判断用户对颗粒度、拼搭体验、性价比的真实反馈。第三个方向是把系统改造成定时任务加入调度框架每天自动采集、清洗、更新数据库再通过邮件或企业微信推送异常波动提醒。我自己后续打算先把时间序列分析做了。乐高的价格受停产、复刻、联名影响很明显如果能积累几个月的价格数据就能识别出哪些套装在涨价哪些已经进入折扣清仓周期这对二手市场和囤货判断都有参考价值。当然前提还是合规采集数据源不能有侵入性。这个项目前后我迭代了三版第一版只用了requests加Excel手工分析第二版加入了pandas和matplotlib第三版才接入了Flet。每次重构都有明确的目的不是为了换技术而换技术。如果你也想做一个类似的数据分析项目我的建议是先用最熟悉的工具把分析思路跑通再考虑工具的升级和界面的美化。数据分析的核心永远是业务理解和数据质量工具只是让你把想法更快地展现出来。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。