Поиск элемента по xpath - lxml и Selenium приводит к разным выводам для одного и того же выражения - PullRequest
1 голос
/ 06 июня 2019

Это первый из пары вопросов о том, как lxml и Selenium обрабатывают выражение xpath.(Хотя это и похоже, но отличается от этого вопроса ).

Итак, давайте начнем с более простого вопроса.

Вот строка:

my_str = """
<div class="container">

   <div class="24">
        <div class="25">forget me</div>
        <div class="26">a target </div>
   </div>
    <div class="27">very desired
        <div class="28">whatever</div>
        <div class="29">another target</div>
    </div>
    <div class="30">go home
         <div class="31">Nothing here</div>
         <div class="32">somewhat desired</div>
    </div>
 </div>
"""

А вот выражение xpath:

simple_expression = "//*[contains(text(), 'target')]"

Теперь давайтепосмотрите, как это обрабатывается с помощью lxml:

import lxml.html
root = lxml.html.fromstring(my_str)

e = root.xpath(simple_expression)
for entry in e:
    print(entry.text)

Это дает желаемый результат:

цель

другая цель

Для Selenium:

from selenium.webdriver import Chrome
driver = Chrome()
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=my_str))

e2 = driver.find_element_by_xpath(simple_expression)
print(e2.text)

Выход на этот раз всего лишь

цель

Итак, во-первых, почему это так?Во-вторых, как сделать Selenium generae одинаковым выходом?

Ответы [ 2 ]

3 голосов
/ 06 июня 2019

Это потому, что вы использовали find_element_by_xpath, и он вернет один элемент и первый найденный элемент.

Вам нужно использовать driver.find_elements_by_xpath, чтобы получить все элементы.

driver.find_elements_by_xpath(simple_expression)

Вот ваш полный код.

from selenium.webdriver import Chrome
my_str = """
<div class="container">

   <div class="24">
        <div class="25">forget me</div>
        <div class="26">a target </div>
   </div>
    <div class="27">very desired
        <div class="28">whatever</div>
        <div class="29">another target</div>
    </div>
    <div class="30">go home
         <div class="31">Nothing here</div>
         <div class="32">somewhat desired</div>
    </div>
 </div>
"""

simple_expression = "//*[contains(text(), 'target')]"
driver = Chrome()
driver.get("data:text/html;charset=utf-8,{html_content}".format(html_content=my_str))

e2 = driver.find_elements_by_xpath(simple_expression)
for e in e2:
 print(e.text)

Вывод:

a target
another target
1 голос
/ 06 июня 2019

В случае lxml вы получаете список узлов и перебираете их.

e = root.xpath(simple_expression)
for entry in e:
    print(entry.text)

Где, как и в селене, вы используете find_element, который вернет первый соответствующий элемент. Вот почему вы получаете только один узел. Попробуйте изменить это значение на find_elements и повторите то же самое, что вы сделали в lxml.

Пример кода:

e2 = driver.find_elements_by_xpath(simple_expression)
for e in e2:
 print(e.text)
...