资讯动态

Selenium 网页自动化实战:核心原理、稳定定位与真实应用场景全解

发布时间:2026/10/21 7:52:15 来源:尧图企业网站定制
Selenium 这名字乍一听很多人觉得是“测试专用”但说它能做任何你想做的事情真不是标题党。我最近一年用 Selenium 做了不少奇奇怪怪的事每天固定时间去后台批量处理审批、定时抓取公开页面做汇总、监控某个页面数据变化、甚至给自己的小项目做自动冒烟检查——全是浏览器里那些“人能干但不想干”的活。它本质上就是一个能替你控制浏览器的工具你手动能完成的操作它基本都能自动跑。这篇文章我不讲套话只讲我实际用下来的场景拆解、核心原理、能直接抄的代码和踩过的坑。1. Selenium 到底能干什么四个最先落地的方向1.1 摆脱重复的人工操作批量填报与巡检最常见的落地场景就是“每天都要做一遍”的机械操作。比如某公司的后台需要逐个点开待审批订单确认信息后点通过或驳回再比如每天要登录系统把某张报表导出再填到另一个网页表单里。我做的一个真实案例是这样的每天早上定时打开内部审批后台把昨天积压的待办按预设规则自动处理掉处理完把结果汇总成 Excel 发到工作群。整个流程跑下来不到五分钟而以前人工做需要将近一个半小时。这类场景的特点是流程固定、判断规则简单、出错后果可控。它是 Selenium 自动化收益最高、风险最低的方向非常适合作为第一个练手项目。你不需要懂多深的编程只要会基础的 Python能把定位、点击、输入这几个动作串起来就已经能解决 80% 的“重复填表”类工作。我建议新手第一步就找身边一个最烦的重复操作去自动化不要一上来就想着做全网最复杂的爬虫系统。1.2 数据采集与网页信息汇总很多人一想到网页数据采集就觉得必须用专门框架但 Selenium 在这种场景下也有独特优势它能直接处理需要登录、需要点击翻页、需要动态加载的页面。尤其是那些数据在点击之后才渲染出来的网站用简单请求很难拿到完整内容用 Selenium 等于用真实浏览器访问所见即所得。我举一个实际操作过的例子某询价平台上有一个列表页只显示 20 条数据翻页按钮是动态渲染的用普通 HTTP 请求抓到的 HTML 里根本没有下一页按钮。用 Selenium 就很简单定位下一页按钮循环点击每次点击后等待列表刷新把当页内容解析出来存到本地。整个过程逻辑简单代码量不大还能顺便模拟人工浏览的节奏避免给目标站点造成压力。需要提醒的是做数据采集要遵守目标网站的访问规则严格控制频率只抓公开合法信息这是底线。1.3 真实浏览器环境下的自动化回归检查如果你维护过任何 Web 项目应该经历过这种痛苦改了这块功能结果那块莫名其妙挂了。Selenium 可以帮你把核心操作路径写成自动化脚本每次发布前跑一遍相当于用程序代替人做“冒烟测试”。这个场景中最有效的做法是只覆盖主流程不追求把所有按钮都测到。我实际维护过的一个后台系统回归脚本只需要做三件事登录、新建一个单据、把单据审批到完结。整套脚本跑完不到两分钟但每次升级后都能第一时间发现“登录按钮失效”“表单提交没反应”这类致命问题。比让测试同学手工点半小时高效得多。你不需要把它弄得多复杂不需要 Jenkins、不需要自动化测试报告平台哪怕是本地双击一下脚本然后看输出日志里有没有报错就已经比裸奔上线强太多了。这也是 Selenium 被低估的一个使用方向。1.4 无人值守的定时任务与页面状态监控这个场景非常冷门但我个人觉得特别实用。Selenium 本质上能完整模拟你打开电脑、打开浏览器、做一系列操作的全过程所以它可以用来做“页面状态监控”。比如某个订单管理页面如果出现异常会弹一个红色提示框某个数据大屏如果某块指标超过阈值图表区域背景会变色。这些都是可以通过 Selenium 定时截图、定时读取页面元素来判断的。我做过一个最简单的版本每半小时打开一次某数据面板用截图保存页面状态然后尝试定位“异常”字样只要发现就推送告警消息。和专业的监控系统相比Selenium 显得很笨重但它的优势是“不挑系统”——只要是浏览器能打开的页面它都能监控不需要目标系统开放任何接口。对内部系统做这种轻量巡检性价比真的很高。2. 动手之前先搞懂绕不开的三个核心概念2.1 WebDriver 不是“驱动”而是遥控器网上很多教程一上来就让你“下载 WebDriver”搞得好像它是一个硬件驱动。实际上它更准确的比喻是“遥控器”你的 Python 脚本通过 Selenium 库发指令给 WebDriverWebDriver 再把这些指令翻译成浏览器底层能执行的原子操作比如“打开标签页”“点击坐标”“输入文字”。这个设计让 Selenium 能控制不同浏览器因为每个浏览器厂商都有自己的 WebDriver 实现。明白了这个关系你才能应对最常见的翻车现场浏览器自动升级后脚本突然报session not created或者cannot find Chrome binary。原因通常是 WebDriver 版本和浏览器版本不匹配。Selenium 4.6 之后自带 Selenium Manager会自动尝试下载匹配的 driver省了很多事但如果你的环境比较特殊还是建议手动固定浏览器版本和 driver 版本避免意外升级导致脚本全线崩溃。在代码里初始化浏览器的写法很简单from selenium import webdriver driver webdriver.Chrome() driver.get(https://example.com)就这一句你已经打开了真实浏览器。很多自动化小白到这一步会很兴奋但我劝你冷静一下后面还有两个概念更重要。2.2 元素定位自动化能不能写下去的分水岭Selenium 所有操作的本质是找到页面上的某个东西然后对它做点什么。所以“怎么找到”决定了脚本的稳定性。Selenium 提供八种定位方式我实际使用下来分布大概是这样的定位方式实用程度我的真实评价ID最高页面里唯一且稳定能用就优先用CSS 选择器高类名、属性组合定位简洁高效XPath高最灵活但写不好会非常脆弱Class Name中多元素共用的类名极容易定位到多个Link Text / Partial Link Text中只适合链接元素适合“点击登录”这种Name低现在很多框架不输出 name 属性Tag Name低页面里同名标签太多基本要配合其他条件很多人一上来就抄一串很长的 XPath形如/html/body/div[3]/div[2]/div[1]/form/div[2]/input。这种绝对路径我极度不推荐因为只要页面结构加一层 div脚本就挂了。我更推荐用相对 XPath根据元素附近的稳定特征来定位。比如一个登录按钮HTML 结构是div classlogin-box input idusername / input idpassword / button typesubmit登 录/button /div定位时可以这样写username_input driver.find_element(By.ID, username) password_input driver.find_element(By.ID, password) login_btn driver.find_element(By.XPATH, //div[contains(class, login-box)]//button)思路就是先找一个稳定的父级容器比如登录框再从它下面找目标按钮这样就算页面上还有其他按钮也不会定位错。这个“先从稳定容器着手再向下查找”的思路能帮你规避一多半的定位问题。2.3 等待策略为什么脚本三天两头“偶发失败”新手最容易犯的错是打开页面后立刻去找元素结果报NoSuchElementException然后怀疑定位写错了。实际上大部分情况是元素还没渲染出来。要解决这个问题有三种等待方式但效果天差地别等待方式写法优点缺点强制等待time.sleep(3)简单直观时间写短了不够写长了浪费时间网络波动时极其不稳定隐式等待driver.implicitly_wait(10)全局生效定位不到就先等一会不管元素是否出现都会浪费固定查询时间只对 find 有效显式等待WebDriverWait 条件精准等到满足条件立即继续需要多写几行代码我个人的准则是能用显式等待就不用强制等待尽可能别依赖隐式等待。显式等待的典型写法是from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By login_btn WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.XPATH, //button[contains(text(), 登 录)])) ) login_btn.click()这段代码的意思很直接最多等 10 秒只要按钮变成可点击状态就立刻操作。页面加载快的时候几乎是秒过加载慢的时候也不报错这是让自动化脚本从“偶发失败”走向“稳定运行”最关键的一步。3. 一个能直接抄的完整案例每天定时处理后台待办审批3.1 场景设计与实现思路我用一个真实做过的简化版例子来展示完整链路。假设场景是某内部订单审核系统每天有几十条待审批订单每条的规则是金额小于 5000 的直接通过金额在 5000 到 10000 之间的需要进一步核对客户等级等级为 A 则通过否则驳回金额大于 10000 的一律转人工。每天 08:30 自动执行处理完后输出一份 Excel 汇总并推送一条结果消息。这个场景巧妙在既有简单的页面自动化登录、遍历、点击又有简单的业务判断逻辑金额分级、条件处理还有结果落盘写入 Excel非常适合作为学习样板。整体流程如下打开系统登录页填入账号密码登录。进入“待审批订单”列表。循环遍历每一行读取金额、客户等级。按规则点“通过”“驳回”或“转人工”。把每笔订单的处理结果记录成结构化数据。全部处理完生成 Excel 汇总表。3.2 环境准备安装和第一版脚本环境上需要准备的东西只有三样Python、Selenium 库、浏览器和对应 WebDriver。安装命令一行pip install selenium浏览器我用 Chrome在 Selenium 4.6 以上的版本里只要 Chrome 是本机装的绝大多数时候直接初始化就行driver 会自动处理。如果你遇到报错请去检查浏览器版本和 driver 版本是否一致。启动浏览器以后有几行“配置项”建议固定写在初始化部分会让你后续调试省力很多from selenium import webdriver from selenium.webdriver.chrome.options import Options options Options() options.add_argument(--start-maximized) # 最大化窗口减少响应式布局带来的定位差异 options.add_argument(--window-size1920,1080) # 固定窗口尺寸保持页面布局稳定 options.add_experimental_option(detach, True) # 脚本跑完不自动关浏览器方便观察现场 driver webdriver.Chrome(optionsoptions) driver.get(https://your-internal-system.example/login)这个detach选项是调试期的神器。默认情况下脚本结束浏览器就关了页面长什么样、按钮在哪你根本没有机会看开了 detach 之后浏览器就留在桌面上你能直观看到脚本刚才对页面做了什么。3.3 核心代码拆解登录、遍历、判断、汇总登录部分没什么神秘就是定位用户名框、密码框、登录按钮填入数据后点击。这里我强烈建议用显式等待因为登录页面经常有跳转和按钮状态变化from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait WebDriverWait(driver, 10) driver.find_element(By.ID, username).send_keys(admin) driver.find_element(By.ID, password).send_keys(your_password) wait.until(EC.element_to_be_clickable((By.ID, loginBtn))).click() # 等待登录跳转后某个可见元素出现确认登录成功 wait.until(EC.visibility_of_element_located((By.CLASS_NAME, order-list)))真正核心的是遍历列表。假设每一行订单都长这样tr classorder-row>import csv from selenium.common.exceptions import NoSuchElementException results [] rows driver.find_elements(By.CLASS_NAME, order-row) for row in rows: order_id row.get_attribute(data-id) amount_text row.find_element(By.CLASS_NAME, order-amount).text level_text row.find_element(By.CLASS_NAME, customer-level).text amount float(amount_text) if amount 5000: row.find_element(By.CLASS_NAME, btn-pass).click() decision 通过 elif amount 10000 and level_text A: row.find_element(By.CLASS_NAME, btn-pass).click() decision 通过 elif amount 10000: row.find_element(By.CLASS_NAME, btn-reject).click() decision 转人工 else: row.find_element(By.CLASS_NAME, btn-reject).click() decision 驳回 results.append((order_id, amount_text, level_text, decision))这里有个极其重要的细节每次点击之后页面 DOM 可能会刷新之前拿到的row元素引用会失效。如果你发现第一次循环正常第二次开始报StaleElementReferenceException就是这个问题。解决办法是在每次循环里重新获取当前行的最新引用或者把“找行”这一步放在点击之前完成点击后立刻跳出重新等待列表刷新。实际做工单详情页面时我常常采用“只点击一个然后重新加载列表再定位下一个”的模式虽然慢一点但稳定性大幅提升。最后把结果写进 CSVwith open(approval_result.csv, w, newline, encodingutf-8-sig) as f: writer csv.writer(f) writer.writerow([订单ID, 金额, 客户等级, 处理结果]) writer.writerows(results)为什么用 CSV 而不用 Excel因为 CSV 是纯文本格式Python 标准库直接支持不需要额外装操作 Excel 的依赖。如果你的场景确实要生成带格式的 xlsx可以再引入专门的处理库但很多内部系统对接时CSV 已经够用且通用性更好。3.4 让它每天自己跑定时任务与无人值守脚本写完只是第一步真正让“自动化”产生价值的是让它无人值守地跑起来。我推荐两种方式看你的运行环境如果你在 Windows 服务器上跑直接用任务计划程序把脚本保存成run_approval.py。写一个run.bat内容只有一行python run_approval.py。在任务计划程序里新建基本任务触发器设为每天 08:30操作选“启动程序”指向run.bat。如果你在 Linux 服务器上跑用 crontab30 8 * * * cd /path/to/project /usr/bin/python3 run_approval.py run.log 21这里最容易被忽略的是日志。无人值守脚本最怕的就是“今天没跑但你没发现”。我强烈建议在脚本最外层套一个日志机制至少把所有关键步骤和异常都写到一个日志文件里import logging logging.basicConfig( filenameauto_approval.log, levellogging.INFO, format%(asctime)s [%(levelname)s] %(message)s ) logging.info(审批自动化任务启动)日志比任何花哨的监控都实在。你可以每天上班第一眼先看日志最后几行只要看到“任务完成”就放心了看到异常堆栈也知道从哪查起。后面我会专门讲日志如何帮你定位问题。4. 我踩过的坑常见问题与排查技巧实录4.1 死活定位不到元素从这四步开始排查这是最多人提问的问题我自己的排查顺序固定是第一步看等待够不够。页面是 Ajax 动态加载还是 iframe 嵌套还是按钮在滚动下方先加一个显式等待试试看。第二步看元素是不是在 iframe 里。很多系统嵌入了第三方页面或富文本编辑器元素在 iframe 里时直接find_element是永远找不到的。需要先切换进去driver.switch_to.frame(driver.find_element(By.TAG_NAME, iframe)) # 操作完再切回来 driver.switch_to.default_content()第三步看元素是否在新打开的标签页窗口里。点击某个按钮打开新页面时Selenium 默认还停留在旧页面你需要切换窗口句柄handles driver.window_handles driver.switch_to.window(handles[-1])第四步看元素是不是被隐藏或遮住了。有些按钮在屏幕外、折叠区域、弹层内部此时元素存在但不可见。可以用滚动element driver.find_element(By.ID, hidden-btn) driver.execute_script(arguments[0].scrollIntoView();, element)这四步能解决九成“找不到元素”的问题。如果四步都试过还不行右键检查那个元素确认你定位用的选择器在真实页面里没有拼错有时候类名里有空格或者动态变化的数字用contains会更稳妥。4.2 元素明明存在却报“点击无效”或被拦截比“找不到元素”更气人的是“找得到但点不动”。典型的报错是ElementClickInterceptedException说明元素被其他东西遮住了比如弹窗遮罩层、固定导航栏、Cookie 同意按钮。我处理这种问题的通用套路是from selenium.webdriver.common.action_chains import ActionChains # 方案一用 JavaScript 直接执行点击绕过遮罩 driver.execute_script(arguments[0].click();, element) # 方案二用 ActionChains 模拟鼠标移动过去再点击 ActionChains(driver).move_to_element(element).click().perform()优先用方案二因为它更像真实用户操作方案一虽然能成功但有时候会绕过前端的事件校验触发一些奇怪的状态。另外还有一种情况是按钮处于disabled状态此时任何点击方式都没用你要检查前端逻辑是不是某个前置条件没满足比如没勾选某个复选项、没填写必填项。脚本报错不是终点你得学会看前端控制台的错误提示。4.3 脚本跑着跑着就崩了从“脆”到“稳”的改造初版脚本往往能跑通一次但第二次、第三次就跑崩原因是缺少兜底。我做稳定性改造时主要做了三件事第一关键步骤全部用显式等待替代sleep前面已经说过不重复。第二在经常会变化的元素上用更宽松的 XPath 策略比如用contains(class, btn)而不是精确等于btn-primary。第三整个主流程包上try/except失败时把当前页面截图保存下来这样早上到公司能看到“当时页面长什么样”而不是只有一堆堆栈。这个截图函数很有用import time def screenshot_on_error(driver, tag): ts time.strftime(%Y%m%d_%H%M%S) driver.save_screenshot(ferror_{tag}_{ts}.png)别小看这张截图大多数元素定位问题的真相一秒钟就能看出来原来是弹窗没关、原来是页面白屏、原来是某个字段填错导致红色校验提示挡住了按钮。文字日志说一百遍不如一张现场截图。4.4 浏览器版本一升级脚本就“全面瘫痪”这是所有 Selenium 用户都会遇到的周期性头疼。解决方案无非几种一锁版本。固定浏览器版本关闭浏览器的自动更新让 driver 和浏览器一直匹配。适合内部系统场景。二用 Selenium Manager。Selenium 4.6 以上会自动匹配新版 driver大多数情况下解决了这个痛点。三用容器化方案。如果你既有 Docker 的环境可以把浏览器、driver、脚本都打进镜像和宿主机版本完全隔离这是最干净的方案。我个人比较推荐容器化但它的学习成本略高。对新手来说先用 Selenium Manager 解决 80% 的问题剩下的 20% 用锁版本来兜底。4.5 页面加载时快时慢怎么保证脚本稳定这个问题在真实环境里非常普遍。同一个页面早上快、下午慢内网快、外网慢。应对思路是不要给整个页面固定一个超时时间而是给每个关键操作单独设定合理的等待条件。我的做法是给每个核心交互步骤都写独立的等待逻辑# 例等待表单可编辑 WebDriverWait(driver, 15).until(EC.visibility_of_element_located((By.ID, form-area))) # 例等待列表加载完成某个动态文本出现 WebDriverWait(driver, 20).until( EC.text_to_be_present_in_element((By.ID, page-status), 共 42 条) )这样页面再慢脚本也只会在真正卡住的地方等待而不是无脑从头到尾全等。注意一点显式等待默认每 500 毫秒检查一次条件你可以通过设置poll_frequency调成 0.2 秒让脚本反应更快不过我实战下来默认值已经够用。5. 让自动化长期稳定运行的五条铁律第一定位选择器集中管理宁可写配置文件不要埋在代码各处。我现在会把所有页面元素的定位表达式放在项目里一个单独的位置集中维护。页面结构变了只改一处而不是翻遍整个代码去替换。第二消灭强制等待让脚本自己判断“等到什么时候”。你自己想一想sleep 3 秒网络好的时候浪费 2 秒网络差的时候少睡 1 秒就挂了。显式等待是唯一推荐方案。第三任何自动化脚本必须有日志。没有日志的无人值守脚本等于裸奔。你不需要搞复杂框架只要保证每个关键操作都有输出、每个异常都记录堆栈、每次失败都留现场截图就够了。第四定时任务一定要加结果反馈。最轻量的方式是日志更稳妥的是异常时发一封通知、一条消息再进一步是把执行结果写入一个状态表用监控面板盯一眼。反馈环节不能省否则自动化的价值会打折扣。第五别一上来就想做“万能浏览器机器人”。先定一个小目标把某一个重复操作做到能稳定跑 7 天不失败。做到了再扩展到下一个场景。我见过很多人一开始雄心勃勃想做全自动办公结果折在第一步登录页面的验证码上。与其被挫败感劝退不如从最简单、最重复、最稳定的流程开始一次只解决一个事。我在实际使用中的体会是Selenium 的学习曲线其实一点都不陡真正的门槛在别处——你愿不愿意把一次性的重复劳动花时间变成一次性的自动化脚本你能不能接受前期调试的不确定性去换取后面长期的省力。如果你愿意它确实可以做任何你想做的事情。最后再分享一个小技巧当你写完一个自动化脚本先连续手动触发三到五次看看会不会偶发失败。如果三到五次都能稳定通过基本可以放心交给定时任务如果中间失败了一次千万不要说“运气不好”——那就是一个还没被解决的隐患趁早去查日志和截图别等到凌晨三点它悄悄崩了才后悔。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑