If you set the implicit wait of the driver, then call the findElement method on an element you expect to be on the loaded page, the WebDriver will poll for that element until it finds the element or reaches the time out value.
In general, with Selenium 2.0 the web driver should only return control to the calling code once it has determined that the page has loaded. If it does not, you can call waitforelemement, which cycles round calling findelement until it is found or times out (time out can be set).
All of these solutions are OK for specific cases, but they suffer from at least one of a couple of possible problems:
They are not generic enough -- they want you to know, ahead of time, that some specific condition will be true of the page you are going to (eg some element will be displayed)
They are open to a race condition where you use an element that is actually present on the old page as well as the new page.
Here's my attempt at a generic solution that avoids this problem (in Python):
First, a generic "wait" function (use a WebDriverWait if you like, I find them ugly):
def wait_for(condition_function):
start_time = time.time()
while time.time() < start_time + 3:
if condition_function():
return True
else:
time.sleep(0.1)
raise Exception('Timeout waiting for {}'.format(condition_function.__name__))
Next, the solution relies on the fact that selenium records an (internal) id-number for all elements on a page, including the top-level <html> element. When a page refreshes or loads, it gets a new html element with a new ID.
So, assuming you want to click on a link with text "my link" for example:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
请参阅 ExpectedConditions class Javadoc 以获取您可以检查的所有条件的列表。
You can also use the class: ExpectedConditions to explicitly wait for an element to show up on the webpage before you can take any action further actions
You can use the ExpectedConditions class to determine if an element is visible:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
See ExpectedConditions class Javadoc for list of all conditions you are able to check.
This seems to be a serious limitation of WebDriver. Obviously waiting for an element will not imply the page being loaded, in particular the DOM can be fully build (onready state) whereby JS is still executing and CSS and images are still loading.
I believe the simplest solution is to set a JS variable upon the onload event after everything is initialized and check and wait for this JS variable in Selenium.
Man all these answers require too much code. This should be a simple thing as its pretty common.
Why not just inject some simple Javascript with the webdriver and check. This is the method I use in my webscraper class. The Javascript is pretty basic even if you don't know it.
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state. See doc link below.
"""
ready_state = self.driver.execute_script('return document.readyState')
if ready_state == 'loading':
self.logger.info("Loading Page...")
elif ready_state == 'interactive':
self.logger.info("Page is interactive")
elif ready_state == 'complete':
self.logger.info("The page is fully loaded!")
return ready_state
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
If you want to wait for a specific element to load, you can use the isDisplayed() method on a RenderedWebElement :
// Sleep until the div we want is visible or 5 seconds is over
long end = System.currentTimeMillis() + 5000;
while (System.currentTimeMillis() < end) {
// Browsers which render content (such as Firefox and IE) return "RenderedWebElements"
RenderedWebElement resultsDiv = (RenderedWebElement) driver.findElement(By.className("gac_m"));
// If results have been returned, the results are displayed in a drop down.
if (resultsDiv.isDisplayed()) {
break;
}
}
I'm surprised that predicates weren't the first choice as you typically know what element(s) you will next interact with on the page you're waiting to load. My approach has always been to build out predicates/functions like waitForElementByID(String id) and waitForElemetVisibleByClass(String className), etc. and then use and reuse these wherever I need them, be it for a page load or page content change I'm waiting on.
For example,
In my test class:
driverWait.until(textIsPresent("expectedText");
In my test class parent:
protected Predicate<WebDriver> textIsPresent(String text){
final String t = text;
return new Predicate<WebDriver>(){
public boolean apply(WebDriver driver){
return isTextPresent(t);
}
};
}
protected boolean isTextPresent(String text){
return driver.getPageSource().contains(text);
}
Though this seems like a lot, it takes care of checking repeatedly for you and the interval for how often to check can be set along with the ultimate wait time before timing out. Also, you will reuse such methods.
In this example, the parent class defined and initiated the WebDriver driver and the WebDriverWait driverWait.
The best way to wait for page loads when using the Java bindings for WebDriver is to use the Page Object design pattern with PageFactory. This allows you to utilize the AjaxElementLocatorFactory which to put it simply acts as a global wait for all of your elements. It has limitations on elements such as drop-boxes or complex javascript transitions but it will drastically reduce the amount of code needed and speed up test times. A good example can be found in this blogpost. Basic understanding of Core Java is assumed.
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
You can use the below existing method to set the pageLoadTimeout. In below example if the page is taking more than 20 seconds to load, then it will throw an exception of page reload:
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
Wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpathOfElement));
var element = GlobalDriver.FindElement(By.XPath(xpathOfElement));
var isSucceededed = element != null;
You can use this snippet of code for the page to load:
IWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver,TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
Or you can use waiter for any element to be loaded and become visible/clickable on that page, most probably which is going to be load at the end of loading like:
Wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpathOfElement));
var element = GlobalDriver.FindElement(By.XPath(xpathOfElement));
var isSucceededed = element != null;
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
xpath 在 HTML DOM 中定位 gif 的位置。 之后,您还可以实现您的操作方法 Click。
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
In my case , I used the following to know the page load status. In our application loading gif(s) are present and, I listen to them as follows to eliminate unwanted wait time in the script.
public static void processing(){
WebDriverWait wait = new WebDriverWait(driver, 30);
wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
wait.until(ExpectedConditions.invisibilityOfElementLocated(By.xpath("//div[@id='Msgpanel']/div/div/img")));
}
Where the xpath locates the gif in the HTML DOM. After this, You may also implement your action methods Click.
public static void click(WebElement elementToBeClicked){
WebDriverWait wait = new WebDriverWait(driver, 45);
wait.until(ExpectedConditions.visibilityOf(element));
wait.until(ExpectedConditions.elementToBeClickable(element));
wait.ignoring(NoSuchElementException.class).ignoring(StaleElementReferenceException.class); elementToBeClicked.click();
}
发布评论
评论(30)
您还可以使用以下代码检查页面加载情况
You can also check pageloaded using following code
使用类 WebDriverWait
另请参阅 此处
您可以期望显示一些元素。类似 C# 中的东西:
Use class WebDriverWait
Also see here
You can expect to show some element. something like in C#:
如果您设置驱动程序的隐式等待,然后对您期望在加载页面上的元素调用
findElement
方法,WebDriver 将轮询该元素,直到找到该元素或达到时间出值。来源: 隐式等待
If you set the implicit wait of the driver, then call the
findElement
method on an element you expect to be on the loaded page, the WebDriver will poll for that element until it finds the element or reaches the time out value.source: implicit-waits
一般来说,对于 Selenium 2.0,Web 驱动程序只有在确定页面已加载后才应将控制权返回给调用代码。如果没有,您可以调用
waitforelemement
,它会循环调用findelement
,直到找到或超时(可以设置超时)。In general, with Selenium 2.0 the web driver should only return control to the calling code once it has determined that the page has loaded. If it does not, you can call
waitforelemement
, which cycles round callingfindelement
until it is found or times out (time out can be set).红宝石实现:
Ruby implementation:
所有这些解决方案都适用于特定情况,但它们至少会遇到以下几个可能问题之一:
它们不够通用 - 它们希望您提前知道某些特定条件将是您将要访问的页面是否为真(例如,将显示某些元素)
它们对竞争条件开放,其中您使用了实际存在于旧页面和新页面上的元素。
这是我尝试的避免此问题的通用解决方案(在 Python 中):
首先,通用的“等待”函数(如果您愿意,可以使用 WebDriverWait,我发现它们很难看):
接下来,该解决方案依赖于 selenium 记录一个事实: (内部)页面上所有元素的 id 号,包括顶级
元素。当页面刷新或加载时,它会获得一个带有新 ID 的新 html 元素。
因此,假设您想单击带有文本“我的链接”的链接,例如:
对于更多 Pythonic、可重用、通用帮助器,您可以创建一个上下文管理器:
然后您可以在几乎任何硒交互中使用它:
我认为那是防弹的!你怎么认为?
更多信息请参见 关于它的博客文章在这里
All of these solutions are OK for specific cases, but they suffer from at least one of a couple of possible problems:
They are not generic enough -- they want you to know, ahead of time, that some specific condition will be true of the page you are going to (eg some element will be displayed)
They are open to a race condition where you use an element that is actually present on the old page as well as the new page.
Here's my attempt at a generic solution that avoids this problem (in Python):
First, a generic "wait" function (use a WebDriverWait if you like, I find them ugly):
Next, the solution relies on the fact that selenium records an (internal) id-number for all elements on a page, including the top-level
<html>
element. When a page refreshes or loads, it gets a new html element with a new ID.So, assuming you want to click on a link with text "my link" for example:
For more Pythonic, reusable, generic helper, you can make a context manager:
And then you can use it on pretty much any selenium interaction:
I reckon that's bulletproof! What do you think?
More info in a blog post about it here
您可以删除
System.out
行。添加它是为了调试目的。You may remove the
System.out
line. It is added for debug purposes.以下是当前得票最多的答案的 Java 8 版本:
其中
myDriver
是WebDriver
对象(之前声明)。注意:请注意,此方法 (
document.readyState
) 仅检查 DOM。Here is a Java 8 version of the currently most upvoted answer:
Where
myDriver
is aWebDriver
object (declared earlier).Note: Be aware that this method (
document.readyState
) only checks the DOM.您还可以使用类:
ExpectedConditions
显式等待元素显示在网页上,然后才能采取任何进一步操作您可以使用
ExpectedConditions
类来确定元素是否可见:请参阅
ExpectedConditions class Javadoc
以获取您可以检查的所有条件的列表。You can also use the class:
ExpectedConditions
to explicitly wait for an element to show up on the webpage before you can take any action further actionsYou can use the
ExpectedConditions
class to determine if an element is visible:See
ExpectedConditions class Javadoc
for list of all conditions you are able to check.Imran 的答案针对 Java 7 进行了重新整理:
Imran's answer rehashed for Java 7:
这似乎是 WebDriver 的一个严重限制。显然,等待元素并不意味着页面正在加载,特别是 DOM 可以完全构建(onready 状态),其中 JS 仍在执行,CSS 和图像仍在加载。
我相信最简单的解决方案是在一切都初始化后在 onload 事件上设置一个 JS 变量,并在 Selenium 中检查并等待这个 JS 变量。
This seems to be a serious limitation of WebDriver. Obviously waiting for an element will not imply the page being loaded, in particular the DOM can be fully build (onready state) whereby JS is still executing and CSS and images are still loading.
I believe the simplest solution is to set a JS variable upon the onload event after everything is initialized and check and wait for this JS variable in Selenium.
伙计,所有这些答案都需要太多代码。这应该是一件简单的事情,因为它很常见。
为什么不直接使用 webdriver 注入一些简单的 Javascript 并进行检查。
这是我在网络爬虫类中使用的方法。即使您不了解,Javascript 也非常基础。
更多信息请参见 MDN Web 文档的“Document.readyState”:https ://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
Man all these answers require too much code. This should be a simple thing as its pretty common.
Why not just inject some simple Javascript with the webdriver and check.
This is the method I use in my webscraper class. The Javascript is pretty basic even if you don't know it.
More Info in "Document.readyState" of MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
如果您想等待特定元素加载,可以在
RenderedWebElement
上使用isDisplayed()
方法:(示例来自 5 分钟入门指南)
If you want to wait for a specific element to load, you can use the
isDisplayed()
method on aRenderedWebElement
:(Example from The 5 Minute Getting Started Guide)
在此等待中显式等待或有条件等待,直到给定此条件。
这将等待每个 Web 元素 60 秒。
使用隐式等待等待页面上的每个元素直到给定时间。
这将等待每个 Web 元素 60 秒。
Explicitly wait or conditional wait in this wait until given this condition.
This will wait for every web element for 60 seconds.
Use implicitly wait for wait of every element on page till that given time.
This will wait for every web element for 60 seconds.
令我惊讶的是,谓词并不是首选,因为您通常知道接下来将在等待加载的页面上与哪些元素进行交互。我的方法一直是构建诸如
waitForElementByID(String id)
和waitForElemetVisibleByClass(String className)
等谓词/函数,然后在需要的地方使用和重用它们,无论是页面加载还是页面内容更改,我都在等待。例如,
在我的测试类中:
在我的测试类父类中:
虽然这看起来很多,但它会为您重复检查
并且检查频率的间隔可以与最终值一起设置
超时之前等待时间。此外,您还将重用此类方法。
在此示例中,父类定义并启动了
WebDriver 驱动程序
和WebDriverWait driverWait
。我希望这有帮助。
I'm surprised that predicates weren't the first choice as you typically know what element(s) you will next interact with on the page you're waiting to load. My approach has always been to build out predicates/functions like
waitForElementByID(String id)
andwaitForElemetVisibleByClass(String className)
, etc. and then use and reuse these wherever I need them, be it for a page load or page content change I'm waiting on.For example,
In my test class:
In my test class parent:
Though this seems like a lot, it takes care of checking repeatedly for you
and the interval for how often to check can be set along with the ultimate
wait time before timing out. Also, you will reuse such methods.
In this example, the parent class defined and initiated the
WebDriver driver
and theWebDriverWait driverWait
.I hope this helps.
使用隐式等待等待页面上的每个元素直到给定时间。
这会等待页面上的每个元素 30 秒。
另一种等待是显式等待或条件等待,这种等待直到给定条件。
在 id 中给出静态元素 id,一旦页面加载,它就会在页面上显示。
Use implicitly wait for wait of every element on page till given time.
this wait for every element on page for 30 sec.
Another wait is Explicitly wait or conditional wait in this wait until given condition.
In id give static element id which is diffidently display on the page, as soon as page is load.
使用 WebDriver 的 Java 绑定时等待页面加载的最佳方法是将页面对象设计模式与 PageFactory 结合使用。这允许您利用 AjaxElementLocatorFactory ,简单来说,它充当所有元素的全局等待。它对下拉框或复杂的 JavaScript 转换等元素有限制,但它将大大减少所需的代码量并加快测试时间。这篇博文中有一个很好的例子。假定您对 Core Java 有基本的了解。
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait -in-page-factory.html
The best way to wait for page loads when using the Java bindings for WebDriver is to use the Page Object design pattern with PageFactory. This allows you to utilize the
AjaxElementLocatorFactory
which to put it simply acts as a global wait for all of your elements. It has limitations on elements such as drop-boxes or complex javascript transitions but it will drastically reduce the amount of code needed and speed up test times. A good example can be found in this blogpost. Basic understanding of Core Java is assumed.http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
在脚本中调用下面的函数,这将等到页面未使用 javascript 加载
Call below Function in your script , this will wait till page is not loaded using javascript
NodeJS解决方案:
在Nodejs中,你可以通过promise来获取它...
如果你编写这段代码,你可以确保当你到达then时页面已完全加载...
如果您编写此代码,您将进行导航,selenium 将等待 3 秒...
从 Selenium 文档 (Nodejs):
NodeJS Solution:
In Nodejs you can get it via promises...
If you write this code, you can be sure that the page is fully loaded when you get to the then...
If you write this code, you will navigate, and selenium will wait 3 seconds...
From Selenium Documentation (Nodejs):
您可以使用以下现有方法来设置
pageLoadTimeout
。在下面的示例中,如果页面加载时间超过 20 秒,则会抛出页面重新加载异常:You can use the below existing method to set the
pageLoadTimeout
. In below example if the page is taking more than 20 seconds to load, then it will throw an exception of page reload:在仅更改文档的一部分的情况下,您可以从文档更改为元素。
这项技术的灵感来自于sincebasic的答案。
You can change from the document to an element, in the case of where only part of a document is being changed.
This technique was inspired by the answer from sincebasic.
SeleniumWaiter:
您使用它:
SeleniumWaiter:
And to you use it:
您可以显式等待元素显示在网页上,然后才能执行任何操作(例如
element.click()
):这是我在类似场景中使用的方法,效果很好。
You can explicitly wait for an element to show up on the webpage before you can take any action (like
element.click()
):This is what I used for a similar scenario and it works fine.
我的简单方法:
My simple way:
您可以使用这段代码来加载页面:
或者您可以使用 waiter 来加载任何元素,并在该页面上变得可见/可点击,很可能会在加载结束时加载,例如:
You can use this snippet of code for the page to load:
Or you can use waiter for any element to be loaded and become visible/clickable on that page, most probably which is going to be load at the end of loading like:
我见过的最好的方法是利用
stalenessOf
ExpectedCondition,等待旧页面变得过时。示例:
它将等待十秒钟,让旧的 HTML 标记变得过时,如果没有发生,则抛出异常。
The best way I've seen is to utilize the
stalenessOf
ExpectedCondition, to wait for the old page to become stale.Example:
It'll wait for ten seconds for the old HTML tag to become stale, and then throw an exception if it doesn't happen.
我使用node + selenium-webdriver(现在版本是3.5.0)。我为此所做的是:
I use node + selenium-webdriver(which version is 3.5.0 now). what I do for this is:
您可以使用等待。 selenium 中基本上有 2 种类型的等待
- 隐式等待
这非常简单,请参阅下面的语法:
- 显式等待
在这种等待中显式等待或条件等待直到给定的条件发生。
您可以使用其他属性,例如
visbityOf()
、visbityOfElement()
You can use wait. there are basically 2 types of wait in selenium
- Implicit wait
This is very simple please see syntax below:
- Explicit wait
Explicitly wait or conditional wait in this wait until given condition is occurred.
You can use other properties like
visblityOf()
,visblityOfElement()
如果有人使用硒化物:
可以在此处找到更多条件:
http://selenide.org/javadoc/3.0/com/codeborne/硒化物/Condition.html
If someone uses selenide:
More Conditions can be found here:
http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html
就我而言,我使用以下方法来了解页面加载状态。在我们的应用程序中,存在加载 gif,我按如下方式收听它们,以消除脚本中不必要的等待时间。
xpath 在 HTML DOM 中定位 gif 的位置。
之后,您还可以实现您的操作方法 Click。
In my case , I used the following to know the page load status. In our application loading gif(s) are present and, I listen to them as follows to eliminate unwanted wait time in the script.
Where the xpath locates the gif in the HTML DOM.
After this, You may also implement your action methods Click.