拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Python爬取淘宝美妆商品数据:价格分析与可视化系统实战

这个题目是我在准备毕业设计时在“管理系统”“算法实现”“爬虫应用”这几个大类里反复权衡后才定下来的。说实话刚开始看到“基于Python的淘宝美妆商品数据爬取与价格分析可视化系统”这个题目时第一反应是会不会太“烂大街”但真正做下来才发现这个题目虽然常见可里头的坑和知识点一点都不少从反爬对抗到数据清洗再到前端可视化几乎把Python数据分析这条线的所有核心技能都串起来了。最关键的是它有一个非常清晰的业务场景——美妆商品的价格分析与比价可视化这在答辩时特别好讲评委一听就懂。这篇博文我打算把整个项目的完整实施过程都摊开来讲从技术选型、环境搭建、爬虫策略、数据库设计、数据分析到可视化页面再到我实际开发中踩过的那些坑和对应的排查方法。内容会比较长但每一步都是可以直接照做的适合正在做计算机毕业设计、想系统入门Python爬虫与数据分析、或者想做一个完整数据可视化作品的读者。我尽量用“过来人”的方式写文档里不会讲的细节我都会补上。1. 项目整体设计与技术选型思路1.1 核心需求拆解这个系统到底要做什么拿到题目先别急着写代码第一步是把“一句话题目”拆成可落地的功能模块。我当时画了一张很粗糙的脑图把这个系统拆成了四条主线数据采集、数据存储、数据分析、可视化展示。数据采集负责从淘宝上获取美妆类商品的信息主要包括商品标题、价格、销量、店铺名称、商品链接、评论数、所在地、是否包邮这些字段。数据存储要把爬下来的数据落库方便后续重复分析和增量更新。数据分析要解决的核心问题是“美妆商品的价格带分布是怎样的”“不同品牌的价格区间有没有规律”“销量和价格之间是否存在关联”。可视化展示则是把分析结果变成图表让用户能直观地看到价格分布、品牌排行、折扣力度等结论。这个拆解过程很重要因为后续所有代码和页面都是围绕这四个模块展开的。如果一开始就钻到“爬虫怎么写”的细节里很容易忽略数据分析和展示的完整性最后做出来的东西只有爬虫没有分析答辩时很吃亏。1.2 技术栈选择为什么是RequestsSeleniumFlaskECharts技术选型是我在这个项目里花心思比较多的地方。当时对比了三套方案最终确定了“Requests为主、Selenium兜底”的采集策略再配合Flask搭建Web端、ECharts渲染图表。第一套备选方案是纯Requests直接调接口。淘宝的Web端和移动端都有一些数据接口Requests模拟请求拿JSON数据在理论上是可行的而且速度快、解析简单。但问题在于淘宝的接口签名机制一直在变很多时候请求出去返回的不是数据而是一个滑块验证页面对新手来说排查成本很高。第二套方案是Selenium模拟浏览器。它的优点是几乎不挑反爬策略页面能渲染出来的数据都能拿到非常适合作业和毕设场景。缺点是速度慢几百个商品可能就要跑很久而且对本地浏览器环境有依赖。我最终把Selenium定位为“兜底方案”——当Requests方案被验证码拦住时切换成Selenium继续跑。第三套是纯静态页面爬取也就是直接拿搜索结果的HTML解析。淘宝搜索结果页的商品信息确实是渲染在HTML里的这部分数据可以用Requests直接拿到算是两种方案之间的一个折中。但要注意的是搜索结果的HTML结构改版比较频繁必须写稳定的CSS选择器或XPath定位。前端可视化我选了FlaskECharts的组合。Flask足够轻量适合毕设这种小规模系统ECharts的图表类型丰富、交互效果好做出来的价格分布图、品牌条形图在答辩演示时特别加分。数据库则选了SQLite零配置文件、单文件存储对个人项目和课程设计来说足够了。2. 开发环境准备与依赖库清单2.1 Python环境安装与国内源配置这个项目对Python版本没有特别苛刻的要求3.8到3.11都能跑。我本机用的是Python 3.10。很多同学在环境这步就被卡住了最常见的问题是直接在官网下载Python后安装时忘了勾选“Add Python to PATH”导致命令行里输入python显示“python was not found”。如果你也遇到这个提示重装一次安装向导第一屏最下面那个复选框务必勾上。装好Python之后建议顺手把pip源切到国内镜像不然下载依赖库的速度会让人怀疑人生。我平时习惯用清华源配置方式是临时指定比如pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple如果想“永久”生效就在用户目录下建一个pip.iniWindows或pip.confmacOS/Linux写入[global] index-url https://pypi.tuna.tsinghua.edu.cn/simple trusted-host pypi.tuna.tsinghua.edu.cn很多教程会推荐清华源实测下来清华源和阿里源的速度都挺稳的。建议选一个用就行不要在多个源之间反复横跳因为某些源同步会有延迟容易出现包版本不一致的问题。2.2 项目依赖库清单与安装命令这个项目用到的第三方库不算多但每一样都有明确的用途。我整理了一份清单带注释说明用途方便你按图索骥。pip install requests pip install beautifulsoup4 pip install lxml pip install selenium pip install pandas pip install flask pip install flask-cors pip install pyechartsrequests用来发送HTTP请求获取网页内容BeautifulSoup4配合lxml解析HTML文档提取商品信息selenium是浏览器自动化的兜底方案pandas做数据清洗和统计分析flask搭建Web服务flask-cors处理跨域请求pyecharts可以在纯Python环境下生成ECharts图表。这里的pyecharts和前端直接用ECharts并不冲突——我实际开发时是前端页面直接引入ECharts的JS文件完全用Python生成图表配置反而不够灵活。另外一个容易被忽略的库是fake-useragent它可以随机生成User-Agent避免每次请求都用同一个浏览器标识pip install fake-useragent如果你需要控制爬虫请求频率建议再装一个time库Python内置不用装结合随机延时使用。2.3 开发工具与调试思路编辑器方面我用的是VS Code配合Python插件之后代码补全、调试、Jupyter Notebook都支持得不错。也有不少同学用PyCharm这个纯看个人喜好我自己的体会是毕设项目代码量不大VS Code足够用而且启动速度快很多。调试时建议尽量用“小步快跑”的方式先写一个最小脚本请求单个商品列表页打印前几条数据确认能拿到内容后再逐步扩展成完整采集流程。不要一上来就想跑全量数据否则一旦中间某步出错排查范围会变得很大。3. 数据采集实战淘宝反爬机制与获取策略3.1 淘宝常见的反爬限制有哪些淘宝是国内反爬做得比较严格的电商平台实战前必须先了解它设了哪些关卡。第一道关卡是User-Agent和Cookie校验如果请求头缺失或特征异常服务器会直接拒绝返回数据。第二道关卡是登录校验很多搜索接口和商品详情接口都要求登录态未登录状态下能拿到的数据有限。第三道关卡是滑块验证码这是最让爬虫头疼的一旦触发滑块纯Requests方案基本就废了。第四道关卡是参数签名淘宝的部分接口请求参数里带有加密签名比如页面加载时动态生成的token直接模拟接口时容易复制不全。第五道关卡是访问频率限制同一个IP在短时间内高频访问会触发风控表现为返回空白页、跳转登录页或要求滑块验证。最后还有字体反爬某些页面的价格数字会用自定义字体渲染直接解析HTML会得到乱码或错误数字。这些机制不是每次都会全部触发但你必须清楚每道关卡的存在。实际开发时的策略就是尽量模拟真实浏览器的请求特征降低请求频率遇到验证码就切换兜底方案。3.2 方案一Requests直接请求并解析搜索结果我的主采集方案是直接请求淘宝搜索页的URL然后从返回的HTML里提取商品信息。以搜索“口红”为例请求的核心URL格式是这样的url https://s.taobao.com/search?q口红sortsale-desc这里的sortsale-desc表示按销量排序也可以换成其他排序方式比如综合排序、价格从低到高sortprice-asc或从高到低sortprice-desc。这个参数在做价格分析时特别有用能快速拿到价格两端的商品样本。请求头必须包含完整的浏览器标识。我在项目里写了一个随机User-Agent生成函数from fake_useragent import UserAgent import random def get_headers(): ua UserAgent() return { User-Agent: ua.random, Accept: text/html,application/xhtmlxml,application/xml;q0.9,image/webp,*/*;q0.8, Accept-Language: zh-CN,zh;q0.9,en;q0.8, Referer: https://www.taobao.com/ }拿到HTML后用BeautifulSoup解析。淘宝商品列表页中每个商品卡片在一个带特定class的div里。比较稳妥的做法是先定位所有商品块再分别提取标题、价格、销量、店铺。我项目里的解析逻辑大致是这样的from bs4 import BeautifulSoup import json, re def parse_items(html): soup BeautifulSoup(html, lxml) items [] for div in soup.select(div[class*Card--doubleCard]): title_elem div.select_one(span[class*Title--title]) price_elem div.select_one(span[class*Price--priceInt]) sales_elem div.select_one(span[class*realSales--text]) shop_elem div.select_one(a[class*ShopInfo--shopName]) if title_elem and price_elem: items.append({ title: title_elem.get_text(stripTrue), price: float(price_elem.get_text(stripTrue)), sales: parse_sales(sales_elem.get_text(stripTrue)) if sales_elem else 0, shop: shop_elem.get_text(stripTrue) if shop_elem else }) return items这里的CSS选择器需要根据当时页面结构调整因为这个类名实际上是动态的隔一段时间就变。所以我在项目里把选择器集中放到了配置文件里方便后续统一修改。如果你解析时发现拿不到数据优先检查选择器是否匹配当前页面结构。3.3 方案二Selenium模拟浏览器兜底当Requests方案触发滑块验证时我的做法是切换到Selenium。Selenium的核心价值是它扮演一个真实的浏览器JavaScript渲染、Cookie管理、悬浮验证这些都不需要你额外处理。缺点是速度慢、资源占用高所以它只作为兜底方案。用Selenium前需要先下载对应浏览器版本的Driver。我本机是Chrome用的是ChromeDriver。注意版本一定要匹配否则会报SessionNotCreatedException。安装和调试的完整流程我写在后面“常见问题”章节里这里先给一个关键的启动配置from selenium import webdriver from selenium.webdriver.chrome.options import Options options Options() options.add_argument(--disable-blink-featuresAutomationControlled) options.add_experimental_option(excludeSwitches, [enable-automation]) driver webdriver.Chrome(optionsoptions) driver.get(https://s.taobao.com/search?q洁面sortsale-desc)这个配置的目的很明确去掉WebDriver的自动化特征让网站在加载时更难识别出你这是爬虫。但即便如此仍有可能弹出滑块这时候就需要人工介入完成一次滑块验证之后Cookie有效期内继续采集。所以我的采集流程里加了一个“人工确认”暂停点弹窗提示操作者完成验证后按回车继续。从我的实际经验看Selenium方式跑了大约几百个商品后同样会触发验证码所以它更适合小规模补采不适合全量跑。毕设场景下商品样本量控制在几百到两三千条足够了太高反而会给演示和后续分析带来麻烦。3.4 数据合规与采集纪律重要关于爬虫的合规问题我在做这个项目的过程中反复提醒过自己。淘宝的Robots协议明确禁止了部分爬虫行为用户协议里也对数据抓取有约束。作为毕业设计项目核心目的是学习爬虫技术、数据分析方法和可视化技巧不建议也没有必要去采集大量商业敏感数据或对线上服务造成压力。我在项目中做了三件事来确保项目边界一是限制采集频率每个请求之间随机休眠1到3秒二是控制数据总量只采集搜索页前几页的展示数据不采集用户隐私数据三是采集后的数据仅用于学习和论文演示不对外发布、不用于任何商业用途。建议你在自己的项目里也遵循这样的纪律既是对平台规则的尊重也是保护自己。4. 数据清洗与价格分析方法4.1 数据清洗从“爬下来”到“能用”爬虫拿到的数据通常是“脏”的。第一个典型问题是销量字段淘宝页面上的销量经常写成“2000人付款”或者“已售100”。需要把文本中的数字和量级单位提取出来转换为纯数字。我写了一个解析函数import re def parse_sales(text): if not text: return 0 # 匹配数字部分 nums re.findall(r[\d.], text) if not nums: return 0 num float(nums[0]) if 万 in text: num * 10000 elif 亿 in text: num * 100000000 return int(num)第二个典型问题是价格字段页面里可能出现“¥89.0”或者“89元起”需要清洗成float类型。第三个问题是标题里的字符串噪音比如包含表情符号、大量空格、特殊字符这些在后续做词频分析时需要提前清理。数据清洗的完整流程我建议按这个顺序去重按商品链接或商品ID、格式统一价格、销量转数字、字段补充缺失店铺名的记录填充为“未知”、内容清洗标题去特殊字符。清洗完成后用pandas写入SQLite数据库方便后续查询和分析。4.2 价格分析的核心维度与计算逻辑价格分析是本系统的灵魂。我当时的分析思路分为五个维度价格区间分布、品牌均价对比、销量与价格关系、折扣率分析、热门商品词频。价格区间分布是把商品价格划分为若干个区间比如0-50元、50-100元、100-200元、200-500元、500元以上统计每个区间的商品数量和销量占比。这个分析能直观回答“美妆商品的主流价格带在哪里”。品牌均价对比需要先从标题中提取品牌关键词。美妆品类的品牌词比较集中像雅诗兰黛、兰蔻、完美日记、花西子、欧莱雅、玉兰油这些可以通过维护一个品牌词典来实现。统计逻辑就是按品牌分组计算平均价格和平均销量。销量与价格关系要回答的问题是“是不是越便宜卖得越好”。我用pandas的cut方法把价格分层然后计算每层的平均销量import pandas as pd df[price_bin] pd.cut(df[price], bins[0, 50, 100, 200, 500, 10000]) grouped df.groupby(price_bin, observedFalse).agg( 商品数(title, count), 平均销量(sales, mean), 平均价格(price, mean) )折扣率分析是看原价和实际售价之间的差距。如果采集字段里包含原价和活动价就可以算折扣率如果没有也可以用“低价SKU起售价”和“默认展示价格”做近似折扣判断。这些分析结果最终都要落到数据库的统计表或JSON文件里供前端可视化调用。我的做法是每次分析完成后将聚合结果导出成一个JSON文件前端页面通过Flask接口读取这个JSON。4.3 数据分析代码示例热点品牌Top10与词频统计品牌Top10是答辩时最出效果的图表之一。实现逻辑不复杂但要注意品牌词典的覆盖。我项目里的简化版本如下brand_dict [完美日记, 花西子, 雅诗兰黛, 兰蔻, 欧莱雅, 玉兰油, 珀莱雅, 自然堂, 百雀羚, 卡姿兰] def extract_brand(title): for brand in brand_dict: if brand in title: return brand return 其他 df[brand] df[title].apply(extract_brand) top10 df[brand].value_counts().head(10)词频统计则是把清洗后的标题分词统计出现频率最高的品牌词、品类词、功效词。这里如果引入jieba分词效果会更好但要注意自定义词典做美妆场景时把“口红”“粉底液”“精华液”这类词加进词典分词才准确。我当时没有用jieba而是直接基于词表匹配因为美妆标题里的关键词非常集中词表方式简单且可控。5. 可视化系统设计与实现5.1 数据库表设计与Flask后端搭建数据库表结构是系统的地基。我设计的商品数据表如下字段名类型说明idINTEGER PRIMARY KEY AUTOINCREMENT自增主键titleTEXT商品标题priceREAL价格original_priceREAL原价salesINTEGER销量shopTEXT店铺名称brandTEXT品牌detail_urlTEXT商品链接cityTEXT发货地created_atTEXT采集时间使用SQLite的Python内置模块sqlite3就可以操作。连接数据库时注意设置检查线程因为Flask默认是多线程模式SQLite在默认配置下多线程读写容易报错。我的做法是连接时加上check_same_threadFalse。Flask后端只需要提供少数几个接口商品列表接口、价格分布统计接口、品牌Top10接口、销量价格关系接口。代码结构很清晰from flask import Flask, jsonify, render_template import sqlite3, json app Flask(__name__) def query_db(sql, args()): conn sqlite3.connect(taobao.db, check_same_threadFalse) cur conn.cursor() cur.execute(sql, args) rows cur.fetchall() conn.close() return rows app.route(/api/price_dist) def price_dist(): rows query_db( SELECT price_bin, COUNT(*) as cnt FROM item_stat GROUP BY price_bin ) result [{bin: r[0], count: r[1]} for r in rows] return jsonify(result) app.route(/) def index(): return render_template(index.html)开发时用debugTrue方便热重载但提交演示时要把debug关掉否则会暴露调试接口。5.2 ECharts图表配置与页面布局可视化页面我采用了典型的“大屏看板”布局顶部是系统标题下面用两行三列的网格放置图表。每张图表对应一个分析维度。价格分布用柱状图品牌Top10用横向条形图销量价格关系用散点图折扣力度用饼图商品数量变化用折线图。ECharts的配置不需要从头开始写我直接把官方示例改成了自己的数据源。比如价格分布柱状图的简化配置var chart echarts.init(document.getElementById(priceChart)); fetch(/api/price_dist) .then(res res.json()) .then(data { chart.setOption({ title: { text: 美妆商品价格区间分布 }, tooltip: {}, xAxis: { data: data.map(d d.bin) }, yAxis: {}, series: [{ name: 商品数量, type: bar, data: data.map(d d.count), itemStyle: { color: #e06b6b } }] }); });这里的fetch接口是浏览器原生支持的不需要额外引入axios省了一次依赖。如果图表出现跨域问题多半是因为Flask接口没有返回CORS头加一行flask-cors的配置即可解决。5.3 系统演示流程与页面效果完成开发后系统运行顺序是先运行爬虫脚本采集数据并写入SQLite再运行清洗分析脚本生成统计结果最后启动Flask服务浏览器打开本地页面查看可视化大屏。我在演示时会先把采集到的原始数据表展示一遍让评委看到数据是真实采集来的然后切到分析页面从价格分布图开始讲说明价格带结构其次讲品牌Top10说明市场格局再用销量价格散点图说明低价商品也不一定销量最高。这样一条线讲下来逻辑非常顺畅。页面样式方面我用了一款免费的开源后台模板改了Logo和主色调。整体以深色背景为主图表用亮色突出视觉上比较像专业的数据分析系统而不像普通作业页面。这里也提醒一句不要花太多时间调UI毕业设计评分重点在功能完整性和技术难度界面干净整洁就够了。6. 常见问题与排查技巧实录6.1 高频问题速查表我把开发过程中和身边同学遇到的问题整理成了表格方便你对照排查。现象可能原因解决方案python命令提示“python was not found”安装时未勾选Add Python to PATH重装Python并勾选或手动配置环境变量pip安装包超时默认源在国外速度慢使用清华源或阿里源临时指定-i参数请求搜索页返回空白页或验证码User-Agent缺失或频率过高伪造完整浏览器请求头增加随机延时BeautifulSoup解析不到商品数据CSS选择器过期页面结构已改版检查页面当前结构更新选择器规则Selenium启动时提示驱动版本不匹配ChromeDriver与浏览器版本不一致在Chrome设置里查看浏览器版本下载对应驱动数据库报“database is locked”SQLite多线程写入冲突连接时加check_same_threadFalse或串行写入前端图表不显示JSON格式错误或接口路径不对浏览器F12查看Network请求确认返回数据Flask页面跨域报错后端未返回CORS头使用flask-cors开启跨域价格字段带有货币符号未做清洗统一用正则提取数字部分销量字段出现“2000人付款”文本型销量用parse_sales函数转成数字ECharts图表数据为空统计表中没有数据先确认分析脚本是否执行数据库是否有结果6.2 实操中的避坑经验第一个最值得说的坑是我在采集阶段花了将近两天时间处理“模拟接口失败”的问题。当时想走捷径直接请求淘宝某个内部接口拿结构化JSON结果每次请求要么校验签名失败要么返回的JSON里是加密字段。后来我调整思路回到“页面HTML解析”这条路反而一下就通了。所以我的建议是毕业设计阶段不要去碰逆向接口老老实实解析页面稳定且容易解释。第二个坑是Selenium的“自动化特征”被检测。一开始直接打开浏览器去访问淘宝秒出滑块验证后来在网上找到设置excludeSwitches和disable-blink-features这两个参数的方案才勉强稳定下来。就算这样采集几百条数据后还是会触发验证码所以不要指望一劳永逸。第三个坑更隐蔽数据清洗时机。我最初是爬完一批直接入库入库后才发现价格字段里有文本混杂导致SQLite里存了非数字类型后续分析全报错。后来我改成“先清洗后入库”的管线结构所有字段在写入数据库之前都完成格式转换和校验这样分析阶段就省去了大量重复处理。第四个坑是品牌词典的维护。美妆品牌的写法非常多比如“LANCOME兰蔻”和“兰蔻”都表示同一个品牌如果词典里只有中文名统计时就会漏掉大量数据。我最终在词典里加上了中英文别名映射并做了一次“品牌名归一化”把同品牌的不同写法映射到同一个标准名称。6.3 答辩前的检查清单最后分享一个答辩前检查清单。第一确认数据库文件有真实数据不要拿空表去演示第二确认Flask服务能正常启动页面能加载所有图表第三把爬虫、清洗、分析、可视化四个模块的功能分别演示一遍第四准备好“如果触发验证码怎么办”的应急说明建议提前录好一段采集视频万一现场网络不稳定视频可以作为备用证据第五把项目目录结构整理干净关键代码加上注释评委可能会现场翻代码。结语这个项目做完之后我自己最大的感受是一个“烂大街”的题目并不等于“容易做”恰恰相反正因为题目常见你需要做得足够扎实才能在答辩中脱颖而出。数据爬取考验的是你对反爬机制的理解和工程能力价格分析考验的是你处理脏数据和找规律的能力可视化则考验你把结果讲清楚的能力。最后再分享一个小心得做这类系统的顺序非常关键不要先做可视化页面应该先跑通数据采集和数据清洗拿到一批真实数据后再设计图表。数据质量决定了可视化效果如果分析结果非常离谱再漂亮的图表也只是空中楼阁。我的习惯是每跑完一个阶段就在终端里print几条记录看看确认数据没问题再进入下一阶段。这套流程你如果能坚持下来整个项目会走得很顺。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门