Selenium中是否有通用函数来检查页面是否完全加载?

6

我想检查Selenium中网页是否已经完全加载完成(即检查所有控件都已加载)。

我尝试了下面的代码:

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

但即使页面正在加载,上述代码也不会等待。
我知道我可以检查特定元素以检查其是否可见/可点击等,但我正在寻找一些通用的解决方案。

您可以检查URL页面是否已加载? - Sneha Shinde
7个回答

4

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

首先让我们看一下你的代码试验,它是这样的:

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

上述代码中的参数pageLoadTimeout并不真正类似于实际的pageLoadTimeout()
在这里,您可以找到有关Selenium中pageLoadTimeout不起作用的详细讨论
现在,由于您的用例涉及页面完全加载,您可以使用pageLoadStrategy()设置为normal [支持的值为noneeagernormal],通过DesiredCapabilities类或ChromeOptions类的实例来实现:
  • Using DesiredCapabilities Class :

     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();
        }
    }
    
  • Using ChromeOptions Class :

    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();
        }
    }
    
您可以在Chrome驱动程序页面加载策略(更新至Selenium v3.12.0)中找到详细讨论。
现在将PageLoadStrategy设置为NORMAL,您的代码试验都确保了浏览器客户端已经达到了'document.readyState'等于"complete"。一旦满足这个条件,Selenium就会执行下一行代码。
您可以在Selenium IE WebDriver仅在调试时有效中找到详细讨论。
但是,浏览器客户端达到'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);
    }
}

你可以在等待Ajax请求完成 - 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();

有时候,尽管页面标题(Page Title)与您的应用程序标题(Application Title)相匹配,但是您想要交互的目标元素尚未加载完成。因此,一种更加细致的方法是结合ExpectedConditions设置为visibilityOfElementLocated()方法,使用WebDriverWait使程序等待所需的元素可见,如下所示:

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

参考资料

您可以在以下几个讨论中找到一些相关的详细讨论:


0

实现这个,它对我们许多人包括我都有效。它包括等待JavaScript、Angular、JQuery的Web页面。

如果您的应用程序包含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);
            }
          }

点击此处获取参考链接

如果您在实现过程中遇到任何问题,请告诉我。

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


1
虽然这个链接可能回答了问题,但最好在这里包含答案的必要部分并提供参考链接。如果链接的页面发生更改,仅链接的答案可能变得无效。- [来自审查] (/review/low-quality-posts/19722427) - Zabuzard
@Zabuza:代码已添加。谢谢。 - Ishita Shah

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

试试这个方法


0

我也使用selenium,曾经遇到过同样的问题,解决方法是等待jQuery加载完成。

如果你也遇到了同样的问题,可以尝试这个方法。

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

你可以将这两个函数封装在一个方法中,在检查页面和jQuery都加载完成之前等待。

你正在做一个假设,即被Selenium驱动的网站使用了JQuery... - Ardesco

0

有一种简单的方法可以做到这一点。当您首次通过JavaScript请求状态时,它会告诉您页面已经完成,但之后它会进入状态加载。第一个完成状态是初始页面!

因此,我的建议是在加载状态后检查完成状态。在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);

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

0

这对于动态渲染的网站对我来说很有效:

  1. 等待完整页面加载

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


    -1

    类似这样的代码应该可以工作(请原谅在Java答案中出现了Python代码):

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

    这应该会阻塞,直到事件循环处于空闲状态,这意味着所有资源都应该被加载。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接