【问题标题】:Do we have any generic function to check if page has completely loaded in Selenium我们是否有任何通用函数来检查页面是否已在 Selenium 中完全加载
【发布时间】:2020-11-28 19:09:54
【问题描述】:

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

我试过下面的代码:

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

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

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

【问题讨论】:

  • 可以查看URL的页面,看看页面是否加载?

标签: java selenium selenium-webdriver pageload dom-events


【解决方案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" 的上述两种方法看起来正在等待不确定的事件。因此,对于一个明确的等待,您可以将WebDriverWaitExpectedConditions 设置为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();

现在,虽然 页面标题 可能与您的 应用程序标题 匹配,但您想要交互的所需元素尚未完成加载。因此,更精细的方法是诱导 WebDriverWaitExpectedConditions 设置为 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();

参考文献

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

【讨论】:

    【解决方案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】:

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

      1. 等待完整页面加载

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

        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) {
        }
      1. 最后,不要获取 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)
            })
          """)
          

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-08-27
            • 2012-06-15
            相关资源
            最近更新 更多