【问题标题】:Selenium ChromeDriver: increasing time of getting WebElement TextSelenium ChromeDriver:增加获取 WebElement 文本的时间
【发布时间】:2018-04-30 09:43:40
【问题描述】:

我有一个代码可以遍历表的行和列,我想将它的值添加到列表中。

这需要我大量的时间。

所以我添加了一个时间测量,我注意到由于某种原因,时间逐行增加。

我不明白为什么。

你能建议吗?

private void buildTableDataMap() {

    WebElement table = chromeWebDriver.findElement(By.id("table-type-1"));

    List<WebElement> rows = table.findElements(By.tagName("tr"));

    theMap.getInstance().clear();

    String item;
    for (WebElement row : rows) {

        ArrayList<String> values = new ArrayList<>(); 

        List<WebElement> tds = row.findElements(By.tagName("td"));

        if(tds.size() > 0){

            WebElement last = tds.get(tds.size() - 1);

            long time = System.currentTimeMillis();

            values.addAll(tds.stream().map(e->e.getText()).collect(Collectors.toList()));

            System.out.println(System.currentTimeMillis() - time);

            //remove redundant last entry:
            values.remove(tds.size() - 1);
            callSomeFunc(values, last);

            item = tds.get(TABLE_COLUMNS.NAME_COL.getNumVal()).getText();
            item = item.replaceAll("[^.\\- /'&A-Za-z0-9]", "").trim();//remove redundant chars

            theMap.getInstance().getMap().put(item, values);
        }
    }
}

伙计们,我继续研究。 首先,弗洛伦特的友好回答对我没有帮助,因为至少据我所知,它返回了我必须解析的字符串数组列表,我不太喜欢这种解决方案......

所以我发现 e.getText() 调用在每次调用之间的时间都在增加,从而解决了这个问题!!! 我也尝试了 e.getAttribute("innerText") 但没有改变。 无法理解为什么。有什么想法可以解决吗?

            WebElement last = null;
            for (WebElement e : tds){
                last = e;

                long tm1 = 0, tm2 = 0;
                if(Settings.verboseYN) {
                    tm1 = System.currentTimeMillis();
                }
                s = e.getText(); //This action increases in time!!!
                if(Settings.verboseYN) {
                    tm2 = System.currentTimeMillis();
                }
                values.add(s); //a 0 ms action!!!
                if(Settings.verboseYN) {
                    System.out.println("e.getText()) took " + (tm2 - tm1) + " ms...");
                }
            }

这是 getText 所用时间的图表...


18 年 5 月 8 日 增加执行时间的另一个来源是:

void func(WebElement anchorsElement){

    List<WebElement> anchors = anchorsElement.findElements(By.tagName("a"));

    for (WebElement a : anchors) {

        if (a.getAttribute("class").indexOf("a") > 0)
            values.add("A");
        else if (a.getAttribute("class").indexOf("b") > 0)
            values.add("B");
        else if (a.getAttribute("class").indexOf("c") > 0)
            values.add("C");

    }
}

每个函数只有 5 次迭代,但每次调用该函数仍会增加其执行时间。 这个也有解决办法吗?

【问题讨论】:

  • 使用您尝试自动化手动步骤以及相关的HTML更新问题
  • @DebanjanB 没有具体的手动步骤。我想做的是从一些站点表中提取数据。所有的表都具有相同的结构。
  • 您是否发现网站本身需要时间返回数据或硒代码对此负责?
  • @HelpingHands 我不确定问题出在站点、selenium 基础架构还是仅仅是 java。请注意,我只是测量时间: values.addAll(tds.stream().map(e->e.getText()).collect(Collectors.toList()));它是从测量到测量不断增加的。也许这是合乎逻辑的并且取决于初始值列表的大小?
  • @dushkin - 您尝试与之交互并存储到数组中的页面共有多少行?

标签: java selenium selenium-webdriver selenium-chromedriver


【解决方案1】:

调用驱动程序是一项昂贵的操作。要显着减少执行时间,请使用带有 executeScript 的 JavaScript 注入在一次调用中读取整个表。然后用 Java 在客户端处理/过滤数据。

public ArrayList<?> readTable(WebElement table)
{
    final String JS_READ_CELLS = 
        "var table = arguments[0]; " +
        "return map(table.querySelectorAll('tr'), readRow); " +
        "function readRow(row) { return map(row.querySelectorAll('td'), readCell) }; " +
        "function readCell(cell) { return cell.innerText }; " +
        "function map(items, fn) { return Array.prototype.map.call(items, fn) }; " ;

    WebDriver driver = ((RemoteWebElement)table).getWrappedDriver();
    Object result = ((JavascriptExecutor)driver).executeScript(JS_READ_CELLS, table);
    return (ArrayList<?>)result;
}

【讨论】:

  • 我会检查的。谢谢
  • 我看到正在读取的表,但是当试图将它返回到 Object[] 时,我得到 java.lang.ClassCastException: java.util.ArrayList cannot be cast to [Ljava.lang.Object ;
  • 我最初是为 C# 编写的,所以返回的类型可能不同。仅供参考,该脚本返回一个锯齿状数组。尝试将 Object 转换为 (ArrayList&lt;?&gt;)result
  • 非常感谢您的努力。请看问题的修正。谢谢
【解决方案2】:

您面临的问题是 Selenium 的设计工作方式。让我们看看 JavaScript get 是如何执行的或操作是如何执行的

tds.get(TABLE_COLUMNS.NAME_COL.getNumVal()).getText();

你有一个对象的集合。 selenium 驱动程序在浏览器端为每个对象分配一个唯一的 ID

所以当你在下面执行getText() 时会发生什么

Your code -> HTTP Request -> Browser Driver -> Browser ->
                                                        |
           <---------------------------------------------

现在,如果您有一个 400rx10c 的表,那么它会占用 4000 HTTP 调用,即使一个调用需要 10 毫秒,我们也会看到 40000ms~=40sec,这是读取表的适当延迟

所以你想要做的是通过执行一个返回二维数组的 javascript 来一次性获取所有数据。这很简单,我在下面的网站上找到了一个代码

http://cwestblog.com/2016/08/21/javascript-snippet-convert-html-table-to-2d-array/

function tableToArray(tbl, opt_cellValueGetter) {
  opt_cellValueGetter = opt_cellValueGetter || function(td) { return td.textContent || td.innerText; };
  var twoD = [];
  for (var rowCount = tbl.rows.length, rowIndex = 0; rowIndex < rowCount; rowIndex++) {
    twoD.push([]);
  }
  for (var rowIndex = 0, tr; rowIndex < rowCount; rowIndex++) {
    var tr = tbl.rows[rowIndex];
    for (var colIndex = 0, colCount = tr.cells.length, offset = 0; colIndex < colCount; colIndex++) {
      var td = tr.cells[colIndex], text = opt_cellValueGetter(td, colIndex, rowIndex, tbl);
      while (twoD[rowIndex].hasOwnProperty(colIndex + offset)) {
        offset++;
      }
      for (var i = 0, colSpan = parseInt(td.colSpan, 10) || 1; i < colSpan; i++) {
        for (var j = 0, rowSpan = parseInt(td.rowSpan, 10) || 1; j < rowSpan; j++) {
          twoD[rowIndex + j][colIndex + offset + i] = text;
        }
      }
    }
  }
  return twoD;
}

我假设您将上述脚本存储在 SCRIPT 变量中,然后您可以像下面这样运行它

WebDriver driver = ((RemoteWebElement)table).getWrappedDriver();
Object result = ((JavascriptExecutor)driver).executeScript(SCRIPT + "\n return tableToArray(arguments[0]);" , table);

这将为您提供一个二维数据数组,然后您可以按照自己喜欢的方式处理它

【讨论】:

  • Tarun,感谢您详细解释的答案。您的解决方案不是 Florent 解决方案的变体吗?要返回表的字符串ArrayList?我对 Florent 的解决方案的问题是,由于某种原因,行中的最后一个 WebElement 没有在他的函数的输出中给出。所以,我只能使用 element.getText() 来提取它的值。恐怕我也会在这里遇到同样的问题,但无论如何我都会尝试。
  • @dushkin,是的,它只在同一行,如果你没有得到最后一行,那么可能有两个原因。最后一行不是主表的一部分,也不是嵌套在同一个表中的东西。我还想添加关于您要求的时间延迟的解释。如果这不起作用,请提供表格的 HTML 供我们检查
  • 我可能没有很好地解释自己。我没有得到行中的最后一个 td 值。我会尝试并尽快更新
猜你喜欢
  • 1970-01-01
  • 2015-10-18
  • 1970-01-01
  • 2021-09-18
  • 2022-01-24
  • 2015-12-30
  • 1970-01-01
  • 2018-02-13
  • 2022-12-10
相关资源
最近更新 更多