Selenium 中使用 ActionChains 时 click 执行失效的分析

 

在 Selenium 中使用 ActionChains 的动作链进行元素操作非常便捷,可以省去很多定位元素的麻烦,但是这里面不小心也会踩坑,尤其是 click 这个函数的使用要稍加小心,否则它会“点击”不到你期望的元素。

 

来,看案例。

 

被测页面:https://login.sina.com.cn/signup/signup?entry=homepage

 

Selenium 中使用 ActionChains 时 click 执行失效的分析_第1张图片

测试需求:

  1. 通过元素定位,点击“新闻”复选框;
  2. 以 ActionChains 方式通过模拟按下键盘的 Tab 键,将焦点切换到“娱乐”复选框;
  3. 通过 click() 函数选中“娱乐”复选框。

 

代码运行现象描述:

  1. 通过元素定位方式,“新闻”复选框被正确选中【✔】
  2. 以 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

 

Selenium 中使用 ActionChains 时 click 执行失效的分析_第2张图片

 

有几点需要注意:

  • 这个函数带有一个默认参数 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()

 

 

改变后分析:

  1. 模拟按下 Tab 键后,立即 perform 执行,当前焦点元素位置(新闻)真实发生改变,定位到了下一个元素(娱乐);
  2. 通过 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 中使用 ActionChains 时 click 执行失效的分析)