在Selenium中等待页面加载

如何让 2.0等待页面加载?

586126 次浏览

一般来说,使用Selenium 2.0时,web驱动程序应该只在确定页面已加载后才将控制权返回给调用代码。如果没有,你可以调用waitforelemement,它会循环调用findelement,直到找到它或超时(超时可以设置)。

如果你想等待一个特定的元素加载,你可以在RenderedWebElement上使用isDisplayed()方法:

// 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;
}
}

(例子来自5分钟入门指南)

使用类WebDriverWait

也可参见在这里

您可以期望显示一些元素。类似于c#:

WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));


_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement")));

如果你设置了驱动程序的隐式等待,然后在你期望加载页面上的元素上调用findElement方法,WebDriver将轮询该元素,直到找到该元素或达到超时值。

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

来源:implicit-waits

你可以显式地等待一个元素出现在网页上,然后才能采取任何操作(如element.click()):

driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
.until(new ExpectedCondition<WebElement>() {
@Override
public WebElement apply(WebDriver d) {
return d.findElement(By.id("myDynamicElement"));
}
}
);

这是我用于类似场景的方法,效果很好。

你也可以使用类:ExpectedConditions来显式地等待一个元素出现在网页上,然后你才能采取任何行动

你可以使用ExpectedConditions类来确定一个元素是否可见:

WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));

查看ExpectedConditions class Javadoc中所有你可以检查的条件列表。

这似乎是WebDriver的一个严重限制。显然,等待一个元素并不意味着页面正在加载,特别是DOM可以完全构建(onready状态),此时JS仍在执行,CSS和图像仍在加载。

我相信最简单的解决方案是在onload事件上设置一个JS变量,在所有东西初始化后,在Selenium中检查和等待这个JS变量。

您还可以使用以下代码检查页面加载

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));


wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

SeleniumWaiter:

import com.google.common.base.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;


public class SeleniumWaiter {


private WebDriver driver;


public SeleniumWaiter(WebDriver driver) {
this.driver = driver;
}


public WebElement waitForMe(By locatorname, int timeout){
WebDriverWait wait = new WebDriverWait(driver, timeout);
return wait.until(SeleniumWaiter.presenceOfElementLocated(locatorname));
}


public static Function<WebDriver, WebElement> presenceOfElementLocated(final By locator) {
// TODO Auto-generated method stub
return new Function<WebDriver, WebElement>() {
@Override
public WebElement apply(WebDriver driver) {
return driver.findElement(locator);
}
};
}
}

和你使用它:

_waiter = new SeleniumWaiter(_driver);


try {
_waiter.waitForMe(By.xpath("//..."), 10);
}
catch (Exception e) {
// Error
}

Ruby实现:

wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
driver.asserts().assertElementFound("Page was not loaded",
By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT);
/**
* Call this method before an event that will change the page.
*/
private void beforePageLoad() {
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("document.mpPageReloaded='notYet';");
}


/**
* Call this method after an event that will change the page.
*
* @see #beforePageLoad
*
*      Waits for the previous page to disappear.
*/
private void afterPageLoad() throws Exception {
(new WebDriverWait(driver, 10)).until(new Predicate<WebDriver>() {


@Override
public boolean apply(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;
Object obj = js.executeScript("return document.mpPageReloaded;");
if (obj == null) {
return true;
}
String str = (String) obj;
if (!str.equals("notYet")) {
return true;
}
return false;
}
});
}

在只更改部分文档的情况下,您可以从文档更改为元素。

这个技巧的灵感来自于sincebasic的答案。

我很惊讶,谓词不是首选,因为您通常知道您将在等待加载的页面上与哪些元素进行下一步交互。我的方法一直是构建像waitForElementByID(String id)waitForElemetVisibleByClass(String className)这样的谓词/函数,然后在我需要它们的地方使用和重用它们,无论是我正在等待的页面加载还是页面内容更改。

例如,

在我的测试类中:

driverWait.until(textIsPresent("expectedText");

在我的测试类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);
}
虽然这看起来很多,但它会为你反复检查 检查频率的间隔可以和最终值一起设置 在计时之前等待一段时间。此外,您还将重用这些方法

在本例中,父类定义并初始化了WebDriver driverWebDriverWait driverWait

我希望这能有所帮助。

你可以删除System.out行。添加它是为了调试目的。

WebDriver driver_;


public void waitForPageLoad() {


Wait<WebDriver> wait = new WebDriverWait(driver_, 30);
wait.until(new Function<WebDriver, Boolean>() {
public Boolean apply(WebDriver driver) {
System.out.println("Current Window State       : "
+ String.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState")));
return String
.valueOf(((JavascriptExecutor) driver).executeScript("return document.readyState"))
.equals("complete");
}
});
}

所有这些解决方案在特定情况下都是可行的,但它们至少会遇到以下几个问题中的一个:

  1. 它们不够通用——它们想让你提前知道,你要访问的页面的某些特定条件将是真的(例如某些元素将被显示)。

  2. 它们会出现竞态条件,即您使用的元素实际上同时出现在旧页面和新页面上。

下面是我尝试的避免这个问题的通用解决方案(在Python中):

首先,一个通用的“等待”函数(如果你喜欢,可以使用WebDriverWait,我觉得它们很丑):

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__))

接下来,解决方案依赖于这样一个事实,即selenium为页面上的所有元素记录了一个(内部的)id-number,包括顶级的<html>元素。当页面刷新或加载时,它会获得一个带有新ID的新html元素。

假设你想点击一个文本为“my link”的链接,例如:

old_page = browser.find_element_by_tag_name('html')


browser.find_element_by_link_text('my link').click()


def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id


wait_for(page_has_loaded)

对于更多python化的、可重用的、通用的helper,你可以创建一个上下文管理器:

from contextlib import contextmanager


@contextmanager
def wait_for_page_load(browser):
old_page = browser.find_element_by_tag_name('html')


yield


def page_has_loaded():
new_page = browser.find_element_by_tag_name('html')
return new_page.id != old_page.id


wait_for(page_has_loaded)

然后你可以在几乎任何硒相互作用中使用它:

with wait_for_page_load(browser):
browser.find_element_by_link_text('my link').click()

我想那是防弹的!你怎么看?

关于它的博客文章在这里中的更多信息

如何让硒等待页面加载后点击提供了以下有趣的方法:

  1. 存储旧页中WebElement的引用。
  2. 点击链接。
  3. 继续调用WebElement上的操作,直到StaleElementReferenceException被抛出。

示例代码:

WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
try
{
link.isDisplayed();
return false;
}
catch (StaleElementReferenceException unused)
{
return true;
}
});

使用:

driver.manage().timeOuts().implicitlyWait(10, TimeUnit.SECONDS);
这意味着任何搜索网页上的元素都需要时间来加载。implicitlyWait在抛出异常之前设置。 TimeUnit显示你想要等待的任何方式(秒、分、小时和天)

我的方法很简单:

long timeOut = 5000;
long end = System.currentTimeMillis() + timeOut;


while (System.currentTimeMillis() < end) {


if (String.valueOf(
((JavascriptExecutor) driver)
.executeScript("return document.readyState"))
.equals("complete")) {
break;
}
}

我不认为含蓄的等待是你想要的。试试这个:

driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);

更多信息在文档

最简单的方法就是等待一些元素出现在加载的页面上

如果你想在页面加载后点击一些按钮,你可以使用等待,然后点击:

await().until().at.most(20, TimeUnit.Seconds).some_element.isDisplayed(); // or another condition
getDriver().find(some_element).click;

Imran对Java 7的回答是:

    WebDriverWait wait = new WebDriverWait(driver, 30);


wait.until(new ExpectedCondition<Boolean>() {
public Boolean apply(WebDriver wdriver) {
return ((JavascriptExecutor) driver).executeScript(
"return document.readyState"
).equals("complete");
}
});

隐式和显式的等待更好。

但是如果你在Java中处理一个异常,那么你可以使用这个来等待页面重新加载:

Thead.sleep(1000);

使用这个函数

public void waitForPageLoad(ChromeDriver d){
String s="";
while(!s.equals("complete")){
s=(String) d.executeScript("return document.readyState");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}


}

当为WebDriver使用Java绑定时,等待页面加载的最佳方法是使用PageFactory的page Object设计模式。这允许你利用AjaxElementLocatorFactory,简单地说,它只是作为你所有元素的全局等待。它对诸如下拉框或复杂javascript转换等元素有限制,但它将大大减少所需的代码量,并加快测试时间。在这篇博文中可以找到一个很好的例子。假定您对Core Java有基本的了解。

http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html

使用隐式等待等待页面上的每个元素直到给定的时间。

driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);

这将等待页面上的每个元素30秒。

另一种等待是显式等待或有条件等待,在这个等待直到给定条件。

WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

在id中,给出静态元素id,一旦页面加载,它就会不小心显示在页面上。

  1. WebDriver driver = new ff / chrome / anyDriverYouWish(); .timeouts driver.manage()()。implicitlyWait(10、TimeUnit.SECONDS); > < /代码

  2. .最长等待10秒
  3. WebDriverWait wait = new WebDriverWait(driver, 10); wait.until (ExpectedConditions。visibilityOf (WebElement元素));< /代码> < / p > < /李> <李> < p > <代码> FluentWait< Driver>fluentWait; fluentWait = new fluentWait <>(驱动程序)。TimeUnit.SECONDS withTimeout(30日) TimeUnit.MILLISECONDS .pollingEvery (200) . ignore (NoSuchElementException.class); < /代码> < / p > < /李>

最后一个选项的优点是可以包含预期的异常,以便继续执行。

对于存在的任何元素使用if条件和

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

对于隐式等待,你可以使用如下代码:

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS)

为了使网页等待一个特定的对象是可见的或某些条件是真实的。您可以使用网页驱动程序等羽。

//120 is maximum number of seconds to wait.
WebDriverWait wait = new WebDriverWait(driver,120);
wait.until(ExpectedConditions.elementToBeClickable("CONDITITON"));

Java中,另一个选项是让线程在特定的时间内休眠。

Thread.sleep(numberOfSeconds*1000);
//This line will cause thread to sleep for seconds as variable

我创建了一个方法来简化线程。睡眠的方法

public static void wait_time(int seconds){
try {
Thread.sleep(seconds*1000);
}catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

使用wait_time(10)方法;线程将休眠10秒。

在Webdriver/Selenium 2软件测试工具中有两种类型的等待。一种是隐式等待,另一种是显式等待。两者(隐式等待和显式等待)在WebDriver中都很有用。使用等待,我们告诉WebDriver在进入下一步之前等待一定的时间。可以使用隐式等待来等待页面加载。

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

您可以尝试这段代码,让页面完全加载,直到找到元素为止。

public void waitForBrowserToLoadCompletely() {
String state = null;
String oldstate = null;
try {
System.out.print("Waiting for browser loading to complete");


int i = 0;
while (i < 5) {
Thread.sleep(1000);
state = ((JavascriptExecutor) driver).executeScript("return document.readyState;").toString();
System.out.print("." + Character.toUpperCase(state.charAt(0)) + ".");
if (state.equals("interactive") || state.equals("loading"))
break;
/*
* If browser in 'complete' state since last X seconds. Return.
*/


if (i == 1 && state.equals("complete")) {
System.out.println();
return;
}
i++;
}
i = 0;
oldstate = null;
Thread.sleep(2000);


/*
* Now wait for state to become complete
*/
while (true) {
state = ((JavascriptExecutor) driver).executeScript("return document.readyState;").toString();
System.out.print("." + state.charAt(0) + ".");
if (state.equals("complete"))
break;


if (state.equals(oldstate))
i++;
else
i = 0;
/*
* If browser state is same (loading/interactive) since last 60
* secs. Refresh the page.
*/
if (i == 15 && state.equals("loading")) {
System.out.println("\nBrowser in " + state + " state since last 60 secs. So refreshing browser.");
driver.navigate().refresh();
System.out.print("Waiting for browser loading to complete");
i = 0;
} else if (i == 6 && state.equals("interactive")) {
System.out.println(
"\nBrowser in " + state + " state since last 30 secs. So starting with execution.");
return;
}


Thread.sleep(4000);
oldstate = state;


}
System.out.println();


} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
private static void checkPageIsReady(WebDriver driver) {
JavascriptExecutor js = (JavascriptExecutor) driver;


// Initially bellow given if condition will check ready state of page.
if (js.executeScript("return document.readyState").toString().equals("complete")) {
System.out.println("Page Is loaded.");
return;
}


// This loop will rotate for 25 times to check If page Is ready after
// every 1 second.
// You can replace your value with 25 If you wants to Increase or
// decrease wait time.
for (int i = 0; i < 25; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
// To check page ready state.
if (js.executeScript("return document.readyState").toString().equals("complete")) {
break;
}
}
}

你可以使用下面的代码片段来加载页面:

    IWait wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver,TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));

或者你可以使用waiter的任何元素被加载,并成为可见/可点击的页面上,最有可能的是,这将是在加载结束时加载,如:

    Wait.Until(ExpectedConditions.ElementToBeClickable(By.XPath(xpathOfElement));
var element = GlobalDriver.FindElement(By.XPath(xpathOfElement));
var isSucceededed = element != null;

我所见过的最好的方法是利用stalenessOf ExpectedCondition,等待旧页面变得陈旧。

例子:

WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);


WebElement oldHtml = driver.findElement(By.tagName("html"));
wait.until(ExpectedConditions.stalenessOf(oldHtml));

它将等待十秒钟,让旧的HTML标记变得陈旧,如果没有发生,则抛出异常。

NodeJS解决方案:

Nodejs中,你可以通过承诺得到它…

如果您编写了这段代码,您可以确保当您到达then…

driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));

如果您编写了这段代码,您将进行导航,selenium将等待3秒……

driver.get('www.sidanmor.com');
driver.sleep(3000);
// you can't be sure that the page is fully loaded!!!
// do your stuff... hope it will be OK...

Selenium文档(Nodejs):

this.get( url ) → Thenable<undefined>

调度命令导航到给定的URL。

返回一个承诺,该承诺将在文档具有完成加载时得到解决。

使用下面的代码,它是非常容易和简单的页面加载。

public void PageLoad(IWebDriver driver, By by)
{
try
{
Console.WriteLine("PageLoad" + by);
WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30));
wait.Until(ExpectedConditions.ElementIsVisible(by));
wait = new WebDriverWait(driver, TimeSpan.FromSeconds(30)); // 30 seconds wait until element not found.
wait.Until(ExpectedConditions.ElementToBeClickable(by));




}
catch (Exception ex)
{


Console.WriteLine(ex.Message);
Assert.Fail("Element not found!")
}
}

我希望这对你有所帮助。

你可以使用下面现有的方法来设置pageLoadTimeout。在下面的例子中,如果页面加载时间超过20秒,那么它将抛出一个页面重新加载异常:

WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS);
public static int counter = 0;


public void stepGeneralWait() {


boolean breakIt = true;


while (true) {
breakIt = true;
try {


do{
// here put e.g. your spinner ID
Controller.driver.findElement(By.xpath("//*[@id='static']/div[8]/img")).click();
Thread.sleep(10000);


counter++;


if (counter > 3){
breakIt = false;


}
}
while (breakIt);






} catch (Exception e) {
if (e.getMessage().contains("element is not attached")) {
breakIt = false;
}
}
if (breakIt) {
break;
}


}


try {
Thread.sleep(12000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}


}

显式等待或条件等待,直到给定这个条件。

WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));

这将等待每个web元素60秒。

使用隐式等待等待页面上的每个元素直到给定的时间。

driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);

这将等待每个web元素60秒。

这段代码将等待页面上的所有元素都加载到DOM中。

WebDriver driver = new WebDriver();
WebDriverWait wait = new WebDriverWait(driver, timeout);


wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*")));

在python中,你可以简单地使用:

driver.implicitly_wait(30)

我使用node + selenium-webdriver(现在的版本是3.5.0)。我所做的是:

var webdriver = require('selenium-webdriver'),
driver = new webdriver.Builder().forBrowser('chrome').build();
;
driver.wait(driver.executeScript("return document.readyState").then(state => {
return state === 'complete';
}))

你可以使用等待。硒中基本上有两种类型的等待

  • 隐式等
  • 显式等

-隐式等待

这很简单,请参阅下面的语法:

driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);

-显式等待

在此等待中显式等待或有条件等待,直到给定条件发生。

WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

你可以使用其他属性,如visblityOf()visblityOfElement()

在脚本中调用下面的函数,这将等待页面未使用javascript加载

public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}

如果有人使用硒化物:

public static final Long SHORT_WAIT = 5000L; // 5 seconds
$("some_css_selector").waitUntil(Condition.appear, SHORT_WAIT);

更多条件可以在这里找到: http://selenide.org/javadoc/3.0/com/codeborne/selenide/Condition.html < / p >

在我的例子中,我使用以下方法来了解页面加载状态。在我们的应用程序加载gif(s)是存在的,我听他们如下,以消除不必要的等待时间在脚本。

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的位置。 之后,您还可以实现您的动作方法单击。

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();
}

下面是当前点赞最多的答案的Java 8版本:

WebDriverWait wait = new WebDriverWait(myDriver, Duration.ofSeconds(15));
wait.until(webDriver -> "complete".equals(((JavascriptExecutor) webDriver)
.executeScript("return document.readyState")));
    

其中myDriver是一个WebDriver对象(前面声明过)。

请注意:注意这个方法(document.readyState)只检查DOM。

伙计,所有这些答案都需要太多代码。这应该是一个简单的事情,因为它很常见。

为什么不注入一些简单的Javascript与webdriver和检查。 这就是我在webscraper课上使用的方法。Javascript是相当基本的,即使你不知道它
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

更多信息见“;Document.readyState"MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState

对于使用java 8向前的程序员,可以使用下面的代码来使用显式等待等待页面加载。

JavascriptExecutor js = (JavascriptExecutor) driver;
new WebDriverWait(driver, 10).until(webDriver ->
(js).executeScript("return document.readyState;").equals("complete"));

注意:在我上面的代码中使用Lambda表达式,它只在java 8的后续版本中可用。

对于使用低版本Java(即Java 8以下)的程序员,可以使用:

ExpectedCondition<Boolean> cond = new ExpectedCondition<Boolean>() {
@Override
public Boolean apply(WebDriver input) {
JavascriptExecutor js = (JavascriptExecutor) driver;
return js.executeScript("return document.readyState;").equals("complete");
}
};
         

new WebDriverWait(driver, 100).until(cond);