我将Selenium
WebDriver与java.awt.Robot结合使用,以更好地模拟用户与Web应用程序的交互。是的,我知道可能没有必要,但是我所服务的客户都需要它。
当前,一切运行良好,但是我有一个小问题,就是我似乎找不到找到将Web元素显示在屏幕上位置的好方法。诸如标题栏,菜单栏,导航栏之类的东西都将内容向下推到物理屏幕上(Robot从中获取坐标),但对Selenium报告元素所在的位置没有影响。
当我element.getLocation();
在Selenium
WebElement上调用:时,它总是为我提供相对于HTML内容呈现窗格的位置,而不是浏览器窗口本身的位置。
一个更好的示例是:driver.findElement(By.tagName("body")).getLocation();
无论窗口的实际屏幕位置如何,始终返回0,0。
现在,我通过在最大化窗口后添加垂直和水平偏移量来破解它,但是不同的浏览器之间这些偏移量并不相同(例如,IE的顶部装饰所占的空间要比Firefox更大),并且每个用户可能会有所不同如果其中添加了书签工具栏,搜索栏等。
是的,我知道我可以在全屏模式下运行,但如果可能的话,我宁愿不运行。
有没有一种方法可以使用WebDriver以可靠的方式获取元素在屏幕上的物理位置?
我相信无法获得页面上元素的真实屏幕位置。
我也认为全屏模式是您最好的选择。
就是说,我写了一个RobotCalibration
可以检测当前浏览器实际偏移量的类。它会打开一个特制页面,并使用Robot
该类单击它。该算法从浏览器的中心开始,然后使用二等分线找到浏览器视口的左上角。
在IE8和FF18上测试。适用于最大化和窗口浏览器。已知问题:如果启用了顶部的书签工具栏,则它可能会单击某些书签,因此会重定向。它可以很容易地处理,但是如果您需要它,我留给您:)。
测试页面:
<!DOCTYPE html>
<html lang="en" onclick="document.getElementById('counter').value++">
<head>
<meta charset="utf-8" />
<title>Calibration Test</title>
</head>
<body>
<img height="1" width="1" style="position: absolute; left: 0; top: 0;"
onclick="document.getElementById('done').value = 'yep'" />
<input type="text" id="counter" value="0" />
<input type="text" id="done" value="nope" />
</body>
</html>
该RobotCalibration
班。它有点长,所以我建议您将其复制粘贴到您喜欢的IDE中并在其中进行探索:
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.nio.file.Paths;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
public class RobotCalibration {
public static Point calibrate(WebDriver driver) {
return new RobotCalibration(driver).calibrate();
}
/** Time for which to wait for the page response. */
private static final long TIMEOUT = 1000;
private final WebDriver driver;
private final Robot r;
private final Point browserCenter;
private int leftX;
private int rightX;
private int midX;
private int topY;
private int bottomY;
private int midY;
private RobotCalibration(WebDriver driver) {
this.driver = driver;
try {
driver.manage().window().getSize();
} catch (UnsupportedOperationException headlessBrowserException) {
throw new IllegalArgumentException("Calibrating a headless browser makes no sense.", headlessBrowserException);
}
try {
this.r = new Robot();
} catch (AWTException headlessEnvironmentException) {
throw new IllegalStateException("Robot won't work on headless environments.", headlessEnvironmentException);
}
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
org.openqa.selenium.Dimension browserSize = driver.manage().window().getSize();
org.openqa.selenium.Point browserPos = driver.manage().window().getPosition();
// a maximized browser returns negative position
// a maximized browser returns size larger than actual screen size
// you can't click outside the screen
leftX = Math.max(0, browserPos.x);
rightX = Math.min(leftX + browserSize.width, screenSize.width - 1);
midX = (leftX + rightX) /2;
topY = Math.max(0, browserPos.y);
bottomY = Math.min(topY + browserSize.height, screenSize.height - 1);
midY = (topY + bottomY) /2;
browserCenter = new Point(midX, midY);
}
private Point calibrate() {
driver.get(Paths.get("files/RobotCalibration.html").toUri().toString());
// find left border
while (leftX < rightX) {
click(midX, midY);
if (clickWasSuccessful()) {
rightX = midX;
} else {
leftX = midX + 1;
// close any menu we could have opened
click(browserCenter.x, browserCenter.y);
}
midX = (leftX + rightX) /2;
}
// find top border
while (topY < bottomY) {
click(midX, midY);
if (clickWasSuccessful()) {
bottomY = midY;
} else {
topY = midY + 1;
// close any menu we could have opened
click(browserCenter.x, browserCenter.y);
}
midY = (topY + bottomY) /2;
}
if (!isCalibrated()) {
throw new IllegalStateException("Couldn't calibrate the Robot.");
}
return new Point(midX, midY);
}
/** clicks on the specified location */
private void click(int x, int y) {
r.mouseMove(x, y);
r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
// for some reason, my IE8 can't properly register clicks that are close
// to each other faster than click every half a second
if (driver instanceof InternetExplorerDriver) {
sleep(500);
}
}
private static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ignored) {
// nothing to do
}
}
private int counter = 0;
/** @return whether the click on a page was successful */
private boolean clickWasSuccessful() {
counter++;
long targetTime = System.currentTimeMillis() + TIMEOUT;
while (System.currentTimeMillis() < targetTime) {
int pageCounter = Integer.parseInt(driver.findElement(By.id("counter")).getAttribute("value"));
if (counter == pageCounter) {
return true;
}
}
return false;
}
/** @return whether the top left corner has already been clicked at */
private boolean isCalibrated() {
long targetTime = System.currentTimeMillis() + TIMEOUT;
while (System.currentTimeMillis() < targetTime) {
if (driver.findElement(By.id("done")).getAttribute("value").equals("yep")) {
return true;
}
}
return false;
}
}
用法示例:
WebDriver driver = new InternetExplorerDriver();
Point p = RobotCalibration.calibrate(driver);
System.out.println("Left offset: " + p.x + ", top offset: " + p.y);
driver.quit();
如果有不清楚的地方,请随时提出任何问题。
问题内容: 如何使用python获取和设置窗口(任何Windows程序)的位置和大小? 问题答案: 假设您使用的是Windows,请尝试使用带有和功能的的模块。 如果您使用的是Mac OS X,则可以尝试使用。 对于Linux,您可以尝试X11的众多接口之一。 编辑: Windows的示例(未测试):
问题内容: 这是该问题的后续内容,其中对我的查询进行了改进,使其使用窗口函数而不是联接内的聚合。虽然查询现在快得多,但我发现结果不正确。 我需要在x年尾随时间框架上执行计算。例如,每行的计算方法是:十年前移至当前行,然后除以结果。为了简单起见,我们将使用1年。 SQL Fiddle对此问题进行了解答。(Postgres 9.6) 作为一个简单的例子,和用于可像这样分别计算: 要做到这一点 ,每行
问题内容: 如何通过自定义Firefox配置文件将Selenium与Java结合使用? 问题答案: 我花了一天的时间尝试执行此操作,并决定在此处分享。网络上也有一些信息,但是其中大多数都有些复杂或者不是最新的… 这是我的配置: 开放终端 类型:(根据需要更改路径) 创建一个新的配置文件,根据需要将其保存在目录中。 使用此配置文件启动firefox,并根据需要添加所有附件和修改。 在硒中,使用: F
问题内容: 我正在试验Firefox的WebDriver,请问是否可以处理“下载”窗口(接受或拒绝传入的下载请求)? 例如,一段简单的代码: 我已经对此进行了一些尝试,但是还没有找到解决方案。我真的很感谢任何提示。 非常感谢,-V 问题答案: 一种解决方案是更改WebDriver的Firefox配置文件,以将某些MIME类型自动下载到给定目录。 我不确定如何(或是否)在Python中公开此信息,但
问题内容: 我需要通过控制器中的代码关闭当前的fxml窗口 我知道stage.close()或stage.hide()在fx中做到这一点 如何在fxml中实现呢?我试过了 但这不起作用! 所有帮助将不胜感激。谢谢! 问题答案: 如果您还没有关闭按钮,请给它一个fx:id: 在您的控制器类中:
问题内容: 我有一个表单,当我单击它时会在新选项卡中打开。当我尝试导航到该新选项卡时,我不断收到NoSuchWindowException。代码非常简单。“ myframe”是新标签中最终将被插入信息的框架。我应该再等吗? 问题答案: 感谢Debanjan(并为以后的回复表示歉意-刚回到办公室)。我能够通过使用解决此问题 我没有意识到,当我单击打开表单时,另一个窗口在后台非常短暂地打开,然后关闭。