用于向 Web 浏览器提供虚拟化输入操作的低级接口。
- 键盘输入
- 鼠标输入
- 笔或触摸设备的指针输入
- 滚轮输入(v4.2+)
实现动作交互依赖ActionChains
库,是对更底层动作类ActionBuilder
的封装。
当调用ActionChains
操作方法时,操作事件被存储在ActionChains
对象的队列中。在调用perform()
时,将按照操作事件的顺序一个接一个触发执行。
暂停(Pause)
鼠标操作链中设置等待时间。
clickable = driver.find_element(By.ID, "clickable")
ActionChains(driver)
.move_to_element(clickable)
.pause(1)
.click_and_hold()
.pause(1)
.send_keys("abc")
.perform()
释放(Clear)
当已经生成了动作链但是没有进行perform
操作,即使后面创建了新的动作类实例,鼠标依然处于先前的状态,所以需要释放已经生成但没有执行的动作链。
from selenium.webdriver.common.actions.action_builder import ActionBuilder
# 释放所有 actions
ActionBuilder(driver).clear_actions()
1. 鼠标(Mouse)
1.1 点击
# 鼠标左键并按住不放
ActionChains(driver)\
.click_and_hold(clickable)\
.perform()
# 鼠标左键
clickable = driver.find_element(By.ID, "click")
ActionChains(driver)\
.click(clickable)\
.perform()
# 鼠标右键
clickable = driver.find_element(By.ID, "clickable")
ActionChains(driver)\
.context_click(clickable)\
.perform()
# 鼠标左键双击
clickable = driver.find_element(By.ID, "clickable")
ActionChains(driver)\
.double_click(clickable)\
.perform()
"""
鼠标键
部分鼠标无按键不支持,经测试 Mac 与罗技无线鼠标均可
"""
# 鼠标后退键(v4.2+)
action = ActionBuilder(driver)
action.pointer_action.pointer_down(MouseButton.BACK)
action.pointer_action.pointer_up(MouseButton.BACK)
action.perform()
# 鼠标前进键(v4.2+)
action = ActionBuilder(driver)
action.pointer_action.pointer_down(MouseButton.FORWARD)
action.pointer_action.pointer_up(MouseButton.FORWARD)
action.perform()
1.2 移动
# 将鼠标移动到元素的中心点
hoverable = driver.find_element(By.ID, "hover")
ActionChains(driver)\
.move_to_element(hoverable)\
.perform()
"""
按偏移量移动
offset(13, 15) 向右移动 13,向下移动 15
offset(-15, -20) 向左移动 15,向上移动 20
"""
# 从元素偏移(左上原点)
mouse_tracker = driver.find_element(By.ID, "mouse-tracker")
ActionChains(driver)\
.move_to_element_with_offset(mouse_tracker, 8, 0)\
.perform()
# 从元素偏移(中心原点)
action = ActionBuilder(driver)
action.pointer_action.move_to_location(8, 0)
action.perform()
# 基于当前指针位置的偏移量
ActionChains(driver)\
.move_by_offset( 13, 15)\
.perform()
1.3 拖放
# 点击并按住 A 元素,移动到 B 元素,释放鼠标
draggable = driver.find_element(By.ID, "draggable")
droppable = driver.find_element(By.ID, "droppable")
ActionChains(driver)\
.drag_and_drop(draggable, droppable)\
.perform()
# 点击并按住 A 元素,移动到给定的偏移量,释放鼠标
draggable = driver.find_element(By.ID, "draggable")
start = draggable.location
finish = driver.find_element(By.ID, "droppable").location
ActionChains(driver)\
.drag_and_drop_by_offset(draggable, finish['x'] - start['x'], finish['y'] - start['y'])\
.perform()
2. 键盘(Keyboard)
2.1 Key
模拟键盘上的键操作。
from selenium.webdriver import Keys
"""
The Keys implementation.
"""
2.2 按下键
from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.common.by import By
# 按下 shift 键不放,输入字母,得到大写字母
ActionChains(driver)\
.key_down(Keys.SHIFT)\
.send_keys("abc")\
.perform()
2.3 抬起键
# 按下 shift 输入大写 A
# 松开 shift 输入小写 b
ActionChains(driver)\
.key_down(Keys.SHIFT)\
.send_keys("a")\
.key_up(Keys.SHIFT)\
.send_keys("b")\
.perform()
2.4 输入字符
# 基于当前元素
ActionChains(driver)\
.send_keys("abc")\
.perform()
2.5 向指定元素输入字符
text_input = driver.find_element(By.ID, "textInput")
ActionChains(driver)\
.send_keys_to_element(text_input, "abc")\
.perform()
2.6 复制粘贴
cmd_ctrl = Keys.COMMAND if sys.platform == 'darwin' else Keys.CONTROL
"""
官方文档通过 firefox_driver 执行
"""
ActionChains(driver)\
.send_keys("Selenium!")\
.send_keys(Keys.ARROW_LEFT)\
.key_down(Keys.SHIFT)\
.send_keys(Keys.ARROW_UP)\
.key_up(Keys.SHIFT)\
.key_down(cmd_ctrl)\
.send_keys("xvv")\
.key_up(cmd_ctrl)\
.perform()
"""
chrome 通过下面的方法实现
"""
ele = driver.find_element(value="textInput")
ele.send_keys('Selenium!')
ele.send_keys(cmd_ctrl, 'a')
time.sleep(2)
# 键盘的复制操作
ele.send_keys(cmd_ctrl, 'c')
time.sleep(2)
# 键盘的剪切操作
ele.send_keys(cmd_ctrl, 'x')
time.sleep(2)
# 键盘的粘贴操作
ele.send_keys(cmd_ctrl, 'v')
time.sleep(2)
# 键盘的删除操作
ele.send_keys(cmd_ctrl, 'a')
ele.send_keys(Keys.BACKSPACE)
3. 笔(Pen)
仅支持 chromium;v4.2+
笔是一种指针输入,具有与鼠标基本相同的行为,但也可以具有手写笔独有的事件属性。此外,鼠标有5个按钮,而笔有3个等效的按钮状态:
- 0:触摸(默认,相当于左键单击)
- 2:筒状按钮(相当于右键单击)
- 5:橡皮擦按钮(目前不支持)
driver.get('https://www.selenium.dev/selenium/web/pointerActionsPage.html')
pointer_area = driver.find_element(By.ID, "pointerArea")
pen_input = PointerInput(POINTER_PEN, "default pen")
action = ActionBuilder(driver, mouse=pen_input)
# 使用笔
action.pointer_action\
.move_to(pointer_area)\
.pointer_down()\
.move_by(2, 2)\
.pointer_up()
action.perform()
# 添加指针事件属性
action.pointer_action\
.move_to(pointer_area)\
.pointer_down()\
.move_by(2, 2, tilt_x=-72, tilt_y=9, twist=86)\
.pointer_up(0)
action.perform()
4. 滚轮(Wheel)
4.1 滚动到元素
一直滚动,直到指定元素出现在屏幕中。
iframe = driver.find_element(By.TAG_NAME, "iframe")
ActionChains(driver)\
.scroll_to_element(iframe)\
.perform()
4.2 按指定偏移量滚动
# 传入一个 delta x 和 delta y 值,表示向右和向下滚动的量。负值分别代表左和上。
footer = driver.find_element(By.TAG_NAME, "footer")
# rect 具有元素位置和大小的字典,取元素的 y 值
# {'height': 23, 'width': 1169, 'x': 8, 'y': 5217.5}
delta_y = int(footer.rect['y'])
ActionChains(driver)\
.scroll_by_amount(0, delta_y)\
.perform()
4.3 基于元素向指定偏移量滚动
"""
第一个表示起始点,我们将其指定为元素,后两个是 delta x 和 delta y 值。
如果元素在可见窗口之外,它将滚动到屏幕底部,然后页面将根据提供的 delta x 和 delta y 值滚动。
"""
iframe = driver.find_element(By.TAG_NAME, "iframe")
scroll_origin = ScrollOrigin.from_element(iframe)
ActionChains(driver)\
.scroll_from_origin(scroll_origin, 0, 200)\
.perform()
4.4 基于元素的偏移量向指定偏移量滚动
footer = driver.find_element(By.TAG_NAME, "footer")
scroll_origin = ScrollOrigin.from_element(footer, 0, -50)
ActionChains(driver)\
.scroll_from_origin(scroll_origin, 0, 200)\
.perform()
4.5 基于原点的偏移量向指定偏移量滚动
scroll_origin = ScrollOrigin.from_viewport(10, 10)
ActionChains(driver)\
.scroll_from_origin(scroll_origin, 0, 200)\
.perform()