有没有办法通过Selenium WebDriver获取HTML窗口(页面主体)的屏幕坐标?
答案 0 :(得分:4)
看了几次并且还没有从WebDriver找到一个优雅的解决方案(他们有一个看起来在他们的ILocatable设置中支持的参数,但该方法尚未实现)。
我所做的是使用UIAutomation获取windows AutomationElement并使用树木行者来查找窗口的实际对象 - 缺点是我注意到浏览器偶尔会更新它们的窗口,因此条件必须每隔一段时间更改一次容纳。
这是一些示例代码(我在这里删除了一些公司代码,所以它在我的结尾更优雅,但这应该适用于C#)
public static Rectangle GetAbsCoordinates(this IWebElement element)
{
var driver = GetDriver(element);
var handle = GetIntPtrHandle(driver);
var ae = AutomationElement.FromHandle(handle);
AutomationElement doc = null;
var caps = ((RemoteWebDriver) driver).Capabilities;
var browserName = caps.BrowserName;
switch (browserName)
{
case "safari":
var conditions = (new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "SearchableWebView")));
doc = ae.FindFirst(TreeScope.Descendants, conditions);
break;
case "firefox":
doc = ae.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document));
break;
case "chrome":
doc = ae.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Chrome Legacy Window"));
if (doc == null)
{
doc = ae.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
if (doc == null)
throw new Exception("unable to find element containing browser window");
doc = doc.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document));
}
break;
case "internet explorer":
doc = ae.FindFirst(TreeScope.Descendants, new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "TabWindowClass")));
break;
}
if (doc == null)
throw new Exception("unable to find element containing browser window");
var iWinLeft = (int) doc.Current.BoundingRectangle.Left;
var iWinTop = (int)doc.Current.BoundingRectangle.Top;
var coords = ((ILocatable) element).Coordinates;
var rect = new Rectangle(iWinLeft + coords.LocationInDom.X, iWinTop + coords.LocationInDom.Y, element.Size.Width, element.Size.Height);
return rect;
}
public static IWebDriver GetDriver(this IWebElement e)
{
return ((IWrapsDriver)e).WrappedDriver;
}
public static IntPtr GetIntPtrHandle(this IWebDriver driver, int timeoutSeconds = Timeout)
{
var end = DateTime.Now.AddSeconds(timeoutSeconds);
while(DateTime.Now < end)
{
// Searching by AutomationElement is a bit faster (can filter by children only)
var ele = AutomationElement.RootElement;
foreach (AutomationElement child in ele.FindAll(TreeScope.Children, Condition.TrueCondition))
{
if (!child.Current.Name.Contains(driver.Title)) continue;
return new IntPtr(child.Current.NativeWindowHandle);;
}
}
return IntPtr.Zero;
}
答案 1 :(得分:1)
基本上,对于UIAutomation,您需要掌握一个名为inspect的工具(在8.1 SDK中免费提供)。像uispy这样的旧工具可能也会起作用。
基本上你会启动chrome然后启动检查器工具 - 你将看到树状结构,然后向下导航到包含DOM的文档。打开工具中的突出显示以使其更容易。
Chrome在树形控件的布局中看起来非常动态 - 不得不修改它几次以适应我正在看的控件。如果您使用的版本与我不同 - 基本上在树中找到文档窗口并查看与其关联的所有控件模式 - 这就是我传递给PropertyCondition以了解如何搜索控件。 Intellisense应该为您提供不同的东西来查询,如AutomationElement.NameProperty。这是我的例子 - 我注意到在winXP机器和win8机器上运行chrome时有区别...因此检查为null。
就像我之前说过的那样 - 这不是很优雅,如果将它内置到Selenium(我想他们有更好的方法来确定DOM区域的坐标)会很棒......我认为这也会有问题对于那些搬到Selenium Grid的人来说(就像我正在做的那样) - 据我所知,使用它我不知道你是否可以通过一堆支持dll将硒转移到远程机器上...至少没有很多黑客。
如果它仍然不适合你 - 给我一个关于操作系统,Chrome版本的具体想法,我会尝试看看并给出确切的属性匹配。可能是最好的,但如果你弄乱自己,不幸的是这些东西不是静止的。
答案 2 :(得分:1)
Zechtitus发布的代码非常棒,我在IE11和Chrome版本39.0.2171.95米下尝试了它,它就像一个魅力。虽然我不得不传递IWebDriver的真实对象而不是使用WrappedDriver,因为它不能与Chrome一起使用。仅为了您的信息,我有Win 7终极x64和使用Selenium WebDriver 2.44。这是我从Zechtitus中获取并修改它的代码:
public static Rectangle GetAbsCoordinates(IWebDriver driver, IWebElement element)
{
var handle = GetIntPtrHandle(driver);
var ae = AutomationElement.FromHandle(handle);
AutomationElement doc = null;
var caps = ((RemoteWebDriver)driver).Capabilities;
var browserName = caps.BrowserName;
switch (browserName)
{
case "safari":
var conditions = (new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "SearchableWebView")));
doc = ae.FindFirst(TreeScope.Descendants, conditions);
break;
case "firefox":
doc = ae.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document));
break;
case "chrome":
doc = ae.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Chrome Legacy Window"));
if (doc == null)
{
doc = ae.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.NameProperty, "Google Chrome"));
if (doc == null)
throw new Exception("unable to find element containing browser window");
doc = doc.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Document));
}
break;
case "internet explorer":
doc = ae.FindFirst(TreeScope.Descendants, new AndCondition(new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Pane),
new PropertyCondition(AutomationElement.ClassNameProperty, "TabWindowClass")));
break;
}
if (doc == null)
throw new Exception("unable to find element containing browser window");
var iWinLeft = (int)doc.Current.BoundingRectangle.Left;
var iWinTop = (int)doc.Current.BoundingRectangle.Top;
var coords = ((ILocatable)element).Coordinates;
var rect = new Rectangle(iWinLeft + coords.LocationInDom.X, iWinTop + coords.LocationInDom.Y, element.Size.Width, element.Size.Height);
return rect;
}
public static IntPtr GetIntPtrHandle(this IWebDriver driver, int timeoutSeconds = 20)
{
var end = DateTime.Now.AddSeconds(timeoutSeconds);
while (DateTime.Now < end)
{
// Searching by AutomationElement is a bit faster (can filter by children only)
var ele = AutomationElement.RootElement;
foreach (AutomationElement child in ele.FindAll(TreeScope.Children, Condition.TrueCondition))
{
if (!child.Current.Name.Contains(driver.Title)) continue;
return new IntPtr(child.Current.NativeWindowHandle); ;
}
}
return IntPtr.Zero;
}
我用过这样的话:
Rectangle recView = GetAbsCoordinates(MyWebDriverObj,myIWebElementObj);
然后将正确的X,Y存储在recView.X和recView.Y中 正如我所说,它为IE11和Chrome都在为我工作。 祝你好运
答案 3 :(得分:1)
是。这是可能的。随便一招。在下面找到我的代码以便继续 屏幕顶部的网页元素。
long scrollPosition = getScollPosition();
long elemYPositionOnScreen = (long) elem.getLocation().getY() - scrollPosition;
public static long getScrollYPosition() {
WebDriver driver = DriverFactory.getCurrentDriver();
JavascriptExecutor jse = (JavascriptExecutor) driver;
Long scrollYPos = (Long) jse.executeScript("return window.scrollY;");
return scrollYPos;
}
答案 4 :(得分:0)
我快速浏览了一下chrome,你可能会有更好的运气。
doc = win.Find.ByConditions(new PropertyCondition(AutomationElement.ClassNameProperty, "Chrome_RenderWidgetHostHWND"));
我认为类名称对于chrome来说是一致的...似乎适用于我的旧版本和更新版本的操作系统 - chrome版本34.0.1847.116m。希望有所帮助。
答案 5 :(得分:0)
一旦得到支持,这应该有效:
WebElement htmlElement = driver.findElement(By.tagName("html"));
Point viewPortLocation = ((Locatable) htmlElement).getCoordinates().onScreen();
int x = viewPortLocation.getX();
int y = viewPortLocation.getY();
但是现在它引发了以下错误:
java.lang.UnsupportedOperationException: Not supported yet.
at org.openqa.selenium.remote.RemoteWebElement$1.onScreen(RemoteWebElement.java:342)
(on org.seleniumhq.selenium:selenium-java:2.46.0)
答案 6 :(得分:0)
我在Robot Framework中需要一个this,而我受到Jeyabal解决方案的启发,所以下面的改编对我有用:
${verticalWindow}= Execute Javascript return window.scrollY;
${verticalElement} = Get Vertical Position /xpath
${hasScrolled} = Evaluate (${verticalElement} - ${verticalWindow}) == 0
答案 7 :(得分:0)
没有什么对我有用。一种解决方法是使用window.innerHeight
和window.innerWidth
并从左下角向上移动。假设浏览器的底部边框几乎为0(没有水平滚动条或厚窗口装饰)。
win_pos = selenium.get_window_position()
win_size = selenium.get_window_size()
win_bottom_y = win_pos['y'] + win_size['height']
# We assume viewport x == window x. For y coordinate we take the bottom
# of the browser and subtract the viewport height
viewport_height = selenium.execute_script('return window.innerHeight')
viewport_width = selenium.execute_script('return window.innerWidth')
viewport_y = win_bottom_y - viewport_height
这不是100%准确,但可以针对您的情况进行调整。
答案 8 :(得分:-1)
你可以这样试试:
WebDriver driver=new FirefoxDriver();
driver.get("http://www.google.com");
JavascriptExecutor js=(JavascriptExecutor) driver;
Double i= (Double) js.executeScript("var element = document.getElementById('hplogo');var position = element.getBoundingClientRect();return position.left");
System.out.print(i);
答案 9 :(得分:-1)
试试这个,我希望它会对你有所帮助:
Rectangle rec = new Rectangle(element.getLocation(), element.getSize());