【问题标题】:How do I select all the columns first cells (tds) in Selenium webdriver?如何在 Selenium webdriver 中选择所有列第一个单元格(tds)?
【发布时间】:2012-09-14 21:47:47
【问题描述】:

我正在使用 Selenium 2.12。使用 WebDriver API,假设我有一个表示表格的 WebElement (<table>)。使用该元素,我如何选择第一列中的所有 td?我假设这里有一个 xpath 表达式。

为了更好地理解表格结构,如果我从 tableElement WebElement 中获取 HTML ...

String html = (String)((JavascriptExecutor)driver).executeScript("return arguments[0].innerHTML;", tableElt); 

我得到了下面的混乱。需要注意的关键是有 6 个 tr 和 16 个 td ...

<thead><tr><th colspan="1" class="GCSPOWVGE GCSPOWVEE GCSPOWVEF GCSPOWVFF"><div style="padding-left: 17px;position:relative;zoom:1;"><div style="left:0px;margin-top:-4px;position:absolute;top:50%;line-height:0px;"><img onload='this.__gwtLastUnhandledEvent="load";' src="http://localhost:9080/cme-productplus-web/productplus/clear.cache.gif" style="width: 11px; height: 7px; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAHCAYAAADebrddAAAAiklEQVR42mNgwALyKrumFRf3iDAQAvmVXVVAxf/zKjq341WYV95hk1fZ+R+MK8C4HqtCkLW5FZ2PQYpyK6AaKjv/5VV1OmIozq3s3AFR0AXFUNMrO5/lV7WKI6yv6mxCksSGDyTU13Mw5JV2qeaWd54FWn0BRAMlLgPZl/NAuBKMz+dWdF0H2hwCAPwcZIjfOFLHAAAAAElFTkSuQmCC) no-repeat 0px 0px;" border="0"></div><div>GUID</div></div></th><th colspan="1" class="GCSPOWVGE GCSPOWVEF">Fung Ratio</th><th colspan="1" class="GCSPOWVGE GCSPOWVEF">Fung type</th><th colspan="1" class="GCSPOWVGE GCSPOWVEF">Fung Date Offset</th><th colspan="1" class="GCSPOWVGE GCSPOWVEF  GCSPOWVOE">Days To Retain</th></tr></thead><colgroup><col><col><col><col><col></colgroup><tbody><tr onclick="" class="GCSPOWVAE"><td class="GCSPOWVPD GCSPOWVBE GCSPOWVCE"><div style="outline:none;" tabindex="0">      DSSUAQR6IE6E    </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      10      </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">              </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      </div></td><td class="GCSPOWVPD GCSPOWVBE GCSPOWVME"><div style="outline:none;">            </div></td></tr><tr onclick="" class="GCSPOWVAF"><td class="GCSPOWVPD GCSPOWVBF GCSPOWVCE"><div style="outline:none;">      ETTUAQR6IE6E    </div></td><td class="GCSPOWVPD GCSPOWVBF"><div style="outline:none;">      30      </div></td><td class="GCSPOWVPD GCSPOWVBF"><div style="outline:none;">              </div></td><td class="GCSPOWVPD GCSPOWVBF"><div style="outline:none;">      </div></td><td class="GCSPOWVPD GCSPOWVBF GCSPOWVME"><div style="outline:none;">            </div></td></tr><tr onclick="" class="GCSPOWVAE"><td class="GCSPOWVPD GCSPOWVBE GCSPOWVCE"><div style="outline:none;">      FCCUAQR6IE6E    </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      20      </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">              </div></td><td class="GCSPOWVPD GCSPOWVBE"><div style="outline:none;">      </div></td><td class="GCSPOWVPD GCSPOWVBE GCSPOWVME"><div style="outline:none;">            </div></td></tr></tbody><tbody style="display: none;"><tr><td colspan="5" align="center"><div><div style="width: 100%; height: 100%; padding: 0px; margin: 0px; display: none;"><div style="width: 100%; height: 100%; display: none;"></div></div><div style="width: 100%; height: 100%; padding: 0px; margin: 0px; display: none;"><div class="GCSPOWVPE" style="width: 100%; height: 100%; display: none;"><img class="gwt-Image" onload='this.__gwtLastUnhandledEvent="load";' src="http://localhost:9080/cme-productplus-web/productplus/clear.cache.gif" style="width: 43px; height: 11px; background: url(data:image/gif;base64,R0lGODlhKwALAPEAAP///0tKSqampktKSiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAKwALAAACMoSOCMuW2diD88UKG95W88uF4DaGWFmhZid93pq+pwxnLUnXh8ou+sSz+T64oCAyTBUAACH5BAkKAAAALAAAAAArAAsAAAI9xI4IyyAPYWOxmoTHrHzzmGHe94xkmJifyqFKQ0pwLLgHa82xrekkDrIBZRQab1jyfY7KTtPimixiUsevAAAh+QQJCgAAACwAAAAAKwALAAACPYSOCMswD2FjqZpqW9xv4g8KE7d54XmMpNSgqLoOpgvC60xjNonnyc7p+VKamKw1zDCMR8rp8pksYlKorgAAIfkECQoAAAAsAAAAACsACwAAAkCEjgjLltnYmJS6Bxt+sfq5ZUyoNJ9HHlEqdCfFrqn7DrE2m7Wdj/2y45FkQ13t5itKdshFExC8YCLOEBX6AhQAADsAAAAAAAAAAAA=) no-repeat 0px 0px;" border="0"></div></div></div></td></tr></tbody><tfoot style="display: none;"><tr><th colspan="5" class="GCSPOWVFE GCSPOWVDE  GCSPOWVNE"></th></tr></tfoot>

很遗憾,这两个表达式都没有产生正确的结果。

        // This returns zero td's
        final List<WebElement> tds = tableElt.findElements(By.xpath("/tr/td[1]"));

        ...

        // This returns 238 td's (I think that's everything in my document)
        final List<WebElement> tds = tableElt.findElements(By.xpath("//td[1]"));

【问题讨论】:

    标签: xpath selenium webdriver


    【解决方案1】:
        // This returns 238 td's (I think that's everything in my document)               
        final List<WebElement> tds = tableElt.findElements(By.xpath("//td[1]"));
    

    这完全符合 thw XPath W3c 规范,是 XPath 中最常见的问题之一。

    // 伪运算符的优先级(priority)小于[] 运算符。

    因此,//SomeName[1] 选择所有名为 SomeName 且是其父级的第一个 SomeName 子级的元素 -- 并且可能有很多这样的元素。

    如果要选择 XML 文档中的第一个 SomeName 元素,则需要使用括号显式覆盖默认运算符优先级:

    (//SomeName)[1]
    

    在这种情况下,您只需要给定元素的第一个 td 后代 - 因此除了上述更正之外,您还必须将表达式更正为 relative - 不是绝对的。绝对 XPath 表达式(以 / 开头的总是以文档节点作为附加上下文节点进行评估)。

    使用

    (.//td)[1]
    

    如果你需要选中当前节点的所有td后代,那么使用:

    .//td
    

    甚至更好:

    .//descendant::td
    

    【讨论】:

    • 这是迄今为止最接近的答案。表达式 (.//td)[1] 只返回第一个 td 单元格,而不是第一列中的所有单元格,这就是我想要的。谢谢,-
    • @Dave:哦,那就用:.//td
    • 感谢您继续坚持这一点,但实际上对我有用的答案是“(.//td[1])”。你的答案不是只返回一个元素吗?
    • @Dave:回复:(.//td[1])。括号无关紧要,您可以省略它们。这将选择作为其父级的第一个 td 子级的任何 td 后代。你没有在你的问题中解释你实际上想要那个。此外,仍然不清楚哪个是初始上下文节点(您正在从其向下寻找 td s。这一切都是由于您没有提供示例源 XML 文档这一事实造成的。这将是如果您编辑您的问题并提供所有这些缺失和重要的信息,那就太好了。我希望您的问题的质量将来会提高。
    • @Dave:关于我的回答“只返回一个节点”——你显然没有阅读更新。 .//td选择初始上下文节点的所有td后代。
    【解决方案2】:

    要使用的确切表达式取决于文档的实际结构。

    在最一般的情况下——从表格中选择所有第一列的单元格——你可以使用以下表达式:

    <path_to_table>//td[1]
    

    例如,在这个文件上:

    <table>
        <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
        </tr>
        <tr>
            <td>a</td>
            <td>b</td>
            <td>c</td>
            <td>d</td>
        </tr>
        <tr>
            <td>i</td>
            <td>ii</td>
            <td>iii</td>
            <td>iv</td>
        </tr>
    </table>
    

    这个表达式:

    /table//td[1]
    

    给予:

    <td>1</td>
    <td>a</td>
    <td>i</td>
    

    请注意,我使用的是后代或自我轴 (//),因为 HTML 表格允许可选的分组元素(例如 &lt;tbody&gt;),这些元素可能存在也可能不存在。但是,这也将包括嵌套表中的第一列单元格。考虑这个输入:

    <table>
        <tr>
            <td>1</td>
            <td><table><td>test</td></table></td>
            <td>3</td>
            <td>4</td>
        </tr>
        <tr>
            <td>a</td>
            <td>b</td>
            <td>c</td>
            <td>d</td>
        </tr>
        <tr>
            <td>i</td>
            <td>ii</td>
            <td>iii</td>
            <td>iv</td>
        </tr>
    </table>
    

    上面的相同表达式返回:

    <td>1</td>
    <td>test</td>
    <td>a</td>
    <td>i</td>
    

    如果您对特定的表结构了解更多,那么您可以编写更具体的表达式。例如,在前面的输入中,这个表达式:

    /table/tr/td[1]
    

    ...仅返回最外层表格中的单元格:

    <td>1</td>
    <td>a</td>
    <td>i</td>
    

    【讨论】:

    • 如果我有一个已经指向相关表格的 WebElement,我需要写什么表达式?所以,它会像 tableElement.findElement(By.xpath("...")) 谢谢,- Dave
    • @Dave - 在这种情况下,它可能类似于 /tr/td[1]//td[1],具体取决于表结构
    • 嗨,很遗憾,这些表达式中的每一个都无法获得正确的结果。我编辑了我的回复以包含来自我的 WebElement 的表结构。虽然这是一团糟,但请相信第一个表达式 (/tr/td[1]) 在调用时返回零个元素,"final List tds = tableElt.findElements(By.xpath("/tr/td[ 1]"));"。第二个返回 238,这是我的 HTML 文档中的每个 td,而不是表元素中的 td。
    • 我不知道 Selenium,但在我看来 XPath 没有相对于表进行评估。
    • 如果你已经有了表格元素,那么它就像 tableElement.findElements(By.tagName("td"));
    【解决方案3】:

    如果每个tr 包含相同数量的td,您可以使用.findElements(By.tagName("td")) 形成所有td 元素的列表,并遍历该列表的每个第n 个元素,其中n 等于@987654325 的数量@元素中的每个tr

    List<WebElement> allTDs = table.findElements(By.tagName("td"));
    int n = table.findElements(By.tagName("tr")).size();
    
    List<WebElement> yourTDs = new ArrayList<WebElement>();
    for (int i = 0; i < allTDs.size(); i = i + n){
        yourTDs.add(allTDs.get(i));
    }
    

    【讨论】:

    • 我和这个人在一起。该代码可能无法正常工作,但您明白了。获取所有 td 或 tr 元素并在您的 java 代码中使用它们,这与 xpath 相比非常快。
    【解决方案4】:

    如果您已经将表格存储为 WebElement,那么您需要做的就是像解析 WebDriver 一样解析 WebElement。

    //The first part is just a reference for others to see the table element being caught
    WebElement TableElement = driver.findElement(By.tagName("table"));
    

    这将创建一个 td 元素的列表(您应该使用 xpath,因为您可以指定元素的相对 xPath 并说明您想要哪个特定元素 xPath 往往有点慢,所以如果您是使用 CssSelector 解析大页面:first-of-type

    List<WebElement> FirstColumns = TableElement.findElements(By.xPath("//tr/td[1]"));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      相关资源
      最近更新 更多