news 2026/5/20 20:09:23

Python爬虫实战(七):Selenium自动化采集苏宁易购商品数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python爬虫实战(七):Selenium自动化采集苏宁易购商品数据

一、前言

在前六篇实战中,我们分别掌握了API接口型爬虫(图书网站)、静态网页解析型爬虫(百度热搜)、大规模分页爬取(水果行情)、高对抗性网站爬取(豆瓣评论)、二进制文件下载(壁纸下载)和POST表单接口爬虫(新发地价格)。这些技术在面对传统服务端渲染页面时游刃有余,但现代电商网站大量采用前后端分离架构懒加载技术,数据通过JavaScript动态渲染,传统的requests+BeautifulSoup组合往往力不从心。

本文将以苏宁易购为目标平台,深入讲解如何:

  • 使用Selenium WebDriver模拟真实浏览器行为
  • 实现自动化搜索页面滚动分页点击等交互操作
  • 处理JavaScript动态渲染的数据加载机制
  • 使用CSS选择器精准定位动态生成的DOM元素
  • 构建电商商品数据采集的完整流水线

目标站点特点:苏宁易购是国内头部电商平台,其搜索页面采用动态加载技术——商品列表随页面滚动逐步渲染,且分页通过JavaScript触发而非URL跳转。这种"滚动加载+JS分页"的组合,是Selenium最经典的适用场景。


二、网站分析与Selenium适用场景

2.1 为什么传统爬虫失效?

在尝试用requests爬取苏宁易购时,会遇到以下问题:

问题原因传统方案局限
页面内容为空商品数据由JS动态加载requests只能获取初始HTML,无法执行JS
滚动后才有数据采用懒加载(Lazy Loading)无法模拟滚动操作
分页无URL变化通过JS点击切换,非页面跳转无法通过URL参数翻页
元素class动态生成前端框架(如Vue/React)渲染静态解析无法定位

Selenium的核心优势:它不是一个HTTP客户端,而是一个真实的浏览器控制器。它启动完整的Chrome/Firefox进程,执行所有JavaScript,渲染完整的DOM树,让我们可以像真实用户一样与页面交互。

2.2 苏宁易购搜索页面分析

打开 苏宁易购口红搜索页,可以看到典型的电商商品列表:

页面特征:

  • 商品以卡片网格形式展示,每张卡片包含:图片、标题、价格、店铺、评论数
  • 初始只加载部分商品,滚动页面后触发AJAX加载更多
  • 分页通过底部"下一页"按钮点击,URL不变,内容通过JS替换
  • 商品信息包裹在item-bg类名的div中,内部通过CSS选择器可精准定位

2.3 动态渲染机制解析

用户访问搜索页 → 服务器返回HTML骨架(无商品数据) ↓ 浏览器执行JS → 发送AJAX请求获取商品JSON ↓ JS渲染DOM → 插入商品卡片到页面 ↓ 用户滚动 → 触发IntersectionObserver → 加载更多商品 ↓ 点击分页 → JS发送新请求 → 替换当前商品列表

关键洞察:商品数据从未出现在初始HTML中,传统爬虫获取的只是一具"空骨架"。只有Selenium这种能执行JS的工具,才能看到最终渲染的完整页面。


三、环境准备与驱动配置

3.1 安装依赖

# 安装Selenium库pipinstallselenium# 下载ChromeDriver(必须与Chrome浏览器版本匹配)# 下载地址:https://googlechromelabs.github.io/chrome-for-testing/# 将chromedriver.exe放入系统PATH,或指定路径

3.2 ChromeDriver版本匹配

ChromeDriver与Chrome浏览器版本必须严格对应:

Chrome版本ChromeDriver版本下载链接
133.0.6943133.0.6943.98下载
132.0.6834132.0.6834.83下载

验证安装:

fromseleniumimportwebdriver# 测试启动browser=webdriver.Chrome()browser.get("https://www.suning.com")print(browser.title)# 应输出"苏宁易购-综合网上购物平台"browser.quit()

四、代码实现与深度解析

4.1 完整源码

fromseleniumimportwebdriverfromselenium.webdriver.common.byimportByimporttimeimportcsv# ========================================# 第一部分:CSV文件初始化# ========================================# 打开CSV文件,'at'模式:追加写入(append text)# 如果文件不存在则创建,存在则在末尾追加# encoding='utf-8':确保中文正常存储# newline='':防止Windows下写入空行(csv模块的特殊要求)f=open('苏宁易购.csv','at',encoding='utf-8',newline='')# 创建DictWriter对象:按字典键值对写入,自动匹配列# fieldnames定义CSV表头顺序,也是字典的键名csv_dict=csv.DictWriter(f,fieldnames={'标题',# 商品标题'价格',# 商品价格'商店',# 销售店铺'评论数',# 累计评论数量'详情页'# 商品详情页链接})# 写入表头(仅首次运行时需要,追加模式下可能重复)# 生产环境中应判断文件是否为空再决定是否写入表头csv_dict.writeheader()# ========================================# 第二部分:Selenium浏览器初始化# ========================================# 目标网站url='https://www.suning.com/'# 启动Chrome浏览器# webdriver.Chrome()会自动查找系统PATH中的chromedriver# 如需指定路径:webdriver.Chrome(executable_path='D:/chromedriver.exe')browser=webdriver.Chrome()# 最大化窗口:确保所有元素可见,避免响应式布局导致元素隐藏# 部分网站在小窗口下会隐藏某些元素,最大化可减少此类问题browser.maximize_window()# 访问苏宁易购首页browser.get(url)# ========================================# 第三部分:模拟搜索操作# ========================================# 定位搜索框:通过ID查找(最稳定的定位方式)# find_element(By.ID, 'searchKeywords'):在页面中查找id="searchKeywords"的元素# 这是Selenium 4.x的语法,旧版使用find_element_by_id(已废弃)search=browser.find_element(By.ID,'searchKeywords')# 输入搜索关键词"口红"# send_keys()模拟键盘输入,支持字符串、特殊键(如Keys.ENTER)search.send_keys('口红')# 固定延时1秒:等待输入完成,避免输入过快导致搜索框未响应# 生产环境建议使用WebDriverWait替代固定延时time.sleep(1)# 定位搜索按钮并点击# click()模拟鼠标点击操作btn=browser.find_element(By.ID,'searchSubmit')btn.click()# ========================================# 第四部分:页面滚动加载(核心技巧)# ========================================defscroll_down():""" 模拟页面滚动,触发懒加载 设计原理: 苏宁易购采用"滚动加载"机制,初始只渲染部分商品 当用户滚动到页面底部时,JS检测到视口变化,发送AJAX请求加载更多 我们需要模拟这个过程,确保所有商品都被加载到DOM中 滚动策略: 分5次滚动,每次滚动到页面高度的20%、40%、60%、80%、100% 这种渐进式滚动比直接跳到底部更自然,更接近真实用户行为 每次滚动后延时1秒,给JS足够的时间发送请求和渲染DOM JavaScript执行: execute_script()允许在浏览器中执行任意JS代码 document.documentElement.scrollTop:当前滚动位置 document.documentElement.scrollHeight:页面总高度 """foriinrange(1,6):# 计算滚动比例:20%, 40%, 60%, 80%, 100%j=i/5# 构造JS代码:设置滚动条位置# f-string格式化,将j的值嵌入JS字符串js_srcllo=f'document.documentElement.scrollTop = document.documentElement.scrollHeight *{j}'# 执行JS代码:浏览器滚动到指定位置browser.execute_script(js_srcllo)# 延时1秒:等待JS加载和渲染# 这是关键:如果滚动后立即查找元素,可能新数据还未渲染time.sleep(1)# ========================================# 第五部分:商品数据提取(核心逻辑)# ========================================defget_detail():""" 提取当前页面的所有商品信息 流程设计: 1. 设置隐式等待:查找元素时最多等待1秒 2. 执行滚动:确保所有商品已加载 3. 查找所有商品节点:通过class名定位 4. 遍历每个节点:提取标题、价格、店铺、评论数、详情链接 5. 写入CSV:持久化存储 定位策略: 使用CSS_SELECTOR进行层级定位,从商品卡片容器出发,逐层深入 这种相对定位比全局查找更精准,避免跨商品的数据错位 """# 隐式等待:设置全局等待时间# 当查找元素时,如果元素未立即出现,Selenium会轮询等待最多1秒# 相比固定time.sleep(),隐式等待更智能,元素出现后立即继续browser.implicitly_wait(1)# 执行页面滚动,触发懒加载scroll_down()# 查找所有商品节点# find_elements(复数):返回所有匹配的元素列表# find_element(单数):返回第一个匹配的元素,无匹配则报错# CLASS_NAME定位:查找class="item-bg"的所有divlis=browser.find_elements(By.CLASS_NAME,'item-bg')print(f"本页找到{len(lis)}个商品")forliinlis:# ---------------- 标题提取 ----------------# CSS_SELECTOR定位:.title-selling-point表示class="title-selling-point"# .text属性:获取元素的可见文本内容(自动去除HTML标签)title=li.find_element(By.CSS_SELECTOR,'.title-selling-point').text# ---------------- 价格提取 ----------------# .def-price:价格显示区域# 价格可能包含"¥"符号和促销信息,保留原始格式price=li.find_element(By.CSS_SELECTOR,'.def-price').text# ---------------- 店铺提取 ----------------# .store-stock:店铺名称和库存信息store=li.find_element(By.CSS_SELECTOR,'.store-stock').text# ---------------- 评论数提取 ----------------# .info-evaluate:评论数量和好评率num=li.find_element(By.CSS_SELECTOR,'.info-evaluate').text# ---------------- 详情页链接提取 ----------------# .img-block > a:class="img-block"的直接子元素a标签# get_attribute('href'):获取元素的href属性值(链接地址)# 这是获取动态链接的唯一方式,因为链接在JS渲染后才生成detail=li.find_element(By.CSS_SELECTOR,'.img-block > a').get_attribute('href')# 组装数据字典info_data={'标题':title,'价格':price,'商店':store,'评论数':num,'详情页':detail}# 写入CSV:DictWriter自动按fieldnames顺序写入csv_dict.writerow(info_data)# 控制台打印:实时观察爬取进度print(info_data)# ========================================# 第六部分:分页爬取主循环# ========================================if__name__=='__main__':# 获取总页数# .fl:页码显示区域的class# .text:获取文本内容,如"共 5 页"# [2]:取第3个字符(索引从0开始),即页码数字# int():转换为整数page_num_text=browser.find_element(By.CSS_SELECTOR,'.fl').text page_num=int(page_num_text[2])print(f"共{page_num}页,开始爬取...")# 循环爬取每一页forpageinrange(1,page_num+1):print(f'\n{"="*50}')print(f'开始爬取第{page}页')print(f'{"="*50}')# 执行数据提取get_detail()# 最后一页不需要点击下一页ifpage==page_num:break# 点击下一页:使用JS执行点击操作# 为什么不用.click()?# 因为"下一页"按钮可能被其他元素遮挡,或处于不可点击状态# execute_script直接触发点击事件,绕过Selenium的交互检查browser.execute_script('document.querySelector("#nextPage").click()')# 等待页面加载:新页面商品渲染需要时间time.sleep(2)# 关闭CSV文件f.close()# 关闭浏览器browser.quit()print(f'\n{"="*50}')print("爬取完成!数据已保存到 苏宁易购.csv")print(f'{"="*50}')

4.2 核心设计思想解析

(1)Selenium定位策略体系

Selenium提供8种元素定位方式,本案例综合使用了4种:

定位方式语法适用场景稳定性
By.IDfind_element(By.ID, 'id')唯一标识的元素⭐⭐⭐⭐⭐
By.CLASS_NAMEfind_element(By.CLASS_NAME, 'class')类名唯一的元素⭐⭐⭐⭐
By.CSS_SELECTORfind_element(By.CSS_SELECTOR, '.class > a')复杂层级关系⭐⭐⭐⭐⭐
By.XPATHfind_element(By.XPATH, '//div[@id="x"]')复杂条件判断⭐⭐⭐⭐

选择原则:

  • ID优先:ID在页面中唯一,最稳定可靠
  • CSS_SELECTOR次之:支持层级、属性、伪类,功能强大且速度快
  • CLASS_NAME慎用:一个class可能被多个元素使用,需确认唯一性
  • 避免XPath:语法复杂,性能较差,仅在CSS无法表达时使用

本案例定位路径:

商品卡片容器: By.CLASS_NAME, 'item-bg' ├── 标题: By.CSS_SELECTOR, '.title-selling-point' ├── 价格: By.CSS_SELECTOR, '.def-price' ├── 店铺: By.CSS_SELECTOR, '.store-stock' ├── 评论: By.CSS_SELECTOR, '.info-evaluate' └── 链接: By.CSS_SELECTOR, '.img-block > a'

关键技巧:先通过CLASS_NAME找到商品卡片容器,再在容器内部使用CSS_SELECTOR相对查找子元素。这种"先定位父节点,再相对查找"的策略,避免了全局搜索导致的字段错位。

(2)滚动加载的模拟原理

这是本案例最核心的技术点。理解滚动加载机制,才能正确触发数据渲染:

# 滚动原理:修改scrollTop属性,模拟用户滚动document.documentElement.scrollTop=document.documentElement.scrollHeight*0.2# ↑ 页面总高度 ↑ 滚动到20%位置

为什么分5次滚动?

策略优点缺点
一次滚动到底部简单快速可能触发过多请求,导致页面卡顿或被封
分5次渐进滚动模拟真实用户行为,降低被封风险耗时稍长

真实用户行为模拟:

  • 用户不会瞬间从顶部滚到底部,而是逐步浏览
  • 渐进滚动给JS足够的时间发送AJAX请求和渲染DOM
  • 每次滚动后停留1秒,模拟阅读时间

替代方案:使用IntersectionObserver API

现代网站使用IntersectionObserver检测元素是否进入视口。Selenium可以通过JS直接触发:

# 直接触发所有懒加载元素的加载browser.execute_script(""" document.querySelectorAll('img[data-src]').forEach(img => { img.src = img.dataset.src; }); """)
(3)隐式等待 vs 显式等待 vs 固定延时

Selenium提供三种等待机制,本案例使用了隐式等待:

等待类型语法原理适用场景
隐式等待implicitly_wait(10)全局设置,查找元素时轮询等待页面加载时间不确定
显式等待WebDriverWait(driver, 10).until(...)条件触发,满足条件立即停止特定元素出现
固定延时time.sleep(3)强制等待指定时间简单场景,但不推荐

最佳实践:

fromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasEC# 显式等待:等待商品卡片加载完成wait=WebDriverWait(browser,10)cards=wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME,'item-bg')))

显式等待比固定延时更智能,元素出现后立即停止等待,既保证稳定性又提升效率。


五、运行效果展示

5.1 浏览器自动化过程

Selenium启动Chrome后,会自动执行以下操作:

  1. 打开苏宁易购首页
  2. 在搜索框输入"口红"
  3. 点击搜索按钮
  4. 自动滚动页面加载商品
  5. 逐页提取数据并点击下一页

5.2 控制台输出

程序运行时的控制台输出如下:

共 5 页,开始爬取... ================================================== 开始爬取第 1 页 ================================================== 本页找到 60 个商品 {'标题': '【官方正品】YSL圣罗兰小金条口红 哑光显白持久不脱色', '价格': '¥350.00', '商店': 'YSL圣罗兰美妆官方旗舰店', '评论数': '2.3万+评价', '详情页': 'https://product.suning.com/0071263964/12100426803.html'} {'标题': 'Dior迪奥烈艳蓝金唇膏999 哑光正红色 显白经典', '价格': '¥370.00', '商店': 'Dior迪奥官方旗舰店', '评论数': '5.8万+评价', '详情页': 'https://product.suning.com/0070087777/11098765432.html'} ... ================================================== 开始爬取第 2 页 ================================================== ...

5.3 生成的CSV文件

爬取完成后,生成的苏宁易购.csv文件结构如下:

标题价格商店评论数详情页
【官方正品】YSL圣罗兰小金条口红 哑光显白持久不脱色¥350.00YSL圣罗兰美妆官方旗舰店2.3万+评价https://product.suning.com/…
Dior迪奥烈艳蓝金唇膏999 哑光正红色 显白经典¥370.00Dior迪奥官方旗舰店5.8万+评价https://product.suning.com/…
完美日记小细跟口红 丝绒哑光显白 持久不脱色¥89.00完美日记官方旗舰店12万+评价https://product.suning.com/…

六、总结

通过本次实战,我们完整掌握了Selenium浏览器自动化爬虫的核心技术:

  1. 浏览器驱动原理:理解WebDriver如何控制真实浏览器进程,执行JS、渲染DOM
  2. 元素定位策略:掌握ID、CLASS_NAME、CSS_SELECTOR等定位方式,理解"相对查找"的设计思想
  3. 交互模拟:实现输入、点击、滚动等用户操作,触发动态数据加载
  4. 等待机制:区分隐式等待、显式等待、固定延时,选择最适合的等待策略
  5. 分页处理:通过JS点击实现无URL变化的分页切换
  6. 反爬对抗:了解无头模式、隐藏自动化特征等进阶技巧
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/20 20:08:21

STM32标准库与HAL库深度对比:从原理到实战选型指南

1. 项目概述:从“库”的选择开始你的STM32之旅当你拿到一块STM32开发板,准备点亮第一个LED,或者驱动一个传感器时,第一个绕不开的问题就是:我该用哪种库来写代码?是传说中的“经典”标准库,还是…

作者头像 李华
网站建设 2026/5/20 20:04:28

工控机如何成为人脸识别系统稳定运行的核心硬件平台

1. 项目概述:当人脸识别遇上工业计算机“刷脸”这件事,从几年前的新奇玩意儿,到现在写字楼、小区、工厂甚至校园门口的标配,也就短短几年光景。我们习惯了不带门禁卡,也习惯了在手机、支付终端前“露个脸”。这背后&am…

作者头像 李华
网站建设 2026/5/20 20:01:52

5G射频测试入门:手把手教你读懂NR-FR1测试模式(TM)与对应测量项

5G射频测试实战指南:从NR-FR1测试模式到仪表操作全解析 第一次接触5G基站射频测试时,面对综测仪屏幕上闪烁的参数和3GPP规范里晦涩的术语,我盯着TM3.1a这个代号发呆了十分钟——它到底想测试什么?为什么偏偏要选256QAM满PRB配置&…

作者头像 李华
网站建设 2026/5/20 19:55:24

时间序列预测损失函数全解析:从MSE到分位数损失的14种选择策略

1. 项目概述:为什么时间序列预测的损失函数如此重要?在时间序列预测项目中,我们常常把大量精力花在模型架构、特征工程和超参数调优上,却容易忽略一个同样关键,甚至在某些场景下决定项目成败的基石——损失函数。损失函…

作者头像 李华
网站建设 2026/5/20 19:55:19

PMOS驱动真的简单吗?揭秘关断延迟背后的电路陷阱

1. PMOS驱动:新手工程师的第一个认知陷阱 第一次用PMOS管做开关电路时,我和大多数初学者一样信心满满——不就是给栅极加个高低电平吗?结果实测100kHz方波驱动时,示波器上的波形直接给我上了一课:本该干净利落的脉冲信…

作者头像 李华
网站建设 2026/5/20 19:54:24

433MHz无线模块多节点通信失效?解析MAC层协议与TDMA解决方案

1. 从“样品OK”到“批量翻车”:一个典型的无线通信陷阱在物联网和工业无线控制领域,433MHz频段的无线模块因其绕射能力强、传输距离远、成本相对低廉而备受青睐。很多工程师在项目选型初期,都会经历一个标准流程:找几家供应商&am…

作者头像 李华