Selenium Actions 链操作 #
ActionChains 概述 #
什么是 ActionChains #
text
┌─────────────────────────────────────────────────────────────┐
│ ActionChains 工作原理 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ActionChains 是 Selenium 提供的低级交互 API │
│ 允许模拟复杂的用户交互操作 │
│ │
│ 特点: │
│ • 链式调用 - 多个操作可以串联执行 │
│ • 延迟执行 - 操作添加到队列,调用 perform() 时执行 │
│ • 精确控制 - 可以精确控制鼠标和键盘操作 │
│ │
│ 工作流程: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ actions = ActionChains(driver) │ │
│ │ │ │ │
│ │ ├── click(element) ──> 队列: [click] │ │
│ │ ├── send_keys("text") ──> 队列: [click, │ │
│ │ │ send_keys] │ │
│ │ ├── double_click() ──> 队列: [click, │ │
│ │ │ send_keys, │ │
│ │ │ double_click] │ │
│ │ │ │ │
│ │ └── perform() ──> 按顺序执行所有操作 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
基本用法 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
# 创建 ActionChains 对象
actions = ActionChains(driver)
# 单个操作
element = driver.find_element(By.ID, "button")
actions.click(element).perform()
# 链式操作
actions.click(element).send_keys("Hello").perform()
driver.quit()
鼠标操作 #
点击操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
element = driver.find_element(By.ID, "button")
actions = ActionChains(driver)
# 单击元素
actions.click(element).perform()
# 在当前位置单击
actions.click().perform()
# 双击元素
actions.double_click(element).perform()
# 右键点击(上下文菜单)
actions.context_click(element).perform()
driver.quit()
悬停操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
actions = ActionChains(driver)
# 悬停到元素
menu = driver.find_element(By.ID, "menu")
actions.move_to_element(menu).perform()
# 悬停后点击子菜单
submenu = driver.find_element(By.ID, "submenu")
actions.move_to_element(menu).move_to_element(submenu).click().perform()
# 多级菜单悬停
menu1 = driver.find_element(By.ID, "menu1")
menu2 = driver.find_element(By.ID, "menu2")
menu3 = driver.find_element(By.ID, "menu3")
actions.move_to_element(menu1).pause(0.5).move_to_element(menu2).pause(0.5).move_to_element(menu3).click().perform()
driver.quit()
移动操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
element = driver.find_element(By.ID, "target")
actions = ActionChains(driver)
# 移动到元素中心
actions.move_to_element(element).perform()
# 移动到元素的偏移位置
actions.move_to_element_with_offset(element, 10, 20).perform()
# 从当前位置移动指定偏移量
actions.move_by_offset(100, 50).perform()
# 重置鼠标位置
actions.move_to_element(element).perform()
actions.move_by_offset(-50, -50).perform()
driver.quit()
拖拽操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com/drag-drop")
source = driver.find_element(By.ID, "draggable")
target = driver.find_element(By.ID, "droppable")
actions = ActionChains(driver)
# 方式一:使用 drag_and_drop
actions.drag_and_drop(source, target).perform()
# 方式二:手动组合操作
actions.click_and_hold(source).move_to_element(target).release().perform()
# 拖拽到偏移位置
actions.drag_and_drop_by_offset(source, 100, 50).perform()
# 手动拖拽到偏移位置
actions.click_and_hold(source).move_by_offset(100, 50).release().perform()
# 拖拽过程中暂停
actions.click_and_hold(source).pause(1).move_to_element(target).pause(1).release().perform()
driver.quit()
键盘操作 #
按键操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
input_field = driver.find_element(By.ID, "input")
actions = ActionChains(driver)
# 发送文本
actions.send_keys("Hello World").perform()
# 发送到特定元素
actions.send_keys_to_element(input_field, "Hello World").perform()
# 发送特殊按键
actions.send_keys(Keys.ENTER).perform()
actions.send_keys(Keys.TAB).perform()
actions.send_keys(Keys.ESCAPE).perform()
driver.quit()
修饰键操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
input_field = driver.find_element(By.ID, "input")
actions = ActionChains(driver)
# 按下 Shift 输入大写
actions.key_down(Keys.SHIFT).send_keys("hello").key_up(Keys.SHIFT).perform()
# 全选 (Ctrl+A)
actions.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
# 复制 (Ctrl+C)
actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
# 粘贴 (Ctrl+V)
actions.key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
# 剪切 (Ctrl+X)
actions.key_down(Keys.CONTROL).send_keys('x').key_up(Keys.CONTROL).perform()
# macOS 使用 COMMAND 键
actions.key_down(Keys.COMMAND).send_keys('a').key_up(Keys.COMMAND).perform()
driver.quit()
组合键操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
input_field = driver.find_element(By.ID, "input")
actions = ActionChains(driver)
# Ctrl+Shift+End (选择到末尾)
actions.key_down(Keys.CONTROL).key_down(Keys.SHIFT).send_keys(Keys.END).key_up(Keys.SHIFT).key_up(Keys.CONTROL).perform()
# Alt+F4 (关闭窗口)
actions.key_down(Keys.ALT).send_keys(Keys.F4).key_up(Keys.ALT).perform()
# Ctrl+Shift+T (重新打开关闭的标签页)
actions.key_down(Keys.CONTROL).key_down(Keys.SHIFT).send_keys('t').key_up(Keys.SHIFT).key_up(Keys.CONTROL).perform()
driver.quit()
高级操作 #
暂停操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
element = driver.find_element(By.ID, "target")
actions = ActionChains(driver)
# pause(seconds) - 在操作链中添加暂停
actions.move_to_element(element).pause(1).click().pause(0.5).double_click().perform()
# 用于等待动画完成
actions.click(element).pause(2).send_keys("text").perform()
driver.quit()
点击并按住 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
element = driver.find_element(By.ID, "target")
actions = ActionChains(driver)
# 点击并按住
actions.click_and_hold(element).perform()
# 移动后释放
actions.click_and_hold(element).move_by_offset(100, 0).release().perform()
# 长按(模拟长按操作)
actions.click_and_hold(element).pause(2).release().perform()
driver.quit()
释放操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Chrome()
driver.get("https://example.com")
element = driver.find_element(By.ID, "target")
actions = ActionChains(driver)
# release() - 释放鼠标按键
actions.click_and_hold(element).move_by_offset(50, 50).release().perform()
# release(element) - 在指定元素上释放
target = driver.find_element(By.ID, "drop-target")
actions.click_and_hold(element).move_to_element(target).release().perform()
driver.quit()
复杂场景示例 #
拖拽排序 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
def drag_to_sort():
driver = webdriver.Chrome()
driver.get("https://example.com/sortable")
try:
items = driver.find_elements(By.CSS_SELECTOR, ".sortable-item")
actions = ActionChains(driver)
# 将第一项拖到最后一项后面
actions.drag_and_drop(items[0], items[-1]).perform()
# 或者使用偏移量精确控制
first_item = items[0]
actions.click_and_hold(first_item).move_by_offset(0, 200).release().perform()
print("拖拽排序完成")
finally:
driver.quit()
drag_to_sort()
多级菜单导航 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
def navigate_multi_level_menu():
driver = webdriver.Chrome()
driver.get("https://example.com")
try:
actions = ActionChains(driver)
# 三级菜单导航
menu1 = driver.find_element(By.CSS_SELECTOR, ".menu-level-1")
menu2 = driver.find_element(By.CSS_SELECTOR, ".menu-level-2")
menu3 = driver.find_element(By.CSS_SELECTOR, ".menu-level-3")
# 链式悬停操作
actions.move_to_element(menu1).pause(0.3).move_to_element(menu2).pause(0.3).move_to_element(menu3).click().perform()
print("菜单导航完成")
finally:
driver.quit()
navigate_multi_level_menu()
画布绘图 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
def draw_on_canvas():
driver = webdriver.Chrome()
driver.get("https://example.com/canvas")
try:
canvas = driver.find_element(By.ID, "drawing-canvas")
actions = ActionChains(driver)
# 移动到画布中心
actions.move_to_element(canvas)
# 绘制正方形
actions.click_and_hold().move_by_offset(100, 0).move_by_offset(0, 100).move_by_offset(-100, 0).move_by_offset(0, -100).release().perform()
# 绘制直线
actions.move_to_element(canvas).move_by_offset(-50, -50).click_and_hold().move_by_offset(100, 100).release().perform()
print("画布绘图完成")
finally:
driver.quit()
draw_on_canvas()
滑块验证 #
python
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
def slider_verification():
driver = webdriver.Chrome()
driver.get("https://example.com/slider-captcha")
try:
wait = WebDriverWait(driver, 10)
# 等待滑块出现
slider = wait.until(EC.presence_of_element_located((By.ID, "slider-button")))
actions = ActionChains(driver)
# 点击滑块并拖动
actions.click_and_hold(slider).move_by_offset(200, 0).pause(0.5).release().perform()
# 验证是否成功
success = driver.find_element(By.ID, "success-message")
if success.is_displayed():
print("滑块验证成功")
finally:
driver.quit()
slider_verification()
文本选择 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
def select_text():
driver = webdriver.Chrome()
driver.get("https://example.com")
try:
textarea = driver.find_element(By.ID, "content")
textarea.send_keys("这是一段需要选择的文本内容,用于演示文本选择功能。")
actions = ActionChains(driver)
# 方式一:双击选择单词
actions.double_click(textarea).perform()
# 方式二:拖拽选择文本
actions.click(textarea).click_and_hold().move_by_offset(100, 0).release().perform()
# 方式三:使用键盘选择
actions.click(textarea).key_down(Keys.SHIFT).send_keys(Keys.ARROW_RIGHT * 10).key_up(Keys.SHIFT).perform()
# 方式四:全选
actions.click(textarea).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
print("文本选择完成")
finally:
driver.quit()
select_text()
复制粘贴操作 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
def copy_paste_operation():
driver = webdriver.Chrome()
driver.get("https://example.com")
try:
source = driver.find_element(By.ID, "source")
target = driver.find_element(By.ID, "target")
actions = ActionChains(driver)
# 选择源文本
actions.click(source).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
# 复制
actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
# 移动到目标并粘贴
actions.click(target).key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
print("复制粘贴完成")
finally:
driver.quit()
copy_paste_operation()
ActionChains 工具类 #
python
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
class ActionsHelper:
def __init__(self, driver):
self.driver = driver
self.actions = ActionChains(driver)
def hover_and_click(self, hover_element, click_element):
"""悬停后点击"""
self.actions.move_to_element(hover_element).click(click_element).perform()
def drag_to_element(self, source, target):
"""拖拽到目标元素"""
self.actions.drag_and_drop(source, target).perform()
def drag_by_offset(self, element, x, y):
"""拖拽指定偏移量"""
self.actions.drag_and_drop_by_offset(element, x, y).perform()
def select_all(self, element=None):
"""全选"""
if element:
self.actions.click(element).key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
else:
self.actions.key_down(Keys.CONTROL).send_keys('a').key_up(Keys.CONTROL).perform()
def copy(self):
"""复制"""
self.actions.key_down(Keys.CONTROL).send_keys('c').key_up(Keys.CONTROL).perform()
def paste(self, element=None):
"""粘贴"""
if element:
self.actions.click(element).key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
else:
self.actions.key_down(Keys.CONTROL).send_keys('v').key_up(Keys.CONTROL).perform()
def cut(self):
"""剪切"""
self.actions.key_down(Keys.CONTROL).send_keys('x').key_up(Keys.CONTROL).perform()
def type_with_delay(self, element, text, delay=0.1):
"""带延迟的输入"""
import time
for char in text:
element.send_keys(char)
time.sleep(delay)
def draw_line(self, canvas, start_offset, end_offset):
"""在画布上画线"""
self.actions.move_to_element(canvas).move_by_offset(*start_offset).click_and_hold().move_by_offset(
end_offset[0] - start_offset[0], end_offset[1] - start_offset[1]
).release().perform()
# 使用示例
driver = webdriver.Chrome()
driver.get("https://example.com")
helper = ActionsHelper(driver)
source = driver.find_element(By.ID, "source")
target = driver.find_element(By.ID, "target")
helper.drag_to_element(source, target)
driver.quit()
最佳实践 #
操作稳定性 #
python
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
def stable_actions():
driver = webdriver.Chrome()
wait = WebDriverWait(driver, 10)
try:
driver.get("https://example.com")
# 等待元素可交互
element = wait.until(EC.element_to_be_clickable((By.ID, "button")))
# 滚动到元素可见
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element)
# 添加暂停确保稳定
actions = ActionChains(driver)
actions.move_to_element(element).pause(0.5).click().perform()
finally:
driver.quit()
跨平台兼容 #
python
import platform
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
def get_modifier_key():
"""根据操作系统返回修饰键"""
return Keys.COMMAND if platform.system() == 'Darwin' else Keys.CONTROL
def cross_platform_shortcut(driver, action):
"""跨平台快捷键"""
modifier = get_modifier_key()
actions = ActionChains(driver)
shortcuts = {
'select_all': lambda: actions.key_down(modifier).send_keys('a').key_up(modifier).perform(),
'copy': lambda: actions.key_down(modifier).send_keys('c').key_up(modifier).perform(),
'paste': lambda: actions.key_down(modifier).send_keys('v').key_up(modifier).perform(),
'cut': lambda: actions.key_down(modifier).send_keys('x').key_up(modifier).perform(),
}
if action in shortcuts:
shortcuts[action]()
下一步 #
掌握了 Actions 链操作后,接下来学习 Pytest 集成 了解如何构建完整的测试框架!
最后更新:2026-03-28