在Selenium中等待页面加载

你如何让Selenium 2.0等待页面加载?

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

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")); 

使用类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将轮询该元素,直到find该元素或达到超时值。

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

来源: 隐式等待

一般来说,在Selenium 2.0中,Web驱动程序一旦确定页面已经加载,就应该只对调用代码返回控制权。 如果没有,可以调用waitforelemement ,循环调用findelement直到find或超时(可以设置超时)。

Ruby实现:

 wait = Selenium::WebDriver::Wait.new(:timeout => 10) wait.until { @driver.execute_script("return document.readyState;") == "complete" } 

您可以删除System.out行。 它被添加用于debugging目的。

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

您还可以使用ExpectedConditions类来显式等待网页上显示的元素,然后才能采取进一步操作

您可以使用ExpectedConditions类来确定元素是否可见:

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

请参阅ExpectedConditions class Javadoc以获取您能够检查的所有条件的列表。

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

我相信最简单的解决scheme是在一切都初始化之后,在onload事件上设置一个JSvariables,并在Selenium中检查并等待这个JSvariables。

所有这些解决scheme都适用于特定情况,但是它们至less会遇到以下几种可能的问题之一:

  1. 它们不够通用 – 他们希望你提前知道你要访问的页面的某些特定条件(例如,某些元素将被显示)

  2. 他们开放的竞争条件,你使用的是旧页面上实际存在的元素,以及新的页面。

这里是我的一个通用解决scheme的尝试,以避免这个问题(在Python中):

首先,一个通用的“等待”function(如果你喜欢,使用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__)) 

接下来,解决scheme依赖于selenium为页面上的所有元素(包括顶级<html>元素)logging(内部)id号。 当一个页面刷新或加载,它会得到一个新的ID与一个新的HTML元素。

所以,假设你想点击一个链接文本“我的链接”,例如:

 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) 

对于更多Pythonic,可重用的generics助手,可以创build一个上下文pipe理器:

 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) 

然后你可以在几乎所有的selenium交互中使用它:

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

我认为这是防弹的! 你怎么看?

更多的信息在这里的博客文章

如果您想等待加载特定元素,则可以在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分钟入门指南中的示例)

伊姆兰的答案重新为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"); } }); 

令我惊讶的是谓词并不是第一select,因为您通常知道接下来将在您等待加载的页面上与哪些元素进行交互。 我的方法一直是build立像waitForElementByID(String id)waitForElemetVisibleByClass(String className)等谓词/函数,然后使用和重用这些无论我需要他们,无论是页面加载或页面内容更改我等待。

例如,

在我的testing课上:

 driverWait.until(textIsPresent("expectedText"); 

在我的testingclass的父母:

 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 driverWebDriver driver等。

我希望这有帮助。

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

 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。

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

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

这个技巧受到了基本的答案的启发。

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 } 

你可以明确地等待一个元素出现在网页上,然后你可以采取任何行动(比如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")); }}); 

这是我用于类似的情况,它工作正常。

我简单的方法:

 long timeOut = 5000; long end = System.currentTimeMillis() + timeOut; while (System.currentTimeMillis() < end) { if (String.valueOf( ((JavascriptExecutor) driver) .executeScript("return document.readyState")) .equals("complete")) { break; } } 

使用WebDriver的Java绑定时,等待页面加载的最佳方式是使用PageFactory的Page Objectdevise模式。 这使您可以利用AjaxElementLocatorFactory来简单地作为全局等待所有元素。 它对投递箱或复杂的JavaScript转换等元素有限制,但会大大减less所需的代码量,加快testing时间。 在这篇博文中可以find一个很好的例子。 对Java核心的基本理解是假定的。

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

NodeJS解决scheme:

Nodejs中,你可以通过promise来获得它…

如果你写这个代码,你可以确保页面完全加载,当你到…

 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文档:

this.get(url)→Thenable

安排命令导航到给定的URL。

返回在文档加载完成后将parsing的承诺。

selenium文档(Nodejs)

您可以使用下面的现有方法来设置pageeLoadTimeout的时间,如下所示,如果页面加载时间超过20秒,则会抛出页面重新加载的exception

  WebDriver driver = new FirefoxDriver(); driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS) 

在这个等待或有条件的等待,直到给定的条件。

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

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

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

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

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

两者都很好。 但我个人最喜欢的是明确的等待,因为它比较稳定

你可以使用等待。 selenium基本上有两种types

  • 隐含的等待
  • 明确的等待

– 隐含的等待

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

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

– 明确的等待

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

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

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

 driver.asserts().assertElementFound("Page was not loaded", By.xpath("//div[@id='actionsContainer']"),Constants.LOOKUP_TIMEOUT); 

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

如果你想在页面加载后点击某个button,可以使用await并点击:

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

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

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

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

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

你可以尝试这个代码让页面加载完全,直到find元素。

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

或者,您可以使用服务器来加载任何元素,并在该页面上可见/可点击,最有可能在加载结束时加载,如:

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

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

例:

 WebDriver driver = new FirefoxDriver(); WebDriverWait wait = new WebDriverWait(driver, 10); WebElement oldHtml = driver.findElement(By.tagName("html")); wait.until(ExpectedConditions.stalenessOf(oldHtml)); 

它会等待十秒钟,旧的HTML标记变为陈旧,然后抛出一个exception,如果没有发生。