【问题标题】:How to use Selenium get text from an element not including its sub-elements如何使用 Selenium 从不包括其子元素的元素中获取文本
【发布时间】:2020-12-02 21:00:23
【问题描述】:

HTML

<div id='one'>
    <button id='two'>I am a button</button>
    <button id='three'>I am a button</button>
    I am a div
</div>

代码

driver.findElement(By.id('one')).getText();

【问题讨论】:

标签: java selenium


【解决方案1】:

在过去大概一年左右的时间里,我已经看到这个问题出现了几次,我想尝试编写这个函数......所以你去吧。它获取父元素并删除每个子元素的 textContent,直到剩下的是 textNode。我已经在您的 HTML 上对此进行了测试,并且可以正常工作。

/**
 * Takes a parent element and strips out the textContent of all child elements and returns textNode content only
 * 
 * @param e
 *            the parent element
 * @return the text from the child textNodes
 */
public static String getTextNode(WebElement e)
{
    String text = e.getText().trim();
    List<WebElement> children = e.findElements(By.xpath("./*"));
    for (WebElement child : children)
    {
        text = text.replaceFirst(child.getText(), "").trim();
    }
    return text;
}

你叫它

System.out.println(getTextNode(driver.findElement(By.id("one"))));

【讨论】:

  • @Dale 有风险。考虑&lt;div id="one"&gt;A button follows: &lt;button&gt;button&lt;/button&gt;&lt;/div&gt; - 通过这种方法,您将得到:A follows: button。不完全是预期的
  • @JeffC 考虑一下&lt;label id="one"&gt;Dimension: &lt;input type='text' name='dim'&gt; &lt;span class='units'&gt;m&lt;/span&gt;&lt;/label&gt;。还在做作?
  • 我已经说过这不是一个通用的案例解决方案。所以我只是好奇......当这个页面上的其他答案在一般情况下也没有工作时,你为什么如此关注我和我的答案?你没有对他们投反对票或评论。您提供的两个答案不起作用,另一个是从另一个用户复制的,仍然不起作用。我刚刚在 Chrome 上运行了您所有的案例以及 OP,但没有一个有效。
【解决方案2】:

警告:最初的解决方案(在下方)不起作用
我针对 Selenium WebDrive 和针对 W3C WebDrive 规范的enhancement request: 2840 和 W3C WebDrive 规范开了一个 another one - 投票越多,他们越早得到足够的关注(希望如此)。在此之前,@shivansh 在另一个答案(通过 Selenium 执行 JavaScript)中建议的解决方案仍然是唯一的选择。这是该解决方案的 Java 改编版本(收集所有文本节点,仅丢弃所有空白,将其余部分用 \t 分隔):

WebElement e=driver.findElement(By.xpath("//*[@id='one']"));
if(driver instanceof JavascriptExecutor) {
  String jswalker=
      "var tw = document.createTreeWalker("
     +   "arguments[0],"
     +   "NodeFilter.SHOW_TEXT,"
     +   "{ acceptNode: function(node) { return NodeFilter.FILTER_ACCEPT;} },"
     +    "false"
     + ");"
     + "var ret=null;"
     + "while(tw.nextNode()){"
     +   "var t=tw.currentNode.wholeText.trim();"
     +   "if(t.length>0){" // skip over all-white text values
     +      "ret=(ret ? ret+'\t'+t : t);" // if many, tab-separate them
     +   "}"
     + "}"
     + "return ret;" // will return null if no non-empty text nodes are found
  ;
  Object val=((JavascriptExecutor) driver).executeScript(jswalker, e);
  // ---- Pass the context node here ------------------------------^
  String textNodesTabSeparated=(null!=val ? val.toString() : null);
  // ----^ --- this is the result you want
}

参考资料:

TreeWalker - 所有浏览器都支持

Selenium Javascript Executor


最初建议的解决方案 - 不起作用 - 请参阅 enhancement request: 2840

driver.findElement(By.id('one')).find(By.XPath("./text()").getText();

在一次搜索中

driver.findElement(By.XPath("//[@id=one]/text()")).getText();

参见XPath spec/Location Paths child::text() 选择器。

【讨论】:

  • org.openqa.selenium.InvalidSelectorException:无效选择器:xpath表达式“.//*[@class='global-alerts']/text()”的结果是:[object Text ]。它应该是一个元素。
  • 当我尝试这个javascript时,我得到e下面的所有文本元素(也来自子元素)和直接的文本子元素(问题是关于什么的)......
【解决方案3】:

我使用如下函数:

private static final String ALL_DIRECT_TEXT_CONTENT =
        "var element = arguments[0], text = '';\n" +
                "for (var i = 0; i < element.childNodes.length; ++i) {\n" +
                "  var node = element.childNodes[i];\n" +
                "  if (node.nodeType == Node.TEXT_NODE" +
                " && node.textContent.trim() != '')\n" +
                "    text += node.textContent.trim();\n" +
                "}\n" +
                "return text;";

public String getText(WebDriver driver, WebElement element) {
    return (String) ((JavascriptExecutor) driver).executeScript(ALL_DIRECT_TEXT_CONTENT, element);
}

【讨论】:

    【解决方案4】:
    var outerElement = driver.FindElement(By.XPath("a"));
    var outerElementTextWithNoSubText = outerElement.Text.Replace(outerElement.FindElement(By.XPath("./*")).Text, "");
    

    【讨论】:

    • 感谢您提供此代码 sn-p,它可能会提供一些有限的即时帮助。 proper explanation 将通过展示为什么这是解决问题的好方法,并使其对有其他类似问题的未来读者更有用,从而大大提高其长期价值。请edit您的回答添加一些解释,包括您所做的假设。
    【解决方案5】:

    与给定解决方案类似,但不是 JavaScript 或将文本设置为 "",而是删除 XML 中的元素,然后获取文本。

    问题:

    需要来自“没有子元素的根元素”的文本,其中子元素的深度可以是 x 级,并且根元素中的文本可以与其他元素中的文本相同。

    该解决方案将 Web 元素视为 XML,并将子元素替换为 void,因此仅保留根。

    然后解析结果。在我的情况下,这似乎有效。

    我只在使用 Groovy 的环境中验证了这段代码。不知道它是否可以在不修改的情况下在 Java 中工作。从本质上讲,您需要用 Java 库替换 XML 的 groovy 库,然后我猜就可以了。

    至于代码本身,我有两个参数:

    • WebElement el
    • 布尔严格

    当 strict 为真时,实际上只考虑根。如果 strict 为 false,则将留下标记标签。我在这个白名单中加入了 p、b、i、strong、em、mark、small、del、ins、sub、sup。

    逻辑是:

    1. 管理列入白名单的标签
    2. 以字符串形式获取元素 (XML)
    3. 解析为 XML 对象
    4. 将所有子节点设置为无效
    5. 解析并获取文本

    到目前为止,这似乎正在奏效。

    您可以在这里找到代码:GitHub Code

    【讨论】:

      猜你喜欢
      • 2022-12-12
      • 2012-09-01
      • 2015-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多