Selenium等到文档准备就绪
任何人都可以让我如何使selenium等待页面加载完成的时间? 我想要一些通用的东西,我知道我可以configurationWebDriverWait并调用类似于“find”的方法来让它等待,但是我不会走得太远。 我只需要testing页面加载成功,并进入下一页testing。
我在.net中发现了一些东西,但无法使其在Java中工作…
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"));
任何想法的人?
试试这个代码:
driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
上面的代码将等待最多10秒的页面加载。 如果页面加载超过了它将抛出TimeoutException
的时间。 你抓住例外,并做你的需求。 我不确定在抛出的exception之后是否退出页面加载。 我没有尝试这个代码呢。 想要尝试一下。
这是一个隐含的等待。 如果您设置了这一次,它将具有范围,直到Web Driver实例被销毁。
欲了解更多信息。
您build议的解决scheme只等待DOM readyState
complete
信号。 但是,Selenium默认会尝试通过driver.get()
和element.click()
方法等待页面加载(以及更多)。 他们已经阻止,他们等待页面完全加载,这些应该工作正常。
显然,问题是通过AJAX请求和运行脚本进行redirect – Selenium无法捕获这些请求,并不等待它们完成。 另外,你不能通过readyState
可靠地捕捉它们 – 它会等readyState
,这可能是有用的,但是在所有的AJAX内容被下载之前,它会complete
很久的信号。
没有一个通用的解决scheme可以在任何地方和任何人工作,这就是为什么很难,每个人都使用一些有点不同的东西。
一般的规则是依靠WebDriver来完成他的任务,然后使用隐式等待,然后使用显式等待页面上要声明的元素,但是还有更多的技巧可以完成。 你应该select一个(或其中几个)的组合,在你的情况下,在你的testing页面上效果最好。
有关更多信息,请参阅我的两个答案:
- 我怎么能检查页面是否完全加载或不在networking驱动程序
- Selenium Webdriver:等待javascript加载的复杂页面
这是你给出的例子的Java版本:
void waitForLoad(WebDriver driver) { new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd -> ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete")); }
示例对于c#:
public static void WaitForLoad(this IWebDriver driver, int timeoutSec = 15) { WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec )); wait.Until(wd => wd.ExecuteScript("return document.readyState") == "complete"); }
以下是我在Python中完全通用的解决scheme的尝试:
首先,一个通用的“等待”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()
我认为这是防弹的! 你怎么看?
更多的信息在这里的博客文章
我有一个类似的问题。 我需要等到文档准备好之后,直到所有的Ajax调用完成。 第二个条件certificate是难以察觉的。 最后,我检查了活动的Ajax调用,它工作。
使用Javascript:
return (document.readyState == 'complete' && jQuery.active == 0)
完整的C#方法:
private void WaitUntilDocumentIsReady(TimeSpan timeout) { var javaScriptExecutor = WebDriver as IJavaScriptExecutor; var wait = new WebDriverWait(WebDriver, timeout); // Check if document is ready Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)"); wait.Until(readyCondition); }
WebDriverWait wait = new WebDriverWait(dr,30); wait.until(ExpectedConditions.jsReturnsValue(“return document.readyState == \”complete \“;”));
对于初始页面加载,我注意到“最大化”浏览器窗口实际上等待页面加载完成(包括来源)
更换:
AppDriver.Navigate().GoToUrl(url);
附:
public void OpenURL(IWebDriver AppDriver, string Url) { try { AppDriver.Navigate().GoToUrl(Url); AppDriver.Manage().Window.Maximize(); AppDriver.SwitchTo().ActiveElement(); } catch (Exception e) { Console.WriteLine("ERR: {0}; {1}", e.TargetSite, e.Message); throw; } }
比使用:
OpenURL(myDriver, myUrl);
这将加载页面,等到完成,最大化和专注于它。 我不知道为什么它是这样的,但它的工作原理。
如果你想在点击下一个或其他页面导航之后等待页面加载,然后触发其他的“导航()”,本代尔的答案(在这个线程中)将完成这项工作。
Ben Dryer的答案没有在我的机器上编译( "The method until(Predicate<WebDriver>) is ambiguous for the type WebDriverWait"
)。
工作Java 8版本:
Predicate<WebDriver> pageLoaded = wd -> ((JavascriptExecutor) wd).executeScript( "return document.readyState").equals("complete"); new FluentWait<WebDriver>(driver).until(pageLoaded);
Java 7版本:
Predicate<WebDriver> pageLoaded = new Predicate<WebDriver>() { @Override public boolean apply(WebDriver input) { return ((JavascriptExecutor) input).executeScript("return document.readyState").equals("complete"); } }; new FluentWait<WebDriver>(driver).until(pageLoaded);
在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)
对于C#NUnit,您需要将WebDriver转换为JSExecuter,然后执行该脚本来检查document.ready状态是否完整。 请查看以下代码以供参考:
public static void WaitForLoad(IWebDriver driver) { IJavaScriptExecutor js = (IJavaScriptExecutor)driver; int timeoutSec = 15; WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec)); wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete"); }
这将等待,直到条件满足或超时。
你可以写一些逻辑来处理这个问题。 我写了一个方法,将返回WebElement
,这个方法将被调用三次,或者你可以增加时间,并添加一个空的检查WebElement
这里是一个例子
public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.get("https://www.crowdanalytix.com/#home"); WebElement webElement = getWebElement(driver, "homekkkkkkkkkkkk"); int i = 1; while (webElement == null && i < 4) { webElement = getWebElement(driver, "homessssssssssss"); System.out.println("calling"); i++; } System.out.println(webElement.getTagName()); System.out.println("End"); driver.close(); } public static WebElement getWebElement(WebDriver driver, String id) { WebElement myDynamicElement = null; try { myDynamicElement = (new WebDriverWait(driver, 10)) .until(ExpectedConditions.presenceOfElementLocated(By .id(id))); return myDynamicElement; } catch (TimeoutException ex) { return null; } }
看看tapestry的 web框架。 你可以在那里下载源代码 。
这个想法是通过body的html属性指示页面已经准备好了。 你可以用这个想法忽略复杂的起诉案件。
<html> <head> </head> <body data-page-initialized="false"> <p>Write you page here</p> <script> $(document).ready(function () { $(document.body).attr('data-page-initialized', 'true'); }); </script> </body> </html>
然后创buildSelenium webdriver的扩展(根据挂毯框架)
public static void WaitForPageToLoad(this IWebDriver driver, int timeout = 15000) { //wait a bit for the page to start loading Thread.Sleep(100); //// In a limited number of cases, a "page" is an container error page or raw HTML content // that does not include the body element and data-page-initialized element. In those cases, // there will never be page initialization in the Tapestry sense and we return immediately. if (!driver.ElementIsDisplayed("/html/body[@data-page-initialized]")) { return; } Stopwatch stopwatch = Stopwatch.StartNew(); int sleepTime = 20; while(true) { if (driver.ElementIsDisplayed("/html/body[@data-page-initialized='true']")) { return; } if (stopwatch.ElapsedMilliseconds > 30000) { throw new Exception("Page did not finish initializing after 30 seconds."); } Thread.Sleep(sleepTime); sleepTime *= 2; // geometric row of sleep time } }
使用由Alister Scott编写的扩展ElementIsDisplayed。
public static bool ElementIsDisplayed(this IWebDriver driver, string xpath) { try { return driver.FindElement(By.XPath(xpath)).Displayed; } catch(NoSuchElementException) { return false; } }
最后创buildtesting:
driver.Url = this.GetAbsoluteUrl("/Account/Login"); driver.WaitForPageToLoad();
我执行了一个JavaScript代码来检查文档是否准备就绪。 为我节省了大量的时间debuggingselenium客户端渲染的网站testing。
public static boolean waitUntilDOMIsReady(WebDriver driver) { def maxSeconds = DEFAULT_WAIT_SECONDS * 10 for (count in 1..maxSeconds) { Thread.sleep(100) def ready = isDOMReady(driver); if (ready) { break; } }
}
public static boolean isDOMReady(WebDriver driver){ return driver.executeScript("return document.readyState"); }
我试过这个代码,它适用于我。 每次移动到另一个页面时,我都会调用这个函数
public static void waitForPageToBeReady() { JavascriptExecutor js = (JavascriptExecutor)driver; //This loop will rotate for 100 times to check If page Is ready after every 1 second. //You can replace your if you wants to Increase or decrease wait time. for (int i=0; i<400; i++) { try { Thread.sleep(1000); }catch (InterruptedException e) {} //To check page ready state. if (js.executeScript("return document.readyState").toString().equals("complete")) { break; } } }
public boolean waitForElement(String zoneName, String element, int index, int timeout) { WebDriverWait wait = new WebDriverWait(appiumDriver, timeout/1000); wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath(element))); return true; }
等待document.ready事件并不是解决这个问题的完整方法,因为这段代码仍然处于争用状态:有时候这个代码在click事件处理之前被触发,所以直接返回,因为浏览器还没有启动加载新的页面呢。
经过一番search,我在Obay上find了一个testing山羊的post, 这个山羊有一个解决这个问题的方法。 该解决scheme的C#代码是这样的:
IWebElement page = null; ... public void WaitForPageLoad() { if (page != null) { var waitForCurrentPageToStale = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); waitForCurrentPageToStale.Until(ExpectedConditions.StalenessOf(page)); } var waitForDocumentReady = new WebDriverWait(driver, TimeSpan.FromSeconds(10)); waitForDocumentReady.Until((wdriver) => (driver as IJavaScriptExecutor).ExecuteScript("return document.readyState").Equals("complete")); page = driver.FindElement(By.TagName("html")); }
`我在driver.navigate.gotourl之后直接使用这个方法,以便尽快得到页面的引用。 玩得开心!
像Rubanov为C#写的,我写它为Java,它是:
public void waitForPageLoaded() { ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver driver) { return (((JavascriptExecutor) driver).executeScript("return document.readyState").toString().equals("complete")&&((Boolean)((JavascriptExecutor)driver).executeScript("return jQuery.active == 0"))); } }; try { Thread.sleep(100); WebDriverWait waitForLoad = new WebDriverWait(driver, 30); waitForLoad.until(expectation); } catch (Throwable error) { Assert.fail("Timeout waiting for Page Load Request to complete."); } }
在Java中,它将如下所示:
private static boolean isloadComplete(WebDriver driver) { return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("loaded") || ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete"); }
当selenium打开一个新的页面从点击或提交或获取方法时,它会等待untell页面加载,但问题是当页面有一个xhr调用(ajax)他永远不会等待xhr被加载,所以创build一个新的方法来监视xhr并等待它们,这将是好事。 (抱歉,我的英语不好:D)
public boolean waitForJSandJQueryToLoad() { WebDriverWait wait = new WebDriverWait(webDriver, 30); // wait for jQuery to load ExpectedCondition<Boolean> jQueryLoad = new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { try { Long r = (Long)((JavascriptExecutor)driver).executeScript("return $.active"); return r == 0; } catch (Exception e) { LOG.info("no jquery present"); return true; } } }; // wait for Javascript to load ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() { @Override public Boolean apply(WebDriver driver) { return ((JavascriptExecutor)driver).executeScript("return document.readyState") .toString().equals("complete"); } }; return wait.until(jQueryLoad) && wait.until(jsLoad); }
如果$ .active == 0所以没有活动的xhrs调用(只适用于jQuery)。 对于JavaScript AJAX调用你必须在你的项目中创build一个variables,并模拟它。
public void waitForPageToLoad() { (new WebDriverWait(driver, DEFAULT_WAIT_TIME)).until(new ExpectedCondition<Boolean>() { public Boolean apply(WebDriver d) { return (((org.openqa.selenium.JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete")); } });//Here DEFAULT_WAIT_TIME is a integer correspond to wait time in seconds
在Ruby中有一些类似的东西:
wait = Selenium::WebDriver::Wait.new(:timeout => 10) wait.until { @driver.execute_script('return document.readyState').eql?('complete') }
您可以让线程hibernate,直到页面重新加载。 这不是最好的解决scheme,因为您需要估计页面加载的时间。
driver.get(homeUrl); Thread.sleep(5000); driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(userName); driver.findElement(By.xpath("Your_Xpath_here")).sendKeys(passWord); driver.findElement(By.xpath("Your_Xpath_here")).click();
你在使用Angular吗? 如果你是可能的,webdriver不认识到asynchronous调用已经完成。
我build议看看Paul Hammants ngWebDriver 。 方法waitForAngularRequestsToFinish()可以派上用场。