在 Selenium 中使用 ActionChains 的动作链进行元素操作非常便捷,可以省去很多定位元素的麻烦,但是这里面不小心也会踩坑,尤其是 click 这个函数的使用要稍加小心,否则它会“点击”不到你期望的元素。
来,看案例。
被测页面:
https://login.sina.com.cn/signup/signup?entry=homepage
测试需求:
-
通过元素定位,点击“新闻”复选框;
-
以 ActionChains 方式通过模拟按下键盘的 Tab 键,将焦点切换到“娱乐”复选框;
-
通过 click() 函数选中“娱乐”复选框。
代码运行现象描述:
-
通过元素定位方式,“新闻”复选框被正确选中
【✔】
-
以 ActionChains 方式执行时,“娱乐”复选框没有被选中,而且“新闻”复选框的选中状态被清除
【✘】
代码如下:
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
# 打开火狐浏览器
driver = webdriver.Firefox()
# 打开新浪注册页面
driver.get('https://login.sina.com.cn/signup/signup?entry=homepage')
# 从浏览器开发者工具中直接复制“新闻”复选框的 CSS 选择器路径
news_css = '.checklst > label:nth-child(1) > input:nth-child(1)'
# 定位到 “新闻” 复选框
ck_news = driver.find_element_by_css_selector(news_css)
# 点击 “新闻” 复选框,获得初始焦点位置
ck_news.click()
# 依次实现动作链: 移动到“新闻” -> 点击 Tab键(到“娱乐”) -> 点击 -> 执行
ActionChains(driver).move_to_element(ck_news).\
send_keys(Keys.TAB).click().\
perform()
发现问题了没有,在 ActionChains 的动作链中,click() 函数没有按我们的意愿执行!!
截取 click 函数的部分
源码
看看
位置:\Lib\site-packages\selenium\webdriver\common\action_chains.py
有几点需要注意:
-
这个函数带有一个默认参数 on_element,默认值为 None;
-
如果传入了一个页面元素,则点击此页面元素;
-
如果没有传入指定元素,则点击当前的焦点元素。
上面的代码中,我们没有为 click 函数传参数,也就是说它点击的是当前页面的焦点元素。那么问题来了,当前页面的焦点元素是哪个呢?
再从源码中继续读一下 ActionChains 这个类的说明:
class ActionChains(object):
。。。。。。。。。。
Generate user actions.
When you call methods for actions on the ActionChains object,
the actions are stored in a queue in the ActionChains object.
When you call perform(), the events are fired in the order they
are queued up.
看明白了吧,只有当调用 perform() 这个函数的时候,前面写的一大串动作链才被依次执行。
也就是说:
-
在 ActionChains 语句之前,焦点位置在 “新闻” 这个复选框上。
-
在执行 perform() 之前,焦点位置一直在 “新闻” 这个复选框上。
-
在执行 perform() 之前的 click() 操作,也是在对焦点元素 “新闻” 进行的点击操作,所以非但没有选中 “娱乐”,还把已经选中的 “新闻” 给清除了选中状态。
接下来我们看看如何解决吧。整体思路是将前面的动作链断开,将点击操作独立出来。
改变前错误代码:
ActionChains(driver).move_to_element(ck_news).\
send_keys(Keys.TAB).click().\
perform()
改变后代码:
ActionChains(driver).move_to_element(ck_news).\
send_keys(Keys.TAB).perform()
ActionChains(driver).\
move_to_element(driver.switch_to.active_element).\
click().perform()
改变后分析:
-
模拟按下 Tab 键后,立即 perform 执行,当前焦点元素位置(新闻)真实发生改变,定位到了下一个元素(娱乐);
-
通过 switch_to 操作,重新定位到当前活动(焦点)元素处,即“娱乐”复选框,此时执行“click”点击操作就没有问题了。
附上最终代码:
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
# 打开火狐浏览器
driver = webdriver.Firefox()
# 打开新浪注册页面
driver.get('https://login.sina.com.cn/signup/signup?entry=homepage')
# 从浏览器开发者工具中直接复制“新闻”复选框的 CSS 选择器路径
news_css = '.checklst > label:nth-child(1) > input:nth-child(1)'
# 定位到 “新闻” 复选框
ck_news = driver.find_element_by_css_selector(news_css)
# 点击 “新闻” 复选框,获得初始焦点位置
ck_news.click()
# 依次实现动作链: 移动到“新闻” -> 点击 Tab键(到“娱乐”) -> 执行
# 作用:实现焦点元素切换
ActionChains(driver).move_to_element(ck_news).\
send_keys(Keys.TAB).perform()
# 依次实现动作链: 移动到焦点元素(娱乐) -> 点击 -> 执行
# 作用:点击最新的焦点元素
ActionChains(driver).\
move_to_element(driver.switch_to.active_element).\
click().perform()
selenium中的使用WebElement.click()出现失效是个老大难的问题,在stackoverflow上也有不少人在抱怨,说从3.0到4.1都没有解决。抛开html页面元素相互遮盖和元素定位不准的情况,经过测试,发现主要出现在chrome 和edge浏览器上,同样一个网站,chrome浏览器点击失效但是使用firefox正常。网上的资料提出了不少的解决办法,但是有些是不靠谱的 ,现一一总结如下:
1.WebElement.click()点击成功,但是程序挂起,不能运行下一步。
...
要实现拖拽印章的动作,我引入ActionChains类模拟鼠标拖动,但却发现没有效果
#通过指定坐标来拖动,没有效果
drag_and_drop_by_offset().perform()
#通过source和target指定两个位置拖动,没有效果
drag_and_drop().perform()
#然后还试了分步拖动,还是没效果
click_and_hold().perform()
move_to_element().perform()
release().perform()
元素是可以定位到的
情景:web自动化模拟拖拽元素,从一个位置拖动到另一个画布canvas,使用ActionChains的方法没有实现,后来也换了pywin32库也没有实现最后找到pyautogui库 ,不过调试坐标点还是很麻烦,只能说是解决了问题。听说opencv处理坐标很方便,还没有使用,有兴趣可以试试。下面是当时用的代码,直接贴下面:
dragged = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "#centerControls >
动态加载的元素上click事件不生效
$(".openORclose2").click(function () {
if ($(this).hasClass("checkOpen2")) {
$(this).removeClass("checkOpen2");
$(this).parent().parent().removeClass("QAhover");
$(this).parent().parent().
1、本文使用Python语言,以淘宝网为例
2、本文将介绍selenium–webdriver库中的ActionChains类,该类提供了模拟鼠标的常用方法,包括单击、双击、悬停、拖动等常用功能
3、前置步骤,需要先安装selenium并导入ActionChains类
一、ActionChains类方法介绍
1.执行所有存储的操作 - perform()
perform(self)预学习perform()方法,首先要先了解一下ActionChains的执行原理:
当你调用ActionChains中的
1.ActionChains基本用法
首先需要了解ActionChains的执行原理,当你调用ActionChains的方法时,不会立即执行,而是会将所有的操作按顺序存放在一个队列里,当你调用perform()方法时,队列中的时间会依次执行。
2、ActionChains方法列表
click_and_hold(on_element=None) ——点击鼠标左键,不松开
context_click(on_element=None) ——点击鼠标右键
double_click(on_element=None).