Selenium xpath не может найти элемент (другие инструменты xpath доказывают, что он есть) - PullRequest
1 голос
/ 12 июня 2019

Selenium 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}')]");

Целевым элементом является div, содержащий guid:

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

Это с

  • dotnet core 2.2
  • chrome webdriver
  • 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 есть три текстовых узла как дочерние (это верно?).Результат выглядит на 100% нормальным - он отлично отрисовывается, а проверка элемента с помощью devtools выглядит как один текстовый узел, а .textContent возвращает объединенную строку.

Ответы [ 3 ]

1 голос
/ 12 июня 2019

Теперь, когда вы дали больше информации (как создается этот элемент):

Да, возможно, что элемент XML имеет в качестве дочерних элементов несколько отдельных текстовых узлов.Однако обычно это не тот случай, если текстовые узлы смежны друг с другом, а не разделены дочерними элементами.

Если '269424ae-4d74-4a68-91e0-1603f2d674a0' действительно является вторым текстовым узлом, то

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

действительно не вернет этот div элемент.Вы не должны думать об этом как о «нарушении XPath», просто точная семантика выражения такова:

Найти элемент с любым именем, чей текстовый узел first содержит'269424ae-4d74-4a68-91e0-1603f2d674a0'.

text() фактически выбирает все текстовые узлы элемента, но такие функции XPath, как contains() silenty select только первый.

На самом деле вы бы хотели выбрать

элемент с любым именем, где любой текстовый узел содержит '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')]]
0 голосов
/ 12 июня 2019

Попробуйте следующий xpath. Смотрите, если вам повезет.

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

EDIT

//div[contains(.,'269424ae-4d74-4a68-91e0-1603f2d674a0')]
0 голосов
/ 12 июня 2019
  1. Это может быть случай, когда элемент живет в iframe, если это так - вам придется использовать функцию IWebDriver.SwitchTo () в чтобы переключиться на нужный iframe, прежде чем пытаться найти элемент.

  2. Это может быть случай, когда элемент не доступен сразу, т.е. он загружается AJAX-запросом *1013*, в этом случае вам нужно будет использовать класс WebDriverWait Selenium может подождать, пока элемент появится в DOM , прежде чем взаимодействовать с ним.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...