恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Selenium自动化测试实战:从安装驱动到滚动与反爬
首页
资讯中心
/
Selenium自动化测试实战:从安装驱动到滚动与反爬
Selenium自动化测试实战:从安装驱动到滚动与反爬
发布时间:2026/10/11 15:48:00
1. 为什么自动化测试绕不开Selenium1.1 一个“老”框架为什么到现在还在大量使用我入行那会儿自动化测试圈子里最响的名字就是Selenium。十几年过去Playwright、Cypress这些新工具一个接一个冒出来但打开招聘软件看测试开发岗的要求Selenium依然出现在绝大多数JD里。这不是因为大家都恋旧而是Selenium解决的问题足够基础、覆盖面足够广跨浏览器兼容测试、回归测试、页面数据采集、甚至办公软件的网页操作自动化它都能干。我在多个项目里同时用过Selenium和Playwright一个很直观的感受是小步快跑的新项目Playwright确实给人惊喜但凡是接手存量系统、要兼容老版本Chrome、或者团队里只有Java/Python基础没有Node经验Selenium反而是最不容易翻车的选择。它的API设计很直白踩坑资料又多出了任何报错几乎都能在社区里搜到前人的解决方案。这种积累不是新工具短时间能追上的。再说职场价值。懂Selenium不只是会调用几个API而是理解浏览器自动化背后的那一整套机制页面生命周期、元素渲染时机、DOM变化、浏览器驱动和协议通信方式。这些底层认知是通用的哪怕哪一天你切换到其他自动化工具底层思路也一样能迁移。所以我的建议很明确不管你用不用它做主力工具Selenium的基本功必须扎实尤其是它背后的“等待策略”和“元素定位”思维值得反复咀嚼。1.2 它能做什么不能做什么先说能做的打开网页、点击按钮、输入表单、提交数据、拖拽元素、切换iframe、处理多窗口、执行JavaScript、截屏、操作Cookie、模拟键盘事件、无头模式跑批任务这些都属于常规操作。配合WebDriverWait还能精确控制脚本等到某个元素出现、消失或可点击比无脑time.sleep()高出一个段位。不能做什么也要心里有数。Selenium本身不是万能爬虫工具它不擅长处理复杂的图片验证码如果不做任何特征屏蔽它也比较容易被网站识别出自动化身份。很多人以为Selenium装上就能绕过一切反爬这是个误解。它更准确的定位是“浏览器自动化操作框架”而不是“反爬对抗武器”。另外某些需要操作系统级交互的功能比如原生文件上传弹窗Selenium处理起来就比较笨重通常要用AutoIt或者其他系统自动化工具配合。所以什么人适合看这篇文章面向测试工程师、爬虫工程师、运维工程师以及想在Excel和网页之间打通自动化的办公人员。无论你是刚准备入行的新人还是写了两年代码想补细节的初级开发下面这些经验应该都能帮你省掉不少试错时间。2. Selenium安装与驱动匹配环境搭不好后面全白干2.1 安装包版本怎么选很多人一上来就pip install selenium装完写脚本就报错然后一脸懵。这里有个最容易忽略的点Selenium版本和Python版本、浏览器驱动版本之间是有对应关系的。现在主流是Selenium 4.x安装命令还是那条pip install selenium但装完之后我建议立刻检查一下版本号import selenium print(selenium.__version__)为什么强调版本因为Selenium 4改动很大API和3.x不兼容。比如3.x常用的driver.find_element_by_id(xxx)在4.x里已经被废弃必须写成driver.find_element(By.ID, xxx)。网上很多教程还是老写法如果你装的是新库跑起来就会看到DeprecationWarning甚至直接报错。我自己带过的新人里十个有八个踩过这个坑。关于版本取向我的建议是不要追最新。Selenium 4刚出来的时候我试过追新版本结果和当时的ChromeDriver配合出了一堆幺蛾子。后来养成的习惯是优先用各分支的正式发布版本等社区把坑填得差不多了再考虑升级。Python环境建议用虚拟环境管理别把全局环境搞得乌烟瘴气尤其是一个机器上同时有多个项目的场景。2.2 浏览器驱动版本匹配是最大的坎Selenium本身不直接控制浏览器它需要通过一个中间程序——ChromeDriver、GeckoDriver或EdgeDriver——和浏览器通信。这个驱动必须和你本机安装的浏览器主版本匹配否则连接时会直接抛SessionNotCreatedException。我常用Chrome所以拿它举例子。首先在浏览器地址栏输入chrome://version/看到版本号比如120.0.6099.130。然后去ChromeDriver的下载页找对应的版本号。这里有个细节驱动版本不需要精确到最后三位前两段“主版本次版本”一致基本就能用。比如浏览器是120.0.6099.130下载120.0.6099.x系列的驱动即可。驱动下载后可以把它放到系统PATH目录也可以直接在脚本里指定路径。Selenium 4推荐的写法是这样的from selenium import webdriver from selenium.webdriver.chrome.service import Service options webdriver.ChromeOptions() options.add_argument(--headless) # 无头模式不弹出浏览器窗口 service Service(executable_path/your/path/to/chromedriver) driver webdriver.Chrome(serviceservice, optionsoptions) driver.get(https://example.com) print(driver.title) driver.quit()另外Selenium 4内置了Selenium Manager会自动尝试下载匹配的驱动。这个功能在断网环境或者受限网络下不一定好使所以我还是建议手动下载并管理驱动路径至少知道你跑起来的那一瞬间用的是哪个驱动。2.3 第一次运行前的检查清单我每次在新环境里搭Selenium都会花两分钟过一遍清单省得被报错追着跑确认Python是64位还是32位驱动和架构要匹配。确认浏览器没开着多个测试实例有时残留进程会占用端口。写一个最简单的打开页面脚本先跑通再往上加业务逻辑。如果项目里有多个人的环境把驱动版本要求写进README别让下一个接手的人猜。这套流程看着简单但能筛掉一大半环境问题。真正写业务逻辑之前先确保“能打开浏览器、能打开页面、能正常退出”这三件事。3. 从定位元素到模拟操作核心细节解析3.1 八种定位方式优先用哪个Selenium里定位元素的方式有很多但实际工作中我几乎只用三种ID、CSS Selector、XPath。理由是ID最快最稳定CSS Selector简洁易读XPath灵活但性能稍差适合处理复杂结构。其他几种比如ClassName、Name、TagName不是不能用而是在现代前端框架下太容易撞车定位到的元素经常不是你想的那个。举个例子很多前端框架的动态列表里class是重复的用ClassName定位会拿到一坨元素还要自己遍历过滤。这时候用CSS Selector或者XPath指定索引会更可控。不过XPath也不能一上来就写绝对路径那种/html/body/div[3]/div[2]/form/input的写法前端稍微加一层div就全废了。我自己写XPath的习惯是从目标元素的属性、文本内容、层级关系里挑一到两个稳定特征写成相对定位。比如from selenium.webdriver.common.by import By username driver.find_element(By.ID, username) submit_button driver.find_element(By.CSS_SELECTOR, .login-form .submit-btn) item driver.find_element(By.XPATH, //div[classitem and contains(text(),目标内容)])这里有个容易忽略的点定位元素不是一次性的事页面动态刷新后之前拿到的元素引用会失效。所以写长脚本时不要养成“拿到元素就到处复用”的习惯必要的时候重新查一遍。3.2 等待策略别再用sleep硬扛新手最爱写time.sleep(3)我当年也这么干过。问题是网络一慢3秒不够网络快的时候3秒又白白浪费时间。而且这种固定等待根本解决不了元素延迟渲染的问题只会让脚本变得又慢又脆。真正靠谱的是显式等待。Selenium里有个WebDriverWait配合expected_conditions可以等到某个条件成立再继续。这个机制不管页面加载快慢都能自适应。我常用的等待条件有element_to_be_clickable等待元素可点击适合按钮。visibility_of_element_located等待元素可见适合动态加载的内容。presence_of_element_located等待元素出现在DOM中适合判断元素是否已经生成。staleness_of等待某个元素从DOM中消失常用来判断页面是否刷新完成。代码大概长这样from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By wait WebDriverWait(driver, 10) button wait.until(EC.element_to_be_clickable((By.ID, submit-btn))) button.click()这里(By.ID, submit-btn)是一个元组注意别漏括号。有个隐藏好处显式等待的报错信息会告诉你超时等待的是哪个条件排查问题比time.sleep过后直接NoSuchElementException清晰得多。不要迷信一种等待策略老项目里经常是隐式等待和显式等待混用的但要清楚它们的机制避免出现等待时间叠加的问题。3.3 表单、提交、拖拽与截图操作定位到元素之后真正模拟用户操作也有不少坑。输入框用send_keys()这个都知道。但有几类操作值得单独记一下下拉框尤其是原生select标签可以用Select类处理。新版前端框架里很多下拉框是自定义组件实际上是一堆div那用Select就没用得先点击展开再点击选项列表里的某个元素。判断方法很简单看页面源码里有没有select标签。拖拽用ActionChains。比如列表排序、地图标记、滑块交互等操作可以通过click_and_hold()、move_by_offset()、release()这些方法组合实现。注意拖拽之前元素必须已经进入可视区域否则坐标不对很容易拖到别的地方。文件上传是另一个经典坑。如果页面里的input标签是typefile那直接用send_keys(本地文件路径)就能搞定不需要真的去操作系统弹窗。但如果页面自己封装了上传组件点击后引入系统文件选择器Selenium就控制不了了这个时候常见做法是绕过前端校验直接把文件路径塞给隐藏的input元素或者借助第三方工具。截图操作我也用得很多。driver.save_screenshot(screen.png)只能截当前窗口想要整页截图很多浏览器驱动已经支持了但不同浏览器表现不一。我一般更倾向于自己控制滚动、分段截图再拼起来这样能保证关键区域不遗漏。3.4 网页左右滑动从横向滚动条到元素可见热搜里“selenium 网页左右滑动”和“selenium 左右滚动可见”在测试场景里特别常见。多数人的第一反应是滑动垂直滚动条实际上横向滚动同样是个高频需求。典型场景包括宽表数据表格、轮播图、横向布局的图表区域、类似股票K线的横向时间轴。Selenium里没有专门的“向右滑动”方法得通过JavaScript或者键盘事件来实现。几种常用手段滚动整个窗口driver.execute_script(window.scrollTo(document.body.scrollWidth, 0);)滚动某个容器先定位到那个容器再设置scrollLeft。例如table driver.find_element(By.CSS_SELECTOR, .data-table-wrapper) driver.execute_script(arguments[0].scrollLeft 800;, table)让某个元素横向进入可视区域driver.execute_script(arguments[0].scrollIntoView({inline: center});, element)键盘左右箭头如果元素是焦点型容器也可以用element.send_keys(Keys.RIGHT)来触发横向滚动。很多朋友说“横向滚动不见效”绝大多数原因是容器选择错了。页面上可能外层有窗口滚动条内层有div滚动条你得先看清楚真正能滚动的容器是哪一个。开发工具里用Elements面板找到有overflow-x: auto或overflow-x: scroll样式的节点那个才是真正需要控制的容器。判断元素是否真正可见除了element.is_displayed()之外还要考虑它在滚动容器的可视范围内这通常要结合坐标来计算或者用scrollIntoView强行把它捞出来。左右滑动还牵涉到懒加载。横向长图、展示型列表很多时候首屏只渲染一部分滚动之后才加载更多。这就是为什么滑动之后要立刻配合显式等待等目标元素出现再继续下一步操作。如果你发现滑动后元素还是找不到多半是内容还没加载完硬等几秒没有逻辑可循不如用WebDriverWait盯着页面变化。4. Python Selenium当自动化测试遇到反爬虫4.1 反爬到底在检测什么“Python selenium反爬虫”这个话题是测试岗位面试里经常被问到的。要弄清楚怎么应对先得知道对方在检测什么。我拆过一些常见的检测逻辑大致分这么几类请求特征User-Agent、Accept-Language、Accept-Encoding是否像真实浏览器。JavaScript环境特征浏览器驱动会注入一些自动化标记比如navigator.webdriver的值在自动化环境里通常是true。浏览器指纹Canvas指纹、WebGL参数、字体列表、插件列表这些略微有差异就可能被标记。行为特征访问速度、鼠标轨迹、点击频率、页面停留时间短时间密集操作很容易暴露。CDP特征通过Chrome DevTools Protocol连接时某些调用痕迹可以被检测到。我这里说“检测”不是说所有自动访问都违法而是很多网站为了防刷会做风控。作为测试人员我们经常需要模拟真实用户访问自己的系统或者验证第三方页面是否有反爬机制掌握这些检测点是有实际用处的。但必须要强调这些方法只用于你有权测试的目标不要拿去绕别人的登录授权更不要用来爬隐私数据。4.2 降低自动化特征代码层能做什么如果你只是在内部测试系统上跑脚本但系统恰好加载了一套线上的风控SDK那就要适当降低自动化特征否则连登录都会被拦。最常见的三个操作第一修改User-Agent。真实浏览器的UA和默认Selenium的UA有明显区别可以先从请求头开始options webdriver.ChromeOptions() options.add_argument(--user-agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ...)第二去掉自动化控制标记。Chrome浏览器启动时如果带--enable-automation开关会有明显特征。可以用排除开关的方式处理options.add_experimental_option(excludeSwitches, [enable-automation]) options.add_experimental_option(useAutomationExtension, False) options.add_argument(--disable-blink-featuresAutomationControlled)第三在页面加载前覆盖navigator.webdriver属性。Selenium 4里可以用CDP注入脚本driver webdriver.Chrome(serviceservice, optionsoptions) driver.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, { get: () undefined }); })这个脚本会在每次页面加载新文档之前执行所以它比页面里的检测代码更早生效这是我测试下来比较有效的一招。但要注意CDP是Chrome系浏览器特有的能力换成Firefox就用不了。4.3 行为层面的模拟别把自己当成永动机光是特征屏蔽还不够很多风控看的是行为。如果脚本每一秒执行一次点击、每次点击间隔完全一致、页面停留时间都是精确的2.5秒那就算webdriver属性被覆盖了也很容易被行为序列分析出来。我的做法是引入随机化。不是伪随机糊弄人而是让操作间隔更像真人。比如登录之后先滚两下页面再挪动鼠标再点击每一步之间加一个随机延迟。Python里可以这样import random import time def human_delay(): time.sleep(random.uniform(0.5, 1.5))注意随机延迟不是万能的只是避免固定节奏。更关键的是要把操作顺序做得像人类先看页面再滚动再点击目标按钮而不是一上来就直奔按钮。这些细节在内部测试时看不出来但在风控严格的页面上差别很大。4.4 合规边界技术能力要用在正道上说到反爬必须把边界讲清楚。我见过有些人学了几个技巧就跑去爬别人的订单数据、用户信息最后惹上法律风险完全没有必要。自动化技术的正确用法是对自己负责的系统做压力测试对公开页面做有限的信息采集对测试环境做完整的流程模拟。在动手前要看清楚目标网站的Robots协议和服务条款必要时先取得授权。这一点不只是法律问题也是职业素养问题。面试的时候面试官也喜欢问“你怎么看待爬虫和反爬”。我的回答角度一直是我会从测试、风控、数据采集三个维度去拆解但核心前提是合规。这个前提想不清楚技术越好越危险。5. Selenium VBAExcel老用户也能玩转网页自动化5.1 为什么要在VBA里用Selenium很多公司内部办公系统还是老旧网页业务人员每天要手动把网页上的数据复制到Excel里或者把Excel里的内容填到网页表单里。纯VBA用InternetExplorer对象操作浏览器老式网站还能应付但遇到现代网页就经常失败。这时候“selenium vba”就成了个实用的关键词——VBA里调用Selenium就能复用Chrome等现代浏览器来跑自动化。SeleniumBasic是一个把Selenium封装成COM组件的库安装之后VBA里可以像操作普通对象一样控制浏览器。典型的代码长这样Dim driver As New Selenium.ChromeDriver driver.Get https://example.com driver.FindElementById(username).SendKeys testuser driver.FindElementById(login-btn).Click driver.Quit当然具体API要根据SeleniumBasic的版本来调整。早期版本对Chrome支持不稳定后来新增了ChromeDriver支持后才好用起来。如果有条件更推荐的方式是把复杂的网页操作逻辑用Python写好VBA只负责调用Python脚本并等待返回值。这样既保有VBA在Excel里的灵活性又不用在COM组件和JavaScript之间来回折腾。5.2 典型办公场景Excel和网页之间的数据搬运我做过的实际案例是财务同事每天要从内部系统导出一张对账单但系统不支持直接导出Excel只能页面展示。之前他们的方案是复制粘贴一天两小时。后来我用SeleniumBasic写了一个VBA宏自动打开网页、跳转到指定页面、提取表格数据、粘贴到Sheet里。运行一次只要一分钟一周能帮同事省出半天的重复劳动。关键步骤也很朴素先记录网页URL和登录方式再定位表格区域把innerText读出来拆分到单元格。需要注意网页表格经常有合并单元格和分页逻辑写起来比较繁琐一定要先理清结构再动手。5.3 VBA方案的三条经验确认Office是32位还是64位。SeleniumBasic的COM注册表项和位宽有关装完第一次运行报“找不到组件”的情况十有八九是位宽不匹配。建议把浏览器驱动文件放到固定目录并在VBA里用绝对路径引用。办公室电脑环境各异依赖全局路径太容易翻车。网页一改版VBA脚本大概率要跟着改。所以我建议在代码里把关键选择器统一放在模块顶部的常量区改起来一目了然。职场里很多不需要专门自动化测试师的场景VBA方案反而是同事们最欢迎的因为它不依赖额外环境打开Excel就能用。6. 常见问题与排查技巧实录6.1 高频报错一份速查表写Selenium脚本这几年我把遇到最多的几类报错整理成了一张表也分享给团队里的新人报错类型常见原因处理思路NoSuchElementException元素没加载出来或选择器写错先手动打开页面确认元素是否存在再改用显式等待TimeoutException等待条件一直不满足检查条件类型是否符合预期查看页面是否有弹窗遮挡ElementClickInterceptedException按钮被其他元素遮挡先scrollIntoView或者关闭弹窗/悬浮层再点击StaleElementReferenceException页面刷新后旧引用失效不要复用旧元素引用重新定位SessionNotCreatedException驱动版本和浏览器版本不匹配下载匹配版本的驱动最好固定浏览器版本InvalidArgumentException传入的参数格式不对检查命令参数比如路径必须是绝对路径WebDriverException浏览器进程异常退出检查是否有残留Chrome进程清理后重试这些报错信息不是看一遍就能记住的最好的习惯是每次遇到就记录到自己的笔记里尤其是当时页面状态和报错堆栈。时间长了你会形成直觉看到哪种报错大概知道是哪一类问题。6.2 调试自动化脚本的三个动作第一把无头模式关掉开着浏览器窗口跑。很多问题在无头模式下表现得很诡异比如元素明明存在但点击无效开着浏览器能看到真实的交互过程问题一下子暴露出来。第二放慢速度。在关键步骤前加一个time.sleep(0.5)或者用调试模式逐行跑。自动化脚本调的不是功能逻辑而是操作时序慢下来才能看清每一步发生了什么。第三用截图和页面源码定位。报错的瞬间先driver.save_screenshot()存张图再把driver.page_source写成html文件。很多时候只看报错信息想破头一打开页面快照就能发现问题比如元素被弹窗挡住了或者页面还在加载中。6.3 工作里特别值得坚持的三个小技巧第一个技巧把选择器集中管理。不要在每个函数里直接写一长串XPath最好定义一个类把每个页面元素的选择器、预期等待条件都收拢到一起。这就是大家常说的Page Object模式。一开始写感觉费时间等脚本规模大了改一个前端字段名只需要改一个地方那种幸福感是实实在在的。第二个技巧始终保证driver会被关闭。脚本出错不可怕可怕的是出错后浏览器进程还挂在服务器上吃内存。我一般用try/finally结构或者with上下文管理器保证driver.quit()一定执行。写长任务脚本时还要定期加个长度检查做看门狗防止浏览器假死拖垮任务。第三个技巧多花十分钟手动走一遍页面再写代码。很多人一上来就写自动化结果连按钮是点击后弹窗还是跳转新页面都没搞明白脚本怎么调都不对。先手动操作目标页面把每一步涉及的元素、跳转、加载等待都记录下来等于先有了一张流程图后面写代码只是把这套动作翻译成Selenium API。这个习惯能大幅减少反复调试的时间。最后说一句我个人的体会Selenium这门手艺平时看不出来多值钱但真到排查一个诡异报错或者帮同事省掉半天重复劳动的时候你会庆幸自己当时没偷懒把底层细节搞明白。希望这篇指南能让你在自动化测试这条路上少踩几个坑。