我正在尝试为iFrame内部的元素创建XPath定位器:我希望这个iframe成为XPath的根,因为我在2个不同的iframe中有两个类似的元素—但似乎无法这样做知道为什么不行吗?
edit-我没有试图以任何方式与此元素交互(我知道我需要在与其中的元素交互之前切换帧,我只是有一个XPath定位器问题),我想创建一个XPath与iframe作为根元素,因为上面提到的情况下面是代码:
<div id="framesWrapper">
<div id="frame1Wrapper">
<iframe src="/sample" id="frame1" width="500px" height="350px"></iframe>
#document
<DOCTYPE hmtl>
<html>
<head>...</head>
<body style="background-color:#a9a9a9" data-new-gr-c-s-check-loaded="14.1065.0" data-gr-ext-installed=""><h1 id="sampleHeading">This is a sample page</h1>
<h1 id="sampleHeading">This is a sample page</h1>
</body>
</html>
</div>
<div id="frame2Wrapper" class="mt-4">
<iframe src="/sample" id="frame2" width="100px" height="100px"></iframe>
</div>
</div>
通常,在尝试与页面上的元素进行交互之前,需要等待页面加载完毕(这似乎是常识)。然而,你可能不知道的是
- 如果你不使用隐式或显式wait, web驱动程序将尝试立即与web元素交互。在缓慢加载的页面上,这将导致一个错误,因为有问题的web元素将不可用。
- 使用隐式等待(使用
WebDriver
对象)只等待一个预定的超时时间。这往往是有点慢,因为它不会打破等待,如果页面加载快。 - 使用显式的等待(使用
WebDriverWait
类)允许你设置一个条件,如果满足条件(即网页元素在页面上可见),将告诉web驱动程序中断等待。
如果你知道这些事实,请原谅我做这样的解释。我认为这是必要的,因为它是遵循。
与位于iframe中的web元素交互的一般方法如下:
1)首先定位iframe
WebDriver driver... // your web driver instance
Duration timeout = Duration.ofSeconds(10); // adjust to your needs
Duration sleepBetweenPolls = Duration.ofMillis(10); // default "sleep" is 500 milliseconds
WebDriverWait wait = new WebDriverWait(driver, timeout, sleepBetweenPolls); // wait object can be reused
...
wait.until(ExpectedConditions.frameToBeAvailableAndSwitchToIt(By.xpath(...))); // passing the XPath of the iframe
我显式地创建了您需要的所有对象,以便您可以更好地看到或理解它们的功能。例如,您不需要显式地创建Duration
对象。我只是觉得这样表达会更有帮助。此外,由于您不需要iframe web元素,因此在wait.until(...)
之前没有变量声明。您只需要在尝试下面的步骤#2之前创建一个等待条件,使iframe可用。
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath(...))); // pass the xpath of the element
button.click(); // you might need something other than a button. There are other conditions to wait for (i.e. visibility of elements, availability of elements, etc.)
3)完成后返回到主(父)框架
driver.switchTo().parentFrame();
那应该是你所需要的。显然,还有更多的原因。TimeoutException
是达到超时限制时抛出的异常。您可能希望也可能不希望将这些代码行包装在try/catch中。通常情况下,我所做的是将try/catch包围起来,这样如果第一次尝试超时,我就可以执行另一个计划。例如,在某些情况下,我在初始尝试后重试。其他时候,我尝试定位另一个元素。例如,如果页面加载时没有出现错误,则元素可能是可见的。因此,我的第一次尝试可能是定位该元素,第二次尝试可能是定位预期的错误消息。关键是使用try/catch来处理超时可能是有益的。我忘记提到的一件事是TimeoutException
是RuntimeException
的一种。因此,您不必强制捕获(处理)它们。这取决于你是让它失败,还是用一种更优雅的方式处理。
显然,在您的情况下,您需要处理两个iframe。您所需要做的就是对这两个框架都遵循这个配方,显式地为每个框架传递正确的定位符,并在完成后切换到父框架。这一点非常重要。否则,当你试图与父框架中的其他组件进行交互时,你的web驱动程序将无法进行交互,因为它仍然认为它试图在你告诉它要查找的最后一帧中找到这些组件(并且这些组件将不再存在)。