
简介这是一份面向有Python基础、希望入门网络爬虫与数据分析实战的开发者教程完整演示了如何爬取并分析淘宝商品信息。内容以Selenium配合二维码扫码完成模拟登录进而设置请求头、构造翻页URL使用正则从页面中提取商品标题、价格、销量、销售地、评论数等关键字段随后导入pandas、matplotlib、jieba等库依次完成价格分布、销售地统计与词云分析并配有可运行的代码片段。教程章节清晰涵盖背景介绍、模拟登录、商品爬取、数据分析等模块便于读者按步骤复现和扩展。资源为单个PDF文件大小约1012KB适合离线阅读与对照练习。目前已吸引4237人学习对于初学者来说是一份能快速上手电商数据采集与分析流程的实用参考资料也可为相关课程设计或毕业设计提供参考。1. 为什么选择“淘宝商品信息”作为爬虫与分析练习的起点想认真学Python爬虫总得找个合适的练手靶场。我见过不少人一上来就对着某个新闻网站或者技术博客写爬虫结果爬是爬下来了拿到数据却不知道干嘛。最后只能把几千条标题打印在终端里存个CSV就完事甚至直接扔了既没有成就感也练不到什么硬功夫。淘宝商品信息这个场景就不一样了。它是个完整的业务闭环有搜索页、有列表页、有详情页、有动态加载的数据、有登录校验、有反爬策略爬下来之后还能做价格分布分析、销量排行、店铺评价维度拆解等等。这不是简单地把网页HTML拉下来就结束的事而是把“采集—清洗—存储—分析—可视化”整条链路都串起来了。就算你以后不写爬虫这套玩法里涉及的HTTP请求、页面解析、数据清洗、Pandas处理和图表可视化能力放到数据分析、自动化办公、系统监控任何方向上都是通用的硬技能。另外一个很现实的原因是淘宝这类电商平台的数据结构足够复杂商品标题、价格、销量、店铺名、地区、品牌、发货时间散落在不同的DOM节点和XHR接口里处理起来比那些整整齐齐的静态博客有挑战得多。你要真的把它跑通对网页结构的理解、对反爬机制的应对、对数据异常的处理能力都会明显上一个台阶。这篇文章我会把我自己跑通流程的完整思路、代码骨架和踩过的坑都整理出来给你一条可以直接照着走的路径。2. 先搞清楚要爬什么数据还有哪些前置条件需要准备这一节很重要但并不复杂。动手写任何代码之前先把目标字段定下来把环境准备好后面会省掉大量返工的时间。2.1 目标字段的确定逻辑商品信息采集并不是“把页面上能看到的文字都抓下来”这么简单。字段不是越多越好而是根据后续分析需求反推出来的。举个例子如果你想做一件T恤的价格带分析你至少需要商品标题用于分词提取款式、品牌、材质信息价格用于价格分布统计注意促销价和原价可能同时存在销量用于判断哪些价格段卖得动店铺名称用于分析店铺集中度或复购率发货地用于物流时效关联分析商品链接用于后续定向追踪详情页先想清楚分析维度再决定爬什么字段这样你的爬虫才会为目标服务。闭着眼把整个页面全抓下来既容易触发反爬策略又会让数据表冗余到没法看。2.2 环境和依赖清单语言用Python 3.9以上版本就行没有特殊要求。我建议全程用虚拟环境别把依赖装到全局里不然哪天Anaconda和系统Python打架的时候有你受的。依赖库我分成三组列出来用途库名版本建议网络请求requests2.28页面渲染selenium4.x浏览器驱动管理webdriver-manager3.x数据解析lxml / BeautifulSoup4最新数据处理pandas1.5数据存储openpyxl3.1可视化matplotlib / pyecharts最新验证码识别ddddocr可选安装命令很简单pip install requests pandas beautifulsoup4 lxml selenium webdriver-manager openpyxl matplotlib pyecharts ddddocr这里要专门说一下webdriver-manager这个库。很多新手卡在selenium启动这一步是因为Chrome版本升级之后原来的chromedriver不匹配报错报得莫名其妙。用webdriver-manager的话它会自动检测你本地浏览器的版本号并下载对应的驱动一句代码就能解决版本匹配问题from selenium import webdriver from webdriver_manager.chrome import ChromeDriverManager driver webdriver.Chrome(ChromeDriverManager().install())如果还想省事直接把无头模式打开这样就不会每次都弹个浏览器窗口出来options webdriver.ChromeOptions() options.add_argument(--headless) options.add_argument(--no-sandbox) options.add_argument(--disable-dev-shm-usage) driver webdriver.Chrome(ChromeDriverManager().install(), optionsoptions)2.3 关于登录与Cookie的一个实用提醒淘宝的商品搜索页在未登录状态下也能访问但页面上会有一部分数据被降级处理比如某些价格会显示成区间价格而不是精确值部分店铺信息也可能不完整。如果你只是做数据分析和趋势研究未登录状态抓到的数据基本够用。但如果要做更细维度的分析建议在浏览器里手动登录一次然后把Cookie导出来带到请求头里。我个人的做法是先把登录态的Cookie复制成JSON文件存放在本地请求的时候动态读取。这样既不会把账号密码硬编码到代码里也能降低频繁触发验证码的概率。具体代码很简单import json with open(taobao_cookies.json, r, encodingutf-8) as f: cookies json.load(f) headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36, Referer: https://www.taobao.com/, Accept-Language: zh-CN,zh;q0.9, }Cookie文件长什么样就是浏览器开发者工具里Network面板请求标头里那一大串字符你可以手动复制也可以用编辑器的自动化登录流程去拿。手动操作虽然原始但最稳妥适合学习阶段。3. 从网络请求到页面渲染两种爬取路径的对比与选型淘宝这个网站有点特殊它的搜索结果页一部分HTML是服务端渲染的另一部分商品数据是浏览器端通过XHR异步加载进来的。这意味着你先得想清楚到底走哪条路径去拿数据。3.1 直接请求接口快但复杂度藏在签名里淘宝前端的商品列表接口正式名称是https://s.taobao.com/search这个页面地址点进去之后浏览器会发出若干次异步请求其中最关键的是一个JSON接口返回结构里包含商品列表的原始数据。如果你直接在Python里模拟这个请求速度很快几乎秒回数据也是结构化的JSON解析起来非常方便。但问题是这个接口请求头里带上了一堆加密参数比如sign、token、_ksTS、callback这类值。这些参数有的是时间戳有的是通过特定算法生成的签名还有的是和登录态绑定的令牌。如果直接裸请求很快就会被识别为机器行为然后弹滑块验证码。3.2 用Selenium渲染页面慢但能模拟真实用户操作Selenium的思路是直接启动一个真实的浏览器环境让页面像正常用户访问一样完整渲染然后再从渲染后的DOM里提取数据。好处是签名问题它根本不关心因为浏览器自己就把这些参数算好了。坏处是速度慢每翻一页可能要等待2到5秒而且权重控制不当容易被识别为异常流量。对于学习者和中小规模数据采集来说我建议优先用Selenium把流程跑通。数据量控制在几百条到几千条的规模Selenium完全够用。等你的分析模型稳定了确实需要每天定时跑大量的数据了再研究接口签名也不迟。3.3 我的实际选择双层策略我自己跑的时候用的是“优先接口失败降级到Selenium”的策略。在主流程里先用requests直接请求搜索页的JSON接口如果返回的数据里能拿到商品列表就继续如果触发了验证码或者返回的JSON里没有商品信息就切到Selenium重新加载这个搜索URL等页面渲染完成后再提取。这样做的好处是正常情况速度很快异常情况也不会让爬虫直接罢工。代码结构大致是def fetch_page_data(keyword, page_num): url fhttps://s.taobao.com/search?q{quote(keyword)}s{page_num * 44} try: resp requests.get(url, headersheaders, cookiescookies, timeout10) data resp.json() if content not in data: raise ValueError(触发反爬降级到Selenium) return parse_items(data[content]) except Exception as e: print(f[降级] 第{page_num}页走Selenium: {e}) return fetch_with_selenium(url)这里parse_items函数负责把JSON里那一长串HTML字符串进一步解析成结构化字段。为什么JSON里会有HTML因为淘宝的接口返回的content字段本身就是渲染好的DOM片段需要再用lxml把它提取一遍。这算是这个接口的一个特色。3.4 搜索URL的两个关键参数搜索URL里的q是搜索关键词s是起始位置。你会发现s的取值范围是0、44、88这样递增的而不是按照页数1、2、3来算。这是淘宝的分页逻辑每页实际展示44个商品所以第二页要从第44个商品开始取。如果你传错了s的值大概率会返回一堆重复数据。另外还有一个sort参数值得关注。默认是综合排序想要按销量排序可以加sortsale-desc想要按价格从低到高用sortprice-asc。这个参数对后续分析很有价值因为综合排序的结果往往混合了广告位单纯基于它做价格带分析会失真。4. 商品列表数据解析思路从混乱的HTML碎片里提取结构化数据现在到了写解析代码的环节。我用Selenium模式举例因为这个模式最直观也最容易照着敲出来。4.1 定位单个商品的容器节点打开淘宝搜索页按F12进入开发者工具用选择器点一下任意一个商品卡片你会发现每个商品都包裹在一个div标签下但这个标签的class名称是动态变化的比如items、item--JX25L4C这类带随机后缀的值。直接按class选择是不可靠的。稳定的选择方式是使用CSS选择器的后代关系比如先定位所有拥有>div[class*items] div[class*item--]这个写法可以模糊匹配到包含“item”关键字的容器节点即使class名里带了随机字符串也不会漏掉。不过用之前最好先在页面里检查一下这个选择器命中的节点数量是否和页面显示的商品数量一致防止抓歪。4.2 提取标题、价格、销量、店铺名Selenium拿到的是WebElement对象每个字段的提取方式略有差异标题一般在a标签的title属性里或者span标签的文本里。优先取title属性因为文本内容可能被截断显示。价格通常在span标签内部而且很可能是一个strong标签里放了两位小数的价格。取文本之后用float()做转换。销量常见格式是“已售9000”或“2000人付款”正则表达式提取数字即可。店铺名一般在商品的右下角是一个div下的span文本。我自己写的一个通用提取函数片段如下def parse_item(item): try: title item.find_element(By.CSS_SELECTOR, a[title]).get_attribute(title).strip() except: title item.find_element(By.CSS_SELECTOR, h3).text.strip() try: price float(item.find_element(By.CSS_SELECTOR, strong).text.replace(¥, )) except: price None try: sale_text item.find_element(By.CSS_SELECTOR, div[class*deal]).text sales int(re.search(r(\d), sale_text.replace(万, 0000)).group(1)) except: sales None try: shop item.find_element(By.CSS_SELECTOR, div[class*shop]).text.strip() except: shop None return { title: title, price: price, sales: sales, shop: shop, }这里有个细节值得单独说销量文本里经常出现“5000人付款”或者“1.2万人付款”这种格式。正则匹配数字时不能直接用一个\d就完事因为“1.2万”会被拆成1和2。我的处理办法是先判断文本里有没有“万”有的话就把数字部分先转为浮点数再乘以10000。上面代码里用replace(万, 0000)是图省事只在整数万时有效如果是“1.2万”就会出错。更稳妥的写法是import re def extract_sales(text): if not text: return None num re.search(r([\d.]), text) if not num: return None n float(num.group(1)) if 万 in text: n * 10000 return int(n)4.3 翻页的循环控制Selenium翻页最稳妥的方式是定位页面底部的“下一页”按钮并点击而不是直接修改URL里的s参数跳转。因为直接改URL相当于重新加载整个页面速度慢不说还更容易被网站怀疑是脚本操作。点击翻页之后要用显式等待等第一个商品元素重新出现在DOM中再继续解析。一个常见的坑是页面刚加载完成时商品节点还在但价格区域的数据还没渲染出来这时候去取会拿到空值。所以等待条件最好设成“价格元素可见”而不是单纯“商品元素存在”。翻页循环我建议设置最大页码限制比如最多爬20页也就是880个商品对分析样本来说已经足够。5. 实际操作中绕不开的五个反爬问题与破解思路淘宝的反爬体系在不同场景下表现不一样但最常见的几种我几乎都踩过逐个说下我的处理方式。5.1 登录滑块验证码触发滑块验证码是高频事件尤其是使用Selenium时动作太规律的话几乎每几页就会弹一次。最简单的缓解方案是增加每页之间的随机延时比如time.sleep(random.uniform(3, 6))让操作节奏尽量接近真人浏览。如果滑块真的弹出来了Selenium可以定位到滑块元素并模拟拖拽但成功率不稳定。我更建议的做法是准备一个手动干预机制检测到滑块弹出后把浏览器切到非无头模式暂停程序让你手动划一下滑块然后按回车继续。代码里用input(请手动完成滑块验证后按Enter...)就可以实现。5.2 高频请求被限流限流的特征很典型前两百条数据正常过了某个临界点之后所有请求都返回空数据或者验证码页面。这是因为淘宝会根据IP的请求频率做动态封禁。对策有两个方向一是放慢速度二是切换IP。对于学习项目来说放慢速度就够用了。把单页请求间隔拉长到8到10秒每次会话最多连续跑10到15页就停一会儿。数据量虽然不够大但足以支撑后续分析练习。如果你想上量那需要认真考虑代理池方案但这里水比较深不是一篇教程能讲透的。5.3 页面动态渲染导致的空数据Selenium模式下经常遇到的情况是页面结构加载出来了但商品列表区是一片空白。这通常是因为浏览器在设置Cookie时出错或者登录态丢失导致页面重定向到了登录页。解决方法是每次创建浏览器实例时先访问一次淘宝首页等首页完全加载后再访问搜索页。这样能确保一些基础Cookie先种下来。5.4 User-Agent和请求头伪装很多教程会让你随机切换User-Agent但在淘宝这个场景下意义不大因为Selenium本身就是真实浏览器指纹不需要刻意伪装。反而如果你用了requests模式User-Agent必须设置成和主流浏览器一致否则极大概率被拒。headers { User-Agent: Mozilla/5.0 ..., Accept: application/json, text/plain, */*, Referer: https://www.taobao.com/, }Referer这个字段不要漏它告诉服务器你从哪个页面跳转过来的。直接带搜索页URL作为Referer比带淘宝首页更自然。5.5 数据去重与异常值过滤爬虫采集的数据往往带着各种脏数据最常见的是重复商品和空价格。每次分页返回的数据可能在前后页有重叠尤其是综合排序时广告位商品会重复出现。处理办法是在Pandas里按商品链接或商品ID去重没有唯一ID的话用“标题价格店铺名”拼接字段去重也可以。价格空值、销量空值的记录我建议直接过滤掉因为后续可视化时这些空值会影响统计结果。还有一类异常值需要特别留意同一个商品链接出现在不同页时价格可能略有波动因为促销价和原价展示时机不同这部分也要按一定规则处理比如取第一次采集到的值。6. 商品数据分析与可视化从数据表到洞察的转化数据采集的部分跑通之后接下来做的事情才是爬虫的价值所在——数据分析。这一部分没有理论上的难度但能把数据用起来的人才是真正把项目做完整了。6.1 加载数据并进行清洗先把采集到的数据读进Pandas DataFrameimport pandas as pd df pd.read_csv(taobao_items.csv) df.drop_duplicates(subset[title, price], inplaceTrue) df df.dropna(subset[price, sales]) df[price] df[price].astype(float) df[sales] df[sales].astype(int)清洗完之后可以先扫一眼数据概况print(df.describe()) print(df[price].quantile([0.25, 0.5, 0.75]))从这里能快速感知到数据的基本分布比如平均价格、中位数价格、销量的波动范围。6.2 价格带分布分析价格带分布是电商数据分析最基础也最常用的视角。先划分价格带比如0-50、50-100、100-200、200-500、500以上这几档然后统计每个价格带的商品数量和平均销量。bins [0, 50, 100, 200, 500, float(inf)] labels [0-50, 50-100, 100-200, 200-500, 500] df[price_range] pd.cut(df[price], binsbins, labelslabels) range_stats df.groupby(price_range, observedTrue).agg( 商品数(title, count), 平均销量(sales, mean), 平均价格(price, mean) ).round(1)这个结果是很有业务含义的如果某个价格带商品极多但平均销量极低说明竞争非常激烈但需求可能并没有那么大反之如果某个价格带商品不多但平均销量非常高往往意味着细分需求没有被完全满足。6.3 销量Top商品的标题关键词提取销量最高的前50个商品的标题能直接反映当前市场的主流卖点。用jieba做分词和词频统计import jieba from collections import Counter top_items df.nlargest(50, sales) words [] for title in top_items[title]: words.extend([w for w in jieba.cut(title) if len(w) 1]) word_count Counter(words).most_common(20) print(word_count)这一步做出来会很有成就感因为你会直观地看到用户真正关心的点是什么。比如有一回我爬女装商品词频Top里竟然还有“显瘦”和“遮肚”这两个词这就是非常明确的消费者偏好信息。6.4 可视化展示matplotlib画价格分布直方图、pyecharts画地区分布图、箱线图看价格离散程度都是常规操作。我提供一个最简单的直方图代码import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False df[price].hist(bins50) plt.xlabel(价格) plt.ylabel(商品数量) plt.title(商品价格分布) plt.show()注意这里一定要设中文字体否则图上的中文全是方框这个坑无数人踩过。7. 几个实用经验分享采集节奏、数据落盘与后续扩展7.1 数据落盘格式建议采集结果除了存CSV我建议同时存一份Excel因为有大量字段需要人工查阅时会方便很多。用ExcelWriter可以把多个分析结果写到同一个工作簿的不同Sheet里。with pd.ExcelWriter(taobao_analysis.xlsx) as writer: df.to_excel(writer, sheet_name原始数据, indexFalse) range_stats.to_excel(writer, sheet_name价格带统计)7.2 关于延时与频率的平衡很多人觉得爬虫嘛快就是好。但真做数据采集的人都知道关键在于能稳定地跑完整个采集过程而不是一味追求速度。你可以设计一个自适应的延时策略一开始请求间隔短一些比如2秒如果连续两次请求都失败了就把间隔翻倍如果连续成功10页再把间隔慢慢减回来。用这种策略能很好地平衡速度与安全性。7.3 后续还能怎么扩展这个项目的天花板不低。采集端可以扩展成定时任务每天自动跑一遍把每天的价格存进数据库形成时间序列数据然后做价格波动趋势预测分析端可以通过情感分析处理某件商品的历史评价如果要商业化还可以对接企业微信机器人把降价提醒推送到群里。我自己后来做了一个很实用的扩展把分析结果输出成PDF周报每周自动汇总竞争对手的定价变化。这个听着很高大上其实底层就是这篇教程里的采集加分析代码套了一层定时任务和PDF生成逻辑而已。7.4 最后说两句心里话很多人学爬虫都死在“从入门到放弃”的路上原因是项目选得太难或者太无聊。淘宝这个题目难度适中数据量大分析价值高练完之后你的requests、Selenium、Pandas、正则、反爬应对这些能力全都扎扎实实地过了一遍。千万别只抄代码一定得亲手跑一遍把报错一个接一个地解决掉。等你跑通了再回头看网上那些“淘宝数据爬取”的开源项目你会发现自己已经能看懂九成以上了。希望这篇分享能让你少走几步弯路。动手跑起来比什么教程都管用。本文还有配套的精品资源点击获取