Selenium鼠标键盘操作全解析:从事件原理到实战应用

📅 发布时间:2026/8/6 8:12:52
Selenium鼠标键盘操作全解析:从事件原理到实战应用
1. 项目概述从“点”到“面”的UI自动化进阶刚入行做UI自动化测试那会儿我总觉得只要能把元素定位到然后调用一个click()或者send_keys()方法任务就算完成了。直到在一个复杂的后台管理系统项目里栽了跟头一个需要鼠标悬停才能显示的下拉菜单一个需要按住Ctrl键多选的文件列表还有一个必须通过拖拽来调整顺序的看板。这些场景让我意识到只会基础的点击和输入在真实的Web应用面前是远远不够的。真正的UI自动化不仅要能“看见”元素更要能“模拟”用户的手去完成所有精细的鼠标移动、键盘组合操作。这就是我们今天要深入探讨的“Web端鼠标与键盘操作”的核心价值——它让你的自动化脚本从只能执行简单命令的“机器人”升级为能模拟真人复杂交互的“智能体”。对于测试工程师、RPA机器人流程自动化开发者甚至是任何需要通过程序与Web页面进行复杂交互的同学来说掌握鼠标和键盘的高级操作是提升自动化脚本健壮性、覆盖率和拟真度的关键一步。这不仅仅是调用几个API那么简单背后涉及到对浏览器事件机制的理解、对操作时序的精确控制以及如何优雅地处理各种异常场景。接下来我会结合近十年的踩坑经验带你从原理到实战彻底搞懂如何在Selenium等主流框架下玩转鼠标和键盘。2. 核心原理浏览器事件与动作链Action Chains在开始写代码之前我们必须先搞清楚一件事当我们在页面上移动鼠标、点击或按下键盘时浏览器里到底发生了什么理解这个才能明白我们写的自动化指令是如何“欺骗”浏览器让它以为是一个真实用户在操作。2.1 浏览器事件流从物理动作到页面响应一个简单的鼠标点击在浏览器内部会触发一系列精密的事件。以点击一个按钮为例鼠标按下mousedown物理按键被按下事件触发。鼠标抬起mouseup物理按键被释放事件触发。点击click在同一个元素上相继触发了mousedown和mouseup后浏览器会合成一个click事件。如果元素是可聚焦的如输入框、按钮可能还会伴随focus获得焦点事件。如果是表单提交按钮可能最终会触发submit事件。键盘输入也是如此keydown-keypress-keyup然后输入框的value改变并触发input或change事件。注意很多新手写的脚本不稳定就是因为只模拟了最终的click事件而页面上的某些JavaScript监听的是mousedown或mouseup事件。如果你的点击“失灵”了检查一下事件监听器是第一步。2.2 Selenium的“动作链”ActionChains设计哲学Selenium 没有采用“一键触发”的简单方式而是引入了ActionChains动作链的概念。这非常符合真实用户的操作逻辑一个复杂操作是由一系列基本动作按顺序组成的。动作链的核心思想是“排队”与“执行”定义动作你将一系列动作如移动鼠标到某元素、按下鼠标左键、移动鼠标、松开左键按顺序添加到一条“链”中。缓存动作这些动作不会立即执行而是被缓存在一个队列里。执行动作当你调用perform()方法时Selenium 会按照队列顺序精确地、连续地执行所有动作并确保每个动作都触发了正确的底层浏览器事件。这种设计的好处是原子性可以构建非常复杂的复合操作如拖拽、右键菜单、画图。可读性代码清晰表达了操作的完整流程。可控性可以在动作之间插入等待pause以应对动画或加载。与低级模拟工具如PyUserInput的区别 你可能在网上看到过像PyUserInput这样的库它直接模拟系统级的鼠标键盘事件。这与Selenium的ActionChains有本质区别ActionChains在浏览器环境内通过WebDriver协议驱动浏览器触发标准的Web事件。它依赖于浏览器和页面DOM更安全、更稳定是Web自动化的首选。PyUserInput在操作系统层面模拟输入不关心浏览器窗口在哪。它可能被安全软件拦截且无法与页面元素状态绑定容易失控。通常只在无法通过WebDriver实现的操作如操作浏览器之外的桌面弹窗时才考虑但这不是Web自动化的主流做法且维护成本高。我们的实战将完全基于Selenium的ActionChains这是最专业、最可靠的路径。3. 环境准备与基础操作工欲善其事必先利其器。我们先搭建一个可靠的练习环境。3.1 环境搭建Python Selenium WebDriver我强烈建议使用Python因为其生态丰富Selenium支持成熟。以下是快速搭建步骤安装Python从官网下载并安装Python 3.7版本安装时务必勾选“Add Python to PATH”。安装Selenium库打开命令行CMD或Terminal执行以下命令。使用清华镜像源可以加速。pip install selenium -i https://pypi.tuna.tsinghua.edu.cn/simple下载浏览器驱动这是Selenium控制浏览器的桥梁。驱动版本必须与你的浏览器版本匹配。Chrome驱动ChromeDriver去 Chrome for Testing availability dashboard 或国内镜像站下载对应版本。Edge驱动Microsoft Edge WebDriver通常随Edge浏览器安装也可从 微软官网 下载。Firefox驱动geckodriver从 GitHub Releases 下载。下载后将驱动文件如chromedriver.exe放在一个固定目录如C:\WebDriver并将该目录添加到系统的PATH环境变量中。这是最一劳永逸的方法避免每次都要指定路径。3.2 第一个脚本验证环境与基础点击创建一个名为basic_operation.py的文件写入以下代码。我们用一个简单的百度搜索来验证环境。from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys import time # 1. 启动浏览器这里以Chrome为例 driver webdriver.Chrome() # 如果驱动已在PATH无需指定路径 # 如果驱动不在PATH需要指定webdriver.Chrome(executable_pathr‘你的驱动路径‘) # 2. 打开网页 driver.get(https://www.baidu.com) driver.maximize_window() # 最大化窗口避免元素被遮挡 time.sleep(2) # 等待页面加载实际项目中应用更智能的等待后面会讲 # 3. 定位搜索框并输入关键词基础键盘操作 search_box driver.find_element(By.ID, kw) # 百度搜索框的id是‘kw‘ search_box.send_keys(Selenium 自动化测试) # 模拟键盘输入 # 4. 定位搜索按钮并点击基础鼠标操作 search_button driver.find_element(By.ID, su) search_button.click() # 5. 等待结果加载并简单断言 time.sleep(3) assert Selenium in driver.title print(页面标题包含‘Selenium‘基础操作成功) # 6. 关闭浏览器 driver.quit()运行这个脚本你应该能看到浏览器自动打开百度输入文字并点击搜索。恭喜你的基础环境通了实操心得time.sleep()是“强制等待”在调试时很方便但在正式脚本中是大忌。它会无条件等待固定时间造成脚本效率极低且不稳定网络慢就失败。我们很快就会用更优的“显式等待”来替代它。4. 鼠标操作实战精解现在让我们进入鼠标操作的核心。Selenium 的鼠标高级操作主要通过ActionChains类来实现。记住它的标准流程创建动作链 - 添加动作 - 执行perform。4.1 悬停Hover让隐藏元素现身悬停是Web应用中极其常见的交互用于触发工具提示Tooltip、下拉菜单Dropdown Menu或二级导航。from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver webdriver.Chrome() driver.get(https://www.example.com) # 请替换为一个有悬停效果的页面例如某电商网站的商品图片 try: # 1. 定位需要悬停的元素例如一个头像或菜单项 # 假设一个菜单项的id是‘userMenu‘ element_to_hover driver.find_element(By.ID, userMenu) # 2. 创建ActionChains对象并执行悬停 actions ActionChains(driver) actions.move_to_element(element_to_hover).perform() # move_to_element 即悬停 # 3. 等待悬停后出现的元素如下拉菜单变得可见 # 假设下拉菜单中‘个人中心‘链接的id是‘profileLink‘ wait WebDriverWait(driver, 10) # 最多等10秒 dropdown_item wait.until(EC.visibility_of_element_located((By.ID, profileLink))) # 4. 对出现的元素进行操作 dropdown_item.click() print(悬停并点击下拉菜单项成功) except Exception as e: print(f操作失败: {e}) finally: driver.quit()关键点解析move_to_element(element)这是悬停的核心方法。它会将鼠标光标移动到目标元素的中心点。perform()必须调用否则所有定义的动作都不会执行。等待策略悬停后页面元素通常是动态出现的。使用WebDriverWait配合EC.visibility_of_element_located是标准做法它会在元素可见后的第一时间进行操作而不是傻等固定时间。4.2 拖拽Drag and Drop元素的位置游戏拖拽操作常用于排序、文件上传区域、构建流程图等场景。Selenium提供了两种方式。方式一使用drag_and_drop(source, target)推荐这是最直观的方法将源元素拖放到目标元素。# 假设有一个可排序的列表我们需要将‘项目A‘拖到‘项目B‘的位置 source_element driver.find_element(By.XPATH, //li[text()项目A]) target_element driver.find_element(By.XPATH, //li[text()项目B]) actions ActionChains(driver) actions.drag_and_drop(source_element, target_element).perform()方式二使用click_and_hold-move_to_element-release分解动作当目标不是一个具体元素而是一个坐标位置时或者需要更精细的控制时使用此方法。source_element driver.find_element(By.ID, draggable) actions ActionChains(driver) # 分解动作在源元素上按下鼠标左键 - 移动到某个偏移量 - 松开 actions.click_and_hold(source_element) # 按下不松 actions.move_by_offset(150, 50) # 向右移动150像素向下移动50像素 actions.release() # 松开鼠标 actions.perform()踩坑记录有些网站的拖拽功能依赖于复杂的JavaScript库如Sortable.js标准的drag_and_drop可能失效。这时可以尝试用execute_script直接执行JavaScript来模拟。例如driver.execute_script( var source arguments[0]; var target arguments[1]; // 这里调用页面内拖拽库的API具体代码需根据页面实际情况分析 // 例如对于某些库可能是 $(source).simulate(drag, { to: target }); , source_element, target_element)这需要你分析目标页面的前端实现是高级技巧。4.3 右键点击与双击右键点击通常用于触发上下文菜单Context Menu。element driver.find_element(By.ID, someElement) actions ActionChains(driver) actions.context_click(element).perform() # context_click 即右键点击 # 之后可能需要操作弹出的右键菜单同样需要定位菜单中的项双击操作常用于激活、打开项目或文本选中。element driver.find_element(By.ID, fileItem) actions ActionChains(driver) actions.double_click(element).perform()4.4 组合鼠标操作一个复杂的绘图案例假设我们要在一个画布上画一条折线点击起点 - 拖拽到中间点 - 再拖拽到终点。canvas driver.find_element(By.ID, drawingCanvas) actions ActionChains(driver) # 定义三个点的坐标相对于画布 start_point (50, 50) mid_point (150, 100) end_point (250, 50) # 动作链移动到起点 - 按下左键 - 移动到中间点 - 移动到终点 - 松开 (actions.move_to_element_with_offset(canvas, start_point[0], start_point[1]) .click_and_hold() .move_by_offset(mid_point[0]-start_point[0], mid_point[1]-start_point[1]) .move_by_offset(end_point[0]-mid_point[0], end_point[1]-mid_point[1]) .release() .perform())这里用到了move_to_element_with_offset(element, xoffset, yoffset)它可以将鼠标移动到相对于某个元素左上角的指定偏移位置非常适合在画布、游戏等固定区域内进行精确操作。5. 键盘操作实战精解键盘操作远不止输入文字。组合键快捷键、功能键、导航键是提升自动化脚本效率和模拟真实用户行为的关键。5.1 基础文本输入与清除send_keys()方法是键盘操作的基石。input_box driver.find_element(By.NAME, username) # 1. 输入文本 input_box.send_keys(我的用户名) time.sleep(1) # 2. 清除文本三种方式 # 方式A使用Keys.BACK_SPACE逐个删除模拟用户 for i in range(len(我的用户名)): input_box.send_keys(Keys.BACK_SPACE) time.sleep(0.1) # 增加一点间隔更像真人 # 方式B使用Keys.CONTROL “a“ 全选然后按删除键更高效 input_box.send_keys(Keys.CONTROL, a) # CtrlA input_box.send_keys(Keys.DELETE) # Delete键 # 方式C直接使用clear()方法最简单直接但可能不触发某些前端事件 input_box.clear() # 重新输入 input_box.send_keys(新的用户名)选择哪种清除方式clear()最快但有些前端框架如React, Vue的输入框可能监听的是onInput事件clear()方法可能不会触发它导致页面状态未更新。稳妥起见在重要操作后检查一下输入框的值或页面状态。模拟快捷键CtrlADelete能触发键盘事件更接近用户行为兼容性更好。模拟Backspace最像真人但速度慢适合需要严格模拟用户操作的场景。5.2 功能键与组合键效率的飞跃Keys类提供了几乎所有常用的功能键。from selenium.webdriver.common.keys import Keys # 单个功能键 driver.find_element(By.TAG_NAME, body).send_keys(Keys.F5) # 刷新页面 driver.find_element(By.TAG_NAME, body).send_keys(Keys.ESCAPE) # 关闭弹窗 search_box.send_keys(Keys.ENTER) # 在搜索框中按回车搜索 # 组合键使用ActionChains更规范 actions ActionChains(driver) # 全选 (CtrlA) actions.key_down(Keys.CONTROL).send_keys(a).key_up(Keys.CONTROL).perform() # 复制 (CtrlC) actions.key_down(Keys.CONTROL).send_keys(c).key_up(Keys.CONTROL).perform() # 粘贴 (CtrlV) 到另一个输入框 another_box driver.find_element(By.ID, box2) another_box.click() # 先聚焦 actions.key_down(Keys.CONTROL).send_keys(v).key_up(Keys.CONTROL).perform() # 切换标签页 (CtrlTab) actions.key_down(Keys.CONTROL).send_keys(Keys.TAB).key_up(Keys.CONTROL).perform() # 注意浏览器标签页切换后WebDriver需要切换句柄driver.switch_to.windowkey_down(key)与key_up(key)它们用于模拟“按下”和“抬起”某个修饰键如Ctrl, Shift, Alt。必须成对使用否则键盘状态会一直处于按下状态导致后续操作异常。5.3 高级技巧文件上传与特殊字符文件上传对于input typefile元素最可靠的方式是直接使用send_keys()传入文件的绝对路径。千万不要尝试用ActionChains去模拟点击“浏览”按钮那会打开系统文件对话框WebDriver无法处理。file_input driver.find_element(By.XPATH, //input[typefile]) file_path rC:\Users\YourName\Pictures\test.png # 使用原始字符串避免转义 file_input.send_keys(file_path)输入特殊字符对于Emoji、中文生僻字或某些符号确保你的脚本文件编码是UTF-8并且直接发送Unicode字符串即可。input_box.send_keys(Hello 这是一个测试。)6. 等待策略让脚本稳如泰山这是UI自动化中最容易出错、也最重要的部分。不合理的等待会导致“元素找不到”、“交互失效”等随机性失败。6.1 三种等待方式对比等待类型使用方法优点缺点适用场景强制等待time.sleep(seconds)简单粗暴效率极低无法适应网络或页面速度变化仅用于调试或极少数必须固定等待的场景隐式等待driver.implicitly_wait(seconds)全局设置一次对所有的find_element生效不够灵活只能用于元素存在性检查无法判断元素状态如可点击、可见可以作为基础的兜底策略设置一个较短时间如5秒显式等待WebDriverWait(driver, timeout).until(condition)灵活、精准可以等待任意自定义条件元素可见、可点击、包含特定文本等代码量稍多生产脚本的黄金标准应对动态加载内容的必备技能6.2 显式等待实战详解from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains driver webdriver.Chrome() driver.get(your_dynamic_page_url) wait WebDriverWait(driver, 10) # 创建等待对象超时时间10秒 # 场景1等待元素加载并可见然后点击 login_button wait.until(EC.element_to_be_clickable((By.ID, loginBtn))) login_button.click() # 场景2等待元素出现存在于DOM但不一定可见 hidden_element wait.until(EC.presence_of_element_located((By.CLASS_NAME, loading))) # 可能用于等待一个加载动画出现 # 场景3等待元素从页面消失例如加载完成 wait.until(EC.invisibility_of_element_located((By.CLASS_NAME, loading))) # 场景4等待页面标题包含特定文字 wait.until(EC.title_contains(订单提交成功)) # 场景5与鼠标操作结合等待悬停后的下拉菜单出现 menu driver.find_element(By.ID, mainMenu) ActionChains(driver).move_to_element(menu).perform() dropdown_item wait.until(EC.visibility_of_element_located((By.LINK_TEXT, 设置))) dropdown_item.click() # 场景6自定义等待条件高级 # 例如等待某个输入框的值不为空 def input_has_value(locator): def predicate(driver): element driver.find_element(*locator) # 解包元组(By.ID, “id”) if element.get_attribute(value): return element else: return False return predicate username_input (By.ID, username) wait.until(input_has_value(username_input)) print(用户名已自动填充。)expected_conditions常用条件visibility_of_element_located等待元素可见不仅存在而且宽高大于0。element_to_be_clickable等待元素可见且可点击最常用。presence_of_element_located等待元素出现在DOM中。invisibility_of_element_located等待元素从DOM中消失或不可见。text_to_be_present_in_element等待元素文本包含特定字符串。alert_is_present等待浏览器弹窗Alert出现。核心原则在每一次与元素交互尤其是点击、输入、获取属性之前都应该使用显式等待来确保元素处于可交互状态。这能消除90%以上的因页面加载延迟导致的脚本失败。7. 高级应用与性能优化掌握了基本操作后我们来看看如何构建更健壮、更高效的自动化脚本。7.1 封装可复用的动作函数将常用的复杂操作封装成函数能极大提升代码的可维护性。def hover_and_click(driver, hover_locator, click_locator, timeout10): 悬停在某个元素上然后点击出现的另一个元素。 :param driver: WebDriver实例 :param hover_locator: 元组用于定位悬停元素如 (By.ID, menu) :param click_locator: 元组用于定位要点击的元素如 (By.LINK_TEXT, 子项) :param timeout: 显式等待超时时间 wait WebDriverWait(driver, timeout) # 悬停 hover_element wait.until(EC.presence_of_element_located(hover_locator)) ActionChains(driver).move_to_element(hover_element).perform() # 点击出现的元素 click_element wait.until(EC.element_to_be_clickable(click_locator)) click_element.click() print(f成功执行悬停点击{hover_locator} - {click_locator}) # 使用示例 hover_and_click(driver, (By.ID, userMenu), (By.XPATH, //a[text()退出登录]))7.2 处理富文本编辑器与Canvas对于像TinyMCE、CKEditor这样的富文本编辑器直接定位内部的iframe和可编辑区域是关键。# 1. 切换到编辑器内部的iframe editor_iframe driver.find_element(By.XPATH, //iframe[title富文本编辑器]) driver.switch_to.frame(editor_iframe) # 2. 定位可编辑的body并操作 editable_body driver.find_element(By.TAG_NAME, body) editable_body.clear() editable_body.send_keys(这是通过自动化输入的内容。) # 可能还需要模拟加粗等操作通常是点击编辑器上的按钮 # driver.switch_to.default_content() # 操作完后切回主页面 # 3. 对于Canvas绘图如前所述主要依靠 move_to_element_with_offset 和 click_and_hold 等7.3 性能优化与稳定性提升减少不必要的等待善用显式等待避免全局过长的隐式等待。使用更稳定的定位器优先使用id、name其次是css selector和xpath。避免使用可能变化的文本或索引位置。操作前滚动到元素对于单页应用SPA元素可能不在可视区域。先滚动到元素位置再操作。element driver.find_element(By.ID, footerButton) driver.execute_script(arguments[0].scrollIntoView(true);, element) element.click()失败重试机制对于不稳定的操作如网络请求可以封装一个简单的重试装饰器。import time from functools import wraps def retry_on_failure(max_attempts3, delay1): def decorator(func): wraps(func) def wrapper(*args, **kwargs): for attempt in range(max_attempts): try: return func(*args, **kwargs) except Exception as e: if attempt max_attempts - 1: raise e print(f尝试 {func.__name__} 失败第{attempt1}次重试... 错误: {e}) time.sleep(delay) return None return wrapper return decorator retry_on_failure(max_attempts3) def click_unstable_button(): button driver.find_element(By.ID, ajaxButton) button.click()保持浏览器环境干净定期清理Cookies、缓存或者使用无痕模式启动避免旧数据干扰测试。options webdriver.ChromeOptions() options.add_argument(--incognito) # 无痕模式 driver webdriver.Chrome(optionsoptions)8. 常见问题排查与调试技巧即使准备充分脚本运行时也难免遇到问题。这里有一份我多年积累的“排错清单”。8.1 问题速查表现象可能原因排查步骤与解决方案元素找不到 (NoSuchElementException)1. 页面未加载完成。2. 元素在iframe/frame内。3. 定位器写错了或元素属性动态变化。4. 元素不在当前可视区域。1. 添加显式等待visibility_of...,presence_of...。2. 使用driver.switch_to.frame()切换到正确的frame。3. 使用浏览器开发者工具F12重新检查元素使用相对稳定的属性如>元素不可交互 (ElementNotInteractableException)1. 元素被遮挡弹窗、其他元素。2. 元素被禁用disabled属性。3. 元素是隐藏的display: none,visibility: hidden。1. 关闭遮挡物或等待其消失。2. 检查元素状态等待enabled。3. 检查CSS样式或等待其变为可见。使用EC.element_to_be_clickable等待条件。点击/输入没反应1. 事件监听问题监听了mousedown而非click。2. 前端框架如React的虚拟DOM未更新。3. 点击在了元素的边缘或错误位置。1. 尝试用ActionChains模拟click_and_hold和release。2. 点击后增加一个短暂等待或触发一个其他事件如send_keys(Keys.TAB)来“唤醒”页面。3. 使用move_to_element确保光标在元素中心再点击。脚本在CI/CD上失败本地却成功1. 环境差异浏览器版本、驱动版本、屏幕分辨率。2. 网络速度差异导致超时。3. 无头模式Headless下的渲染差异。1. 在CI环境中固定浏览器和驱动版本。2. 增加显式等待的超时时间。3. 为无头模式添加额外参数并考虑在失败时截图。options.add_argument(--window-size1920,1080)拖拽操作无效1. 目标页面使用了自定义的拖拽库。2. 拖拽坐标计算错误。1. 尝试用execute_script执行页面内的JS拖拽API。2. 使用move_to_element_with_offset进行更精确的坐标控制并考虑加入短暂pause。8.2 强大的调试工具截图与日志当脚本失败时第一手现场信息至关重要。自动截图在关键步骤或捕获异常时截图。def take_screenshot(driver, namescreenshot): 保存截图文件名包含时间戳 import datetime timestamp datetime.datetime.now().strftime(%Y%m%d_%H%M%S) filename f{name}_{timestamp}.png driver.save_screenshot(filename) print(f截图已保存: {filename}) return filename try: # 你的操作代码 element.click() except Exception as e: take_screenshot(driver, before_error) raise e # 重新抛出异常详细日志使用Python的logging模块记录脚本执行过程。import logging logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logger logging.getLogger(__name__) logger.info(开始执行登录流程...) element driver.find_element(By.ID, username) logger.info(f定位到用户名输入框: {element}) element.send_keys(testuser)浏览器开发者工具在脚本运行时如果浏览器窗口没有关闭你可以手动按F12打开开发者工具查看Console、Network和Elements面板这往往是定位问题最快的方式。8.3 处理弹窗与多窗口浏览器原生弹窗 (Alert/Confirm/Prompt)from selenium.webdriver.common.alert import Alert # 等待弹窗出现 WebDriverWait(driver, 5).until(EC.alert_is_present()) alert Alert(driver) # 获取弹窗文本 print(alert.text) # 点击确认 alert.accept() # 点击取消 # alert.dismiss() # 在Prompt弹窗中输入文本 # alert.send_keys(输入的内容)多窗口/标签页切换# 获取当前所有窗口句柄 main_window driver.current_window_handle all_windows driver.window_handles # 列表 # 点击一个会打开新窗口的链接 driver.find_element(By.LINK_TEXT, 新窗口打开).click() # 等待新窗口出现 WebDriverWait(driver, 10).until(lambda d: len(d.window_handles) len(all_windows)) # 切换到新窗口 for window_handle in driver.window_handles: if window_handle ! main_window: driver.switch_to.window(window_handle) break # 在新窗口操作... # ... # 关闭新窗口并切回主窗口 driver.close() driver.switch_to.window(main_window)UI自动化中的鼠标键盘操作就像给脚本装上了一双灵巧的手。从最基础的点击输入到复杂的悬停拖拽组合键每一步都离不开对浏览器事件机制的深刻理解和对脚本稳定性的不懈追求。我个人的体会是写出一个能跑的脚本不难但写出一个能在各种环境、各种网络条件下稳定运行数月的脚本需要大量的细节打磨和经验积累。多使用显式等待少用强制等待多封装复用代码少写重复逻辑遇到问题先截图分析再查日志定位。把这些习惯融入你的开发流程你的自动化脚本才能真正成为值得信赖的测试和生产力工具。最后别忘了UI自动化是最后的手段如果接口能实现优先做接口自动化它更快、更稳定。但当UI交互无法避免时希望这篇详尽的指南能成为你手中可靠的“操作手册”。