【发布时间】:2011-07-21 11:33:34
【问题描述】:
作为我对登录功能的 Selenium 测试的一部分,我想通过识别其坐标并指示 Selenium 单击这些坐标来单击按钮。这将在不识别元素本身的情况下完成(通过 id、xpath 等)。
我知道还有其他更有效的方法来运行点击命令,但我希望专门使用这种方法来最好地匹配用户体验。谢谢。
【问题讨论】:
标签: selenium selenium-rc
作为我对登录功能的 Selenium 测试的一部分,我想通过识别其坐标并指示 Selenium 单击这些坐标来单击按钮。这将在不识别元素本身的情况下完成(通过 id、xpath 等)。
我知道还有其他更有效的方法来运行点击命令,但我希望专门使用这种方法来最好地匹配用户体验。谢谢。
【问题讨论】:
标签: selenium selenium-rc
有一种方法可以做到这一点。使用 ActionChains API,您可以将鼠标移动到包含元素上,调整一些偏移量(相对于该元素的中间)以将“光标”放在所需的按钮(或其他元素)上,然后单击该位置。以下是在 Python 中使用 webdriver 的方法:
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
browser = webdriver.Chrome()
elem = browser.find_element_by_selector(".some > selector")
ac = ActionChains(browser)
ac.move_to_element(elem).move_by_offset(x_offset, y_offset).click().perform()
你们很快就会驳回这个问题。有许多原因可能需要单击特定位置而不是元素。在我的例子中,我有一个带有覆盖元素的 SVG 条形图,可以捕获所有点击。我想模拟点击其中一个栏,但由于覆盖在那里 Selenium 无法点击元素本身。这种技术对于图像映射也很有价值。
【讨论】:
ActionChains(browser).move_to_element(find_element_by_tag_name('html')).move_by_offset(x, y).click().perform()?
<html> 元素生成的 click() 事件不会将点击事件沿 dom 传播到实际元素。
在 C# API 中,您使用操作
var element = driver.FindElement(By...);
new Actions(driver).moveToElement(element).moveByOffset(dx, dy).click().perform();
虽然最好尽可能只使用简单的 Id、CSS、Xpath 选择器。但该功能在需要时存在(即单击某些地理位置的元素以获得功能)。
【讨论】:
我第一次使用 JavaScript 代码,效果非常好,直到网站没有点击。
所以我找到了这个解决方案:
首先,为 Python 导入 ActionChains 并激活它:
from selenium.webdriver.common.action_chains import ActionChains
actions = ActionChains(driver)
要点击会话中的特定点,请使用:
actions.move_by_offset(X coordinates, Y coordinates).click().perform()
注意:上面的代码只有在鼠标没有被触摸的情况下才有效,重置鼠标坐标使用这个:
actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), 0,0))
完整:
actions.move_to_element_with_offset(driver.find_element_by_tag_name('body'), 0,0)
actions.move_by_offset(X coordinates, Y coordinates).click().perform()
【讨论】:
这可以使用java 中的Actions 类来完成
使用以下代码 -
new Actions(driver).moveByOffset(x coordinate, y coordinate).click().build().perform();
注意: Selenium 3 不支持 Actions 类的 geckodriver
另外,请注意 x 和 y 坐标是相对于当前鼠标位置的值。假设鼠标坐标从(0,0)开始,如果你想使用绝对值,你可以使用上面的代码点击它后立即执行下面的操作。
new Actions(driver).moveByOffset(-x coordinate, -y coordinate).perform();
【讨论】:
如果您可以选择在 Selenium 中使用 commercial 插件,那么这是可能的:假设您的按钮位于坐标 x=123, y=456。然后可以使用Helium点击这些坐标处的元素,如下:
from helium.api import *
# Tell Helium about your WebDriver instance:
set_driver(driver)
click(Point(123, 456))
(我是 Helium 的作者之一。)
【讨论】:
这适用于我在 Java 中单击坐标而不考虑任何元素。
Actions actions = new Actions(driver);
actions.moveToElement(driver.findElement(By.tagName("body")), 0, 0);
actions.moveByOffset(xCoordinate, yCoordinate).click().build().perform();
第二行代码会将光标重置到浏览器视图的左上角,最后一行将单击作为参数提供的 x,y 坐标。
【讨论】:
在 Selenium Java 中,您可以使用 Javascript 进行尝试:
WebDriver driver = new ChromeDriver();
if (driver instanceof JavascriptExecutor) {
((JavascriptExecutor) driver).executeScript("el = document.elementFromPoint(x-cordinate, y-cordinate); el.click();");
}
【讨论】:
动作链可能有点挑剔。您也可以通过执行 javascript 来实现。
self.driver.execute_script('el = document.elementFromPoint(440, 120); el.click();')
【讨论】:
我使用了上面列出的许多 Actions 类,但我发现如果我需要从我使用 Firefox Add-On Measurit 获取相对坐标的元素中找到一个相对位置,这很有帮助。 例如:
IWebDriver driver = new FirefoxDriver();
driver.Url = @"https://scm.commerceinterface.com/accounts/login/?next=/remittance_center/";
var target = driver.FindElement(By.Id("loginAsEU"));
Actions builder = new Actions(driver);
builder.MoveToElement(target , -375 , -436).Click().Build().Perform();
我通过单击一个元素然后向后拖动直到到达我需要单击的点得到了 -375、-436。 MeasureIT 说我刚刚减去的坐标。在上面的示例中,我在页面上唯一可点击的元素是“loginAsEu”链接。所以我从那里开始。
【讨论】:
WebElement button = driver.findElement(By.xpath("//button[@type='submit']"));
int height = button.getSize().getHeight();
int width = button.getSize().getWidth();
Actions act = new Actions(driver);
act.moveToElement(button).moveByOffset((width/2)+2,(height/2)+2).click();
【讨论】:
import pyautogui
from selenium import webdriver
driver = webdriver.Chrome(chrome_options=options)
driver.maximize_window() #maximize the browser window
driver.implicitly_wait(30)
driver.get(url)
height=driver.get_window_size()['height']
#get browser navigation panel height
browser_navigation_panel_height = driver.execute_script('return window.outerHeight - window.innerHeight;')
act_y=y%height
scroll_Y=y/height
#scroll down page until y_off is visible
try:
driver.execute_script("window.scrollTo(0, "+str(scroll_Y*height)+")")
except Exception as e:
print "Exception"
#pyautogui used to generate click by passing x,y coordinates
pyautogui.FAILSAFE=False
pyautogui.moveTo(x,act_y+browser_navigation_panel_height)
pyautogui.click(x,act_y+browser_navigation_panel_height,clicks=1,interval=0.0,button="left")
这对我有用。希望,这对你们有用:)...
【讨论】:
我使用 AutoIt 来做到这一点。
using AutoIt;
AutoItX.MouseClick("LEFT",150,150,1,0);//1: click once, 0: Move instantaneous
【讨论】:
补充一下,因为我为此苦苦挣扎了一段时间。这些是我采取的步骤:
document.onclick = function(e)
{
var x = e.pageX;
var y = e.pageY;
alert("User clicked at position (" + x + "," + y + ")")
};
WebDriverWait(DRIVER GOES HERE, 10).until(EC.element_to_be_clickable(YOUR ELEMENT LOCATOR GOES HERE))
actions = ActionChains(DRIVER GOES HERE)
actions.move_by_offset(X, Y).click().perform()
【讨论】:
如果此页面上提到的所有其他方法都失败并且您使用的是 python,我建议您使用mouse module 以更原生的方式来代替。代码很简单
import mouse
mouse.move("547", "508")
mouse.click(button='left')
你也可以使用keyboard module来模拟键盘动作
import keyboard
keyboard.write('The quick brown fox jumps over the lazy dog.')
要查找鼠标的坐标,可以使用下面的 JavaScript 代码。
document.onclick=function(event) {
var x = event.screenX ;
var y = event.screenY;
console.log(x, y)
}
如果你不喜欢 screenX,你可以使用 pageX 或 clientX。更多关于here
附:我遇到了一个阻止与 JavaScript/DOM/Selenium 进行编程交互的网站。这可能是一种机器人预防机制。但是,他们无法禁止操作系统操作。
【讨论】:
Selenium::WebDriver 具有PointerActions 模块,其中包括许多您可以在不指定元素的情况下链接和/或触发的操作,例如。 move_to_location 或 move_by。见detailed specs here。如您所见,您只能使用实际坐标。我确信这个接口是在其他语言/库中实现的。
我的简短回复可能会与这里的一些其他 cmets 相呼应,但我只是想提供一个链接以供参考。
【讨论】:
如果你能看到页面的源代码,通过它的 id 或 NAME 属性来引用按钮总是最好的选择。例如,您的“登录”按钮如下所示:
<input type="submit" name="login" id="login" />
在这种情况下是最好的方法
selenium.click(id="login");
只是出于好奇 - 这不是 HTTP 基本身份验证吗?在这种情况下,也许看看这个: http://code.google.com/p/selenium/issues/detail?id=34
【讨论】:
Selenium 不会让你这样做。
【讨论】:
moveToElement() 完全符合原始发帖人的意愿:通过坐标以外的其他方式识别元素。差不多 6 年后,我仍然不明白为什么 OP 会想要这样,但 Selenium 仍然不可能。