Answers:
您还可以使用以下代码检查页面加载
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"));
也请看这里
您可以期望显示一些元素。类似于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);
来源:隐式等待
通常,对于Selenium 2.0,Web驱动程序仅在确定页面已加载后才应将控制权返回给调用代码。如果没有,您可以调用waitforelemement
,它会循环调用findelement
直到找到它或超时(可以设置超时)。
If click() causes a new page to be loaded via an event or is done by sending a native event (which is a common case on Firefox, IE on Windows) then the method will not wait for it to be loaded and the caller should verify that a new page has been loaded.
JavascriptExecutor
,等待document.readyState“完成”。由于从硒到浏览器的往返行程,我猜想缓解了竞争条件,并且这种“始终”对我有效。当我希望加载页面时,在“ click()”之后,我明确地(使用WebDriverWait)等待ready状态。]
Ruby实现:
wait = Selenium::WebDriver::Wait.new(:timeout => 10)
wait.until {
@driver.execute_script("return document.readyState;") == "complete"
}
您可以删除该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");
}
});
}
所有这些解决方案都可以在特定情况下使用,但是它们至少会遇到以下两种可能的问题之一:
它们不够通用-他们希望您提前知道要进入的页面符合某些特定条件(例如,将显示某些元素)
它们会在竞争条件下开放,您可以使用旧页面和新页面上实际存在的元素。
这是我为避免这种问题的通用解决方案所做的尝试(在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__))
接下来,解决方案依赖于硒记录页面上所有元素(包括顶层元素)的(内部)ID号这一事实<html>
。页面刷新或加载时,它将获得带有新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,可重用的通用帮助器,您可以创建一个上下文管理器:
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()
我认为那是防弹的!你怎么看?
您还可以使用class:ExpectedConditions
明确地等待某个元素显示在网页上,然后再执行任何操作
您可以使用ExpectedConditions
该类来确定元素是否可见:
WebElement element = (new WebDriverWait(getDriver(), 10)).until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("input#houseName")));
请参阅ExpectedConditions class Javadoc
以获取您可以检查的所有条件的列表。
这似乎是WebDriver的严重限制。显然,等待元素并不意味着正在加载页面,特别是可以完全构建DOM(就绪状态),从而JS仍在执行,CSS和图像仍在加载。
我相信最简单的解决方案是在初始化所有内容后在onload事件上设置JS变量,然后在Selenium中检查并等待此JS变量。
如果要等待特定元素加载,可以在isDisplayed()
上使用方法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;
}
}
(“ 5分钟入门指南”中的示例)
RenderedWebElement
API中没有任何内容。但是,isDisplayed()
方法现在可以直接在上使用WebElement
。
在此等待中显式等待或条件等待,直到给出此条件。
WebDriverWait wait = new WebDriverWait(wb, 60);
wait.until(ExpectedConditions.elementToBeClickable(By.name("value")));
这将等待每个Web元素60秒钟。
使用隐式等待页面上每个元素的等待直到给定的时间。
driver.manage().timeouts().implicitlyWait(60, TimeUnit.SECONDS);
这将等待每个Web元素60秒钟。
使用隐式等待页面上每个元素的等待直到给定的时间。
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,该ID在页面加载后立即显示在页面上。
令您惊讶的是谓词并不是首选,因为您通常会知道接下来要与之交互的元素将在等待加载的页面上进行。我的做法一直是打造出来的谓词/像功能waitForElementByID(String id)
和waitForElemetVisibleByClass(String className)
,等等,然后在需要的地方使用和重用这些,无论是等待页面加载还是页面内容更改。
例如,
在我的测试课中:
driverWait.until(textIsPresent("expectedText");
在我的测试班级家长中:
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 driver
和WebDriverWait driverWait
。
我希望这有帮助。
使用WebDriver的Java绑定时,等待页面加载的最佳方法是将Page Object设计模式与PageFactory一起使用。这样,您就可以利用AjaxElementLocatorFactory
将其简单地用作全局等待所有元素的方式。它对诸如保管箱或复杂的javascript转换之类的元素有限制,但是它将大大减少所需的代码量并加快测试时间。可以在此博客文章中找到一个很好的例子。假定您对Core Java有基本的了解。
http://startingwithseleniumwebdriver.blogspot.ro/2015/02/wait-in-page-factory.html
NodeJS解决方案:
在Nodejs中,您可以通过promises获得它。
如果您编写此代码,则可以确定到页面时页面已完全加载。
driver.get('www.sidanmor.com').then(()=> {
// here the page is fully loaded!!!
// do your stuff...
}).catch(console.log.bind(console));
如果您编写此代码,则将进行导航,硒将等待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...
从硒文档:
this.get(URL)→可以
调度命令以导航到给定的URL。
返回将在文档完成加载后解决的Promise。
在脚本中的Function下面调用,它将等到未使用javascript加载页面时
public static boolean isloadComplete(WebDriver driver)
{
return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded")
|| ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
}
/**
* 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
}
您可以使用下面的现有方法在以下示例中设置pageeLoadTimeout的时间,如果页面加载时间超过20秒,则它将抛出页面重新加载异常
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
您可以明确地等待某个元素显示在网页上,然后再执行任何操作(例如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"));
}});
这是我在类似情况下使用的,并且工作正常。
我见过的最好的方法是利用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标签过时,然后如果未发生,则引发异常。
您可以使用等待。硒中基本上有两种等待类型
-隐式等待
这很简单,请参见下面的语法:
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
-明确等待
在此等待中显式等待或条件等待,直到发生给定条件。
WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));
您可以使用其他属性,如visblityOf()
,visblityOfElement()
如果有人使用硒化物:
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
就我而言,我使用以下信息来了解页面加载状态。在我们的应用程序中,存在正在加载的gif,我按照以下方式进行监听,以消除脚本中不必要的等待时间。
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();
}
男人所有这些答案都需要太多的代码。这应该很简单,因为它很常见。
为什么不只是使用Webdriver注入一些简单的javascript并进行检查。这是我在webscraper类中使用的方法。即使您不懂js,JavaScript还是很基本的。
def js_get_page_state(self):
"""
Javascript for getting document.readyState
:return: Pages state.
More Info: https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState
"""
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
单击后如何使Selenium等待页面加载提供了以下有趣的方法:
WebElement
对旧页面中a的引用。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;
}
});
new WebDriverWait(driver, 10).until(ExpectedConditions.stalenessOf(element))
。