我们是不是有任何通用函数来检查页面是不是已在 Selenium 中完全加载

Posted

技术标签:

【中文标题】我们是不是有任何通用函数来检查页面是不是已在 Selenium 中完全加载【英文标题】:Do we have any generic function to check if page has completely loaded in Selenium我们是否有任何通用函数来检查页面是否已在 Selenium 中完全加载 【发布时间】:2018-10-23 22:13:01 【问题描述】:

我正在尝试在 selenium 中检查网页是否加载完成(即检查所有控件是否已加载)。

我试过下面的代码:

new WebDriverWait(firefoxDriver, pageLoadTimeout).until(
          webDriver -> ((javascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));

但即使页面正在加载上面的代码也不会等待。

我知道我可以检查特定元素以检查其是否可见/可点击等,但我正在寻找一些通用解决方案

【问题讨论】:

可以查看URL的页面,看看页面是否加载? 【参考方案1】:

正如你提到的,如果有任何通用函数可以检查页面是否已通过Selenium 完全加载,答案是

首先让我们看看你的代码试验如下:

new WebDriverWait(firefoxDriver, pageLoadTimeout).until(webDriver -> ((JavascriptExecutor) webDriver).executeScript("return document.readyState").equals("complete"));

上述代码行中的参数pageLoadTimeout 与实际的pageLoadTimeout() 并没有真正的相似之处。

这里可以找到pageLoadTimeout in Selenium not working的详细讨论


现在,由于您的 用例 与页面完全加载相关,您可以使用 pageLoadStrategy() 设置为 normal [支持的值为 none em>、eagernormal ] 通过 DesiredCapabilities 类或 ChromeOptions 类的实例使用如下:

使用DesiredCapabilities类:

 import org.openqa.selenium.WebDriver;
 import org.openqa.selenium.firefox.FirefoxDriver;
 import org.openqa.selenium.firefox.FirefoxOptions;
 import org.openqa.selenium.remote.DesiredCapabilities;

 public class myDemo 
 
    public static void main(String[] args) throws Exception 
    
        System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
        DesiredCapabilities dcap = new DesiredCapabilities();
        dcap.setCapability("pageLoadStrategy", "normal");
        FirefoxOptions opt = new FirefoxOptions();
        opt.merge(dcap);
        WebDriver driver = new FirefoxDriver(opt);
        driver.get("https://www.google.com/");
        System.out.println(driver.getTitle());
        driver.quit();
    

使用 ChromeOptions 类:

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.PageLoadStrategy;

public class myDemo 

    public static void main(String[] args) throws Exception 
    
        System.setProperty("webdriver.gecko.driver", "C:\\Utility\\BrowserDrivers\\geckodriver.exe");
        FirefoxOptions opt = new FirefoxOptions();
        opt.setPageLoadStrategy(PageLoadStrategy.NORMAL);
        WebDriver driver = new FirefoxDriver(opt);
        driver.get("https://www.google.com/");
        System.out.println(driver.getTitle());
        driver.quit();
    

您可以在Page load strategy for Chrome driver (Updated till Selenium v3.12.0)找到详细讨论


现在将 PageLoadStrategy 设置为 NORMAL 并且您的代码试用都确保 Browser Client 具有(即 Web Browser em>) 已达到'document.readyState' 等于"complete"。一旦满足这个条件,Selenium 就会执行下一行代码。

您可以在Selenium IE WebDriver only works while debugging找到详细讨论

但是 Browser Client 达到 'document.readyState' 等于 "complete" 仍然不能保证所有 JavaScriptAjax 调用完成。


要等待所有 JavaScriptAjax 调用 完成,您可以编写如下函数:

public void WaitForAjax2Complete() throws InterruptedException

    while (true)
    
        if ((Boolean) ((JavascriptExecutor)driver).executeScript("return jQuery.active == 0"))
            break;
        
        Thread.sleep(100);
    

您可以在Wait for ajax request to complete - selenium webdriver找到详细讨论


现在,通过 PageLoadStrategy"return jQuery.active == 0" 的上述两种方法看起来正在等待不确定的事件。因此,对于一个明确的等待,您可以将WebDriverWait 与ExpectedConditions 设置为titleContains() 方法相结合,这将确保页面标题(即网页)是可见并假设所有元素也是可见的,如下所示:

driver.get("https://www.google.com/");
new WebDriverWait(driver, 10).until(ExpectedConditions.titleContains("partial_title_of_application_under_test"));
System.out.println(driver.getTitle());
driver.quit();

现在,虽然 页面标题 可能与您的 应用程序标题 匹配,但您想要交互的所需元素尚未完成加载。因此,更精细的方法是诱导 WebDriverWait 与 ExpectedConditions 设置为 visibilityOfElementLocated() 方法的联合使用,这将使您的程序等待所需的元素可见,如下所示:

driver.get("https://www.google.com/");
WebElement ele = new WebDriverWait(driver, 10).until(ExpectedConditions.visibilityOfElementLocated(By.xpath("xpath_of_the_desired_element")));
System.out.println(ele.getText());
driver.quit();

参考文献

您可以在以下位置找到一些相关的详细讨论:

Selenium IE WebDriver only works while debugging Selenium how to manage wait for page load?

【讨论】:

【参考方案2】:

我也使用 selenium,但我也遇到了同样的问题,为了解决这个问题,我也只是等待 jQuery 加载。

所以如果你有同样的问题也试试这个

((Long) ((JavascriptExecutor) browser).executeScript("return jQuery.active") == 0);

您可以将这两个函数包装在一个方法中并检查直到页面和 jQuery 都被加载

【讨论】:

您假设由 Selenium 驱动的网站使用 JQuery...【参考方案3】:

实现这一点,它适用于包括我在内的许多人。它包括在 JavaScript、Angular、JQuery 上等待的网页(如果有的话)。

如果您的应用程序包含 Javascript 和 JQuery,您可以只为它们编写代码,

通过在单个方法中定义它,您可以在任何地方调用它:

          // Wait for jQuery to load
                       
            ExpectedCondition<Boolean> jQueryLoad = driver -> ((Long) ((JavascriptExecutor) driver).executeScript("return jQuery.active") == 0);

            boolean jqueryReady = (Boolean) js.executeScript("return jQuery.active==0");

            if (!jqueryReady) 
                // System.out.println("JQuery is NOT Ready!");
                wait.until(jQueryLoad);
            
            wait.until(jQueryLoad);
          

          // Wait for ANGULAR to load
                         
            String angularReadyScript = "return angular.element(document).injector().get('$http').pendingRequests.length === 0";

            ExpectedCondition<Boolean> angularLoad = driver -> Boolean.valueOf(((JavascriptExecutor) driver).executeScript(angularReadyScript).toString());

            boolean angularReady = Boolean.valueOf(js.executeScript(angularReadyScript).toString());

            if (!angularReady) 
                // System.out.println("ANGULAR is NOT Ready!");
                wait.until(angularLoad);
            
          

          // Wait for Javascript to load    
                       
            ExpectedCondition<Boolean> jsLoad = driver -> ((JavascriptExecutor) driver).executeScript("return document.readyState").toString()
                    .equals("complete");

            boolean jsReady = (Boolean) js.executeScript("return document.readyState").toString().equals("complete");

            // Wait Javascript until it is Ready!
            if (!jsReady) 
                // System.out.println("JS in NOT Ready!");
                wait.until(jsLoad);
            
          

Click here for Reference Link

让我知道您是否通过实施陷入困境。

它克服了线程或显式等待的使用。

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review @Zabuza :添加了代码。谢谢。【参考方案4】:
    public static void waitForPageToLoad(long timeOutInSeconds) 
    ExpectedCondition<Boolean> expectation = new ExpectedCondition<Boolean>() 
        public Boolean apply(WebDriver driver) 
            return ((JavascriptExecutor) driver).executeScript("return document.readyState").equals("complete");
        
    ;
    try 
        System.out.println("Waiting for page to load...");
        WebDriverWait wait = new WebDriverWait(Driver.getDriver(), timeOutInSeconds);
        wait.until(expectation);
     catch (Throwable error) 
        System.out.println(
                "Timeout waiting for Page Load Request to complete after " + timeOutInSeconds + " seconds");
    

试试这个方法

【讨论】:

【参考方案5】:

这对我来说很适合动态呈现的网站:

    等待完整页面加载

WebDriverWait wait = new WebDriverWait(driver, 50); 
wait.until((ExpectedCondition<Boolean>) wd -> ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
    使用一个总是会失败的虚拟条件进行另一个隐式等待

  try           
 wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*[contains(text(),'" + "This text will always fail :)" + "')]"))); // condition you are certain won't be true 
   
  catch (TimeoutException te) 
  
    最后,不要获取 html 源代码(在大多数单页应用程序中会给您带来不同的结果),而是拉取第一个 html 标记的 outerhtml

String script = "return document.getElementsByTagName(\"html\")[0].outerHTML;"; 
content = ((JavascriptExecutor) driver).executeScript(script).toString();

【讨论】:

【参考方案6】:

有一种简单的方法可以做到这一点。当你第一次通过javascript请求状态时,它会告诉你页面是complete,但之后它会进入状态loading。第一个complete 状态是初始页面!

所以我的建议是在loading 状态之后检查complete 状态。用 php 检查这段代码,很容易翻译成另一种语言。

        $prevStatus  = '';
        $checkStatus = function ($driver) use (&$prevStatus)

          $status = $driver->executeScript("return document.readyState"); 

          if ($prevStatus=='' && $status=='loading')
            //save the previous status and continue waiting
            $prevStatus = $status; 
            return false;
          

          if ($prevStatus=='loading' && $status=='complete')
            //loading -> complete, stop waiting, it is finish!
            return true;
          
          //continue waiting 
          return false;

        ;
        $this->driver->wait(20, 150)->until($checkStatus);

检查是否存在的元素也很有效,但您需要确保该元素仅存在于目标页面中。

【讨论】:

【参考方案7】:

这样的东西应该可以工作(请原谅java答案中的python):

idle = driver.execute_async_script("""
  window.requestIdleCallback(() => 
    arguments[0](true)
  )
""")

这应该阻塞,直到事件循环空闲,这意味着应该加载所有资产。

【讨论】:

以上是关于我们是不是有任何通用函数来检查页面是不是已在 Selenium 中完全加载的主要内容,如果未能解决你的问题,请参考以下文章

如何检查类型是不是提供无参数构造函数?

如何检测函数是不是已在本地定义?

修改 glibc 动态链接器以检查共享库是不是已在另一个进程中加载

检查用户是不是已在 Swift 中注册本地通知时出错

如何检查 `let` 变量是不是已在 ES6 上声明?

如何检查重用标识符是不是已在 UITableView 中注册?