Selenium 在读取 DOM 时非常慢

Sai*_*fur 4 selenium webdriver selenium-firefoxdriver selenium-webdriver firefox-driver

Selenium 与 DOM 的交互似乎非常慢,同时在每个页面实例化中做几件事。在整个站点中,我们都有可见的微调器,指示是否已解决任何未解决的 API 调用。总之,我有三种方法可以在执行任何操作之前确保页面的稳定性。

  1. 检查 DOM 就绪状态
  2. 检查任何未完成的 JQuery 调用
  3. 检查加载微调器

所有这三个都是通过以下方法作为页面对象实例化的一部分完成的。

    public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver){
    final WebDriverWait wait = new WebDriverWait(driver, timeout);
    
    wait.until(waitForDomReadyState());
    wait.until(waitForjQueryToBeInactive());
    List<WebElement> elements = wait.until(ExpectedConditions.presenceOfAllElementsLocatedBy(spinnersLoacator));
    
    for(WebElement element: elements){
        wait.until(invisibilityOfElementLocated(element));  
     }
    }

    private static ExpectedCondition<Boolean> waitForDomReadyState(){

        return new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver d){

                return ( ((JavascriptExecutor) d).executeScript("return document.readyState;").equals("complete"));
            }
        };
    }


    private static ExpectedCondition<Boolean> waitForjQueryToBeInactive(){

        return new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver d){

                return (Boolean) ( ((JavascriptExecutor) d).executeScript("return jQuery.active == 0;"));
            }
        };
    }

    public static ExpectedCondition<Boolean> invisibilityOfElementLocated(final WebElement element){

        return new ExpectedCondition<Boolean>() {

            @Override
            public Boolean apply(WebDriver driver){

                try{
                    return !element.isDisplayed();
                } catch (NoSuchElementException | StaleElementReferenceException e){
                    // Returns true because the element is not present in DOM.
                    // The
                    // try block checks if the element is present but is
                    // invisible or stale
                    return true;
                }
            }
        };
    }
Run Code Online (Sandbox Code Playgroud)

以具有大量 API 调用并获取大量数据的页面(例如患者页面)为例。对于初始类实例化,大约需要 17 秒(日志如下)。我的 Selenium 知识表明,后续页面实例化不应花费相同或更多的时间来检查 DOM 就绪状态,或者 JQuery 调用或微调器等待,因为根本没有任何变化。但是,每次实例化新页面时,我都会看到检查所有这三个页面所花费的时间相同。那里发生了什么?每次我执行这些操作时,Selenium 是否真的尝试与服务器交互,或者由于某种原因与客户端的交互速度很慢?如果是这样,可能的答案是什么?

控制台日志

==== [[完成等待 [17] 秒后在小部件 [患者] 上找到 8 个微调元素]]

==== [[开始等待在小部件 [Patient] 上找到 8 个微调元素]]

==== [[完成等待 [17] 秒后在小部件 [患者] 上找到 8 个微调元素]]

==== [[[患者]]] 上的浏览​​器

==== [[开始等待在小部件 [Patient] 上找到 8 个微调元素]]

==== [[完成等待 [17] 秒后在小部件 [患者] 上找到 8 个微调元素]]

环境:

  1. 硒 2.48
  2. 火狐 38

我还尝试了 Selenium 2.52 和 firefox 44,结果相同

Flo*_* B. 5

Selenium 处理客户端的所有等待,每次评估都会向服务器发送请求,直到满足条件为止。在高延迟的情况下,它会迅速退化,尤其是在有大量调用的情况下。此外,一些评估需要脚本注入,这也无济于事。

因此,在您的情况下提高性能的最佳方法是使用单个异步 JavaScript 调用:

public static void waitForLoadingAllSpinnersAnywhere(final WebDriver driver) {
  const String JS_WAIT_SPINNERS = 
      "var callback = arguments[0]; " +
      "(function fn(){ " +
      "  if (document.readyState == 'complete' && jQuery.active == 0) { " +
      "    var elts = $('.spinners'); " +
      "    if (elts.length == 8 && !elts.is(':visible')) " +
      "      return callback(); " +
      "  } " +
      "  setTimeout(fn, 60); " +
      "})();";

   ((JavascriptExecutor)driver).executeAsyncScript(JS_WAIT_SPINNERS);
}
Run Code Online (Sandbox Code Playgroud)

初始化超时:

driver.manage().timeouts().setScriptTimeout(30, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)


dja*_*fan 3

您的测试似乎都是non-native调用,因此 Firefox 应该适合您,但令我惊讶的是,如果您使用 44 和 48,Firefox 对 driver.navigate() 的本机调用甚至可以帮助您进入初始页面。这很好已知 31.6.0 是最后一个受支持的本机 Firefox 版本。所以,我想说你应该使用 Chrome,直到你弄清楚这一点。

但是,回答你关于缓慢的问题。您编写代码的方式高度依赖 jQuery,我想您会遇到对 jQuery 代码的调用被延迟的问题,这会传播到您的 Selenium 测试,并进一步受到以下事实的影响:您循环多个旋转器。我之前注意到的一件事是,如果页面正忙于运行 ajax 调用,那么使用 JavascriptExecutor 的 Selenium 调用可能必须排队等待,以便放弃一些处理器时间。

我会采取什么不同的做法?好吧,我会编写我的微调器等待在 DOM 上操作,而不是调用 jQuery 的 JavascriptExecutors。也许在您的情况下,这不是一个选择,但我认为经过深思熟虑的计划可以提高页面就绪工作流程的效率。