Selenium的ActionChains Api接口详解
ActionChains
有时候我们在通过Selenium做UI自动化的时候,明明能够在DOM树内看到这个元素,但是我在通过driver click、sendkey的时候,就是点击不到或无法输入字符串。实际上这是由于WEB中某些元素需要通过一系列连贯的操作才能处于可以点击的状态,driver提供的click方法是每次都只执行一个命令操作,而我们需要连贯的操作。或者经常遇到那种,需要鼠标悬浮后,要操作的元素才会出现的某种场景,那么我们就要模拟鼠标悬浮到某一个位置,做一系列的连贯操作,这里就要应用Selenium提供的ActionChains模块
具体使用方法参考官方文档: https://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.common.action_chains
或某大佬翻译的中文文档:https://python-selenium-zh.readthedocs.io/zh_CN/latest/7.2%20%E8%A1%8C%E4%B8%BA%E9%93%BE/
引入方式
#引入方式一 from selenium.webdriver.common.action_chains import ActionChains #引入方式二 from selenium.webdriver import ActionChains
实际上ActionChains这个模块的实现的核心思想就是,当你调用ActionChains的方法时,不会立即执行,而是会将所有的操作按顺序存放在一个List里,当你调用perform()方法时,队列中的时间会依次执行。(注:推荐一个尺子工具,MeasulerIt)
ActionChains方法列表
click(on_element=None) ——单击鼠标左键
click_and_hold(on_element=None) ——点击鼠标左键,不松开
context_click(on_element=None) ——点击鼠标右键
double_click(on_element=None) ——双击鼠标左键
drag_and_drop(source, target) ——拖拽到某个元素然后松开
drag_and_drop_by_offset(source, xoffset, yoffset) ——拖拽到某个坐标然后松开
key_down(value, element=None) ——按下某个键盘上的键
key_up(value, element=None) ——松开某个键
move_by_offset(xoffset, yoffset) ——鼠标从当前位置移动到某个坐标
move_to_element(to_element) ——鼠标移动到某个元素
move_to_element_with_offset(to_element, xoffset, yoffset) ——移动到距某个元素(左上角坐标)多少距离的位置
perform() ——执行链中的所有动作
release(on_element=None) ——在某个元素位置松开鼠标左键
send_keys(*keys_to_send) ——发送某个键到当前焦点的元素
send_keys_to_element(element, *keys_to_send) ——发送某个键到指定元素
drag_and_drop(鼠标拖动)
# 将source元素拖放至target元素处,参数为两个elementObj
ActionChains(driver).drag_and_drop(source=source,target=target)
# 将一个source元素 拖动到针对source坐上角坐在的x y处 可存在负宽度的情况和负高度的情况
ActionChains(driver).drag_and_drop_by_offset(source, x, y)
# 这种也是拖拽的一种方式,都是以源元素的左上角为基准,移动坐标
ActionChains(driver).click_and_hold(dom).move_by_offset(169,188).release().perform()
move_to_element
# 鼠标移动到某一个元素上,结束elementObj
ActionChains(driver).move_to_element(e)
# 鼠标移动到制定的坐标上,参数接受x,y
ActionChains(driver).move_by_offset(e['x'],e['y'])
例:
driver = webdriver.Chrome()
driver.maximize_window()
driver.get('http://www.baidu.com')
time.sleep(2)
# driver.execute_script('document.body.scrollTop=0')
driver.execute_script('document.documentElement.scrollTop')
time.sleep(1)
a = driver.find_element_by_id('a').location
dis = driver.find_element_by_id('dis1')
ActionChains(driver).move_by_offset(a['x'],a['y']).double_click(dis).perform()
click
# 单击事件,可接受elementObj
ActionChains(driver).click()
# 双击事件,可接受elementObj
ActionChains(driver).double_click()
# 点击鼠标右键
ActionChains(driver).context_click()
# 点击某个元素不松开,接收elementObj
ActionChains(driver).click_and_hold()
# # 某个元素上松开鼠标左键,接收elementObj
ActionChains(driver).release()
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:test_actionchains.py
@time:2020/09/27
"""
import pytest
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains
class TestDefaultSuite():
def setup_method(self, ):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(5)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> teardown_method(self):
self.driver.quit()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标点击测试</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> @pytest.mark.skip</span>
<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_case_click(self):
self.driver.get(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">http://sahitest.com/demo/clicks.htm</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
click_btn </span>= self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//input[@value="click me"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 单击按钮</span>
doubleclick_btn = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//input[@value="dbl click me"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 双击按钮</span>
rightclick_btn = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//input[@value="right click me"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 右键单击按钮</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> action=ActionChains(self.driver)</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> action.click(click_btn) # 单击</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> action.double_click(doubleclick_btn) # 双击</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> action.context_click(rightclick_btn) # 右键</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> action.perform()</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> sleep(5)</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 或者直接以长链的方式执行,按照顺序依次执行</span>
ActionChains(self.driver).click(click_btn).double_click(doubleclick_btn).context_click(rightclick_btn).perform()
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标移动测试</span>
<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_case_move(self):
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> self.driver.get('https://www.baidu.com/')</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> set_ele=self.driver.find_element_by_id('s-usersetting-top') # 百度的设置元素</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> ActionChains(self.driver).move_to_element(set_ele).perform()</span>
<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> sleep(5)</span>
self.driver.get(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">http://sahitest.com/demo/mouseover.htm</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
write </span>=<span style="color: rgba(0, 0, 0, 1)"> self.driver.find_element_by_xpath(
</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//input[@value="Write on hover"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标移动到此元素,在下面的input框中会显示“Mouse moved”</span>
blank = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//input[@value="Blank on hover"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标移动到此元素,会清空下面input框中的内容</span>
result = self.driver.find_element_by_name(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">t1</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
action </span>=<span style="color: rgba(0, 0, 0, 1)"> ActionChains(self.driver)
action.move_to_element(write).perform() </span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 移动到write,显示“Mouse moved”</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(result.get_attribute(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> action.move_to_element(blank).perform()</span>
action.move_by_offset(10, 50).perform() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 移动到距离当前位置(10,50)的点,与上句效果相同,移动到blank上,清空</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(result.get_attribute(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">))
action.move_to_element_with_offset(blank, </span>10, -40).perform() <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 移动到距离blank元素(10,-40)的点,可移动到write上</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(result.get_attribute(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">value</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">))
sleep(</span>2<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 鼠标拖拽</span>
<span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_case_drapdrop(self):
self.driver.get(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">http://sahitest.com/demo/dragDropMooTools.htm</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
dragger </span>= self.driver.find_element_by_id(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">dragger</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 被拖拽元素</span>
item1 = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//div[text()="Item 1"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 目标元素1</span>
item2 = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//div[text()="Item 2"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 目标2</span>
item3 = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//div[text()="Item 3"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 目标3</span>
item4 = self.driver.find_element_by_xpath(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">//div[text()="Item 4"]</span><span style="color: rgba(128, 0, 0, 1)">'</span>) <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 目标4</span>
action = ActionChains(self.driver)
action.drag_and_drop(dragger, item1).perform() # 1.移动dragger到目标1
sleep(2)
action.click_and_hold(dragger).release(item2).perform() # 2.效果与上句相同,也能起到移动效果
sleep(2)
action.click_and_hold(dragger).move_to_element(item3).release().perform() # 3.效果与上两句相同,也能起到移动的效果
sleep(2)
# action.drag_and_drop_by_offset(dragger, 400, 150).perform() # 4.移动到指定坐标
action.click_and_hold(dragger).move_by_offset(400, 150).release().perform() # 5.与上一句相同,移动到指定坐标
sleep(2)
if name == 'main':
pytest.main()
执行结果
Testing started at 12:59 上午 ... /usr/local/bin/python3.9 "/Applications/PyCharm CE.app/Contents/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path /Users/chenshifeng/MyCode/PythonCode/SFDSZL/test_selenium/test_actionchains.py Launching pytest with arguments /Users/chenshifeng/MyCode/PythonCode/SFDSZL/test_selenium/test_actionchains.py in /Users/chenshifeng/MyCode/PythonCode/SFDSZL/test_selenium============================= test session starts ==============================
platform darwin -- Python 3.9.0, pytest-6.1.1, py-1.9.0, pluggy-0.13.1 -- /usr/local/bin/python3.9
cachedir: .pytest_cache
rootdir: /Users/chenshifeng/MyCode/PythonCode/SFDSZL/test_selenium
plugins: allure-pytest-2.8.18
collecting ... collected 3 itemstest_actionchains.py::TestDefaultSuite::test_case_click
test_actionchains.py::TestDefaultSuite::test_case_move
test_actionchains.py::TestDefaultSuite::test_case_drapdrop============================== 3 passed in 37.93s ==============================
Process finished with exit code 0
PASSED [ 33%]PASSED [ 66%]Mouse movedMouse moved
PASSED [100%]
有时我们需要模拟键盘操作时,那么就需要用到ActionChains中的key操作了,提供了两个方法,key_down与key_up,模拟按下键盘的某个键子,与松开某个键子,接收的参数是按键的Keys与elementObj。可以与send_keys连用(例:全选、复制、剪切、粘贴)
# key_down 模拟键盘摁下某个按键 key_up 松开某个按键,与sendkey连用完成一些操作,每次down必须up一次否则将出现异常
ActionChains(driver).key_down(Keys.CONTROL,dom).send_keys('a').send_keys('c').key_up(Keys.CONTROL)\
.key_down(Keys.CONTROL,dom1).send_keys('v').key_up(Keys.CONTROL).perform()
Keys 实际是Selenium提供的一个键盘事件模块,在模拟键盘事件时需要导入Keys模块
引入路径
from selenium.webdriver.common.keys import Keys
#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author:chenshifeng
@file:test_actionchains.py
@time:2020/09/27
"""
import pytest
from selenium import webdriver
from time import sleep
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
class TestDefaultSuite():
def setup_method(self, ):
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.implicitly_wait(5)
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> teardown_method(self):
self.driver.quit()
</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> test_key(self):
self.driver.get(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">https://www.baidu.com/</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
dom </span>= self.driver.find_element_by_id(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">kw</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
ActionChains(self.driver).key_down(Keys.SHIFT, dom).send_keys(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">a</span><span style="color: rgba(128, 0, 0, 1)">'</span>).send_keys(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">c</span><span style="color: rgba(128, 0, 0, 1)">'</span>).key_up(Keys.SHIFT).pause(2).perform()</pre>
end
转载至https://www.cnblogs.com/feng0815/p/8344120.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
2017-07-17 心情
2017-07-17 http接口测试框架-遇到的问题
2017-07-17 http接口测试框架-构想图
2017-07-17 http接口测试框架-python