Selenium xpath找不到元素(其他xpath工具证明它在那里)

时间:2019-06-12 13:39:08

标签: selenium xpath .net-core selenium-chromedriver

硒FindElement:

driver.FindElement(By.XPath($"//*[contains(text(), '{text}')]"));

投掷:

no such element: Unable to locate element:
{
    "method":"xpath",
    "selector":"//*[contains(text(), '269424ae-4d74-4a68-91e0-1603f2d674a0')]"
}
(Session info: chrome=74.0.3729.169)
(Driver info: 
    chromedriver=74.0.3729.6 (255758eccf3d244491b8a1317aa76e1ce10d57e9-refs/branch-heads/3729@{#29}),
    platform=Linux 4.18.0-20-generic x86_64)

但是它肯定在那里并且xpath有效,因为我可以使用AngleSharp来使用相同的xpath表达式来解析驱动程序的页面源:

    new HtmlParser()
        .ParseDocument(driver.PageSource)
        .SelectSingleNode($"//*[contains(text(), '{text}')]");

目标元素是一个包含guid的div:

<div class="home-project-title-text"> 269424ae-4d74-4a68-91e0-1603f2d674a0 </div>

这是

  • dotnet核心2.2
  • chrome网络驱动程序
  • Chrome 74
  • Ubuntu 18.04

EDIT1

有趣的是,浏览器控制台中的document.evaluate也因此xpath表达式而失败。我将其用作运行xpath的辅助函数:

selectSingle = xpath => document.evaluate(xpath, document).iterateNext()

,然后发现它返回null:

> selectSingle("//*[contains(text(), '269424ae-4d74-4a68-91e0-1603f2d674a0')]")

> null

,但绝对存在,并且具有预期的文字,例如我可以使用其他xpath表达式来手动定位并检查其文本内容:

> selectSingle("//*[@id='app']/div/div[1]/div[3]/div/div[1]/div/div[1]/div")
    .textContent
    .trim() 
    == "269424ae-4d74-4a68-91e0-1603f2d674a0"

> true

EDIT2

所以原因是创建div的反应是这样的:

React.createElement(
    "div", 
    {className = "home-project-title-text"}, 
    " ", 
    "269424ae-4d74-4a68-91e0-1603f2d674a0", 
    " ");

我认为这大致意味着div具有三个textnode作为子节点(是否有效?)。结果看起来100%正常-它呈现完美,并且使用devtools检查元素看起来像是单个文本节点,并且.textContent返回串联的字符串。

3 个答案:

答案 0 :(得分:1)

现在,您提供了更多信息(如何创建此元素):

是的,XML元素可能有几个单独的文本节点作为其子元素。但是,如果文本节点彼此相邻而不是由子元素分隔,则通常不是这种情况。

如果'269424ae-4d74-4a68-91e0-1603f2d674a0'确实是第二个文本节点,则

//*[contains(text(), '269424ae-4d74-4a68-91e0-1603f2d674a0')]

实际上会返回此div元素。您不应将其视为“破坏性的XPath”,只是表达式的确切语义是:

  

找到一个名称为 first 文本节点包含“ 269424ae-4d74-4a68-91e0-1603f2d674a0”的元素。

text()实际上选择了元素的所有文本节点,但是诸如contains()之类的XPath函数仅仅选择第一个文本

您实际要选择的是

  

任何名称的元素,其中 any 文本节点包含“ 269424ae-4d74-4a68-91e0-1603f2d674a0”

要完全实现的表达式是:

//*[text()[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]]

您可以使用一个小的玩具文档来测试这些表情,例如:

<div className="home-project-title-text">
   <other/>
   269424ae-4d74-4a68-91e0-1603f2d674a0
   <other/>
</div>

other元素迫使div元素包含三个单独的文本节点,其中两个仅包含空格。


最后,如果您已经知道要查找的元素是div,则应该专门针对该元素:

//div[text()[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]]

答案 1 :(得分:0)

  1. 该元素可能位于iframe中,如果是这种情况,则您必须使用IWebDriver.SwitchTo()函数才能尝试切换到所需的iframe定位元素。

  2. 可能是该元素无法立即使用的情况,即它是由AJAX request加载的,在这种情况下,您将需要使用WebDriverWait类,以便Selenium可以等到元素在与之交互之前会出现在DOM中。

答案 2 :(得分:0)

尝试以下xpath。看看是否有运气。

//div[@class='home-project-title-text'][contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]

编辑

//div[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]