Как получить текст элемента в Selenium WebDriver (через Python api) без включения текста дочернего элемента?

<div id="a">This is some
   <div id="b">text</div>
</div>

Получение "Это некоторые" является нетривиальным. Например, это возвращает "Это какой-то текст":

driver.find_element_by_id('a').text

Как один, в общем, получить текст конкретного элемента без включения его содержимого?

(Я предоставляю ответ ниже, но оставит вопрос открытым, если кто-то может придумать менее отвратительное решение).

Ответ 1

Здесь общее решение:

def get_text_excluding_children(driver, element):
    return driver.execute_script("""
    return jQuery(arguments[0]).contents().filter(function() {
        return this.nodeType == Node.TEXT_NODE;
    }).text();
    """, element)

Элемент, переданный функции, может быть чем-то полученным из методов find_element...() (т.е. может быть объектом WebElement).

Или, если у вас нет jQuery или вы не хотите его использовать, вы можете заменить тело функции выше:

return self.driver.execute_script("""
var parent = arguments[0];
var child = parent.firstChild;
var ret = "";
while(child) {
    if (child.nodeType === Node.TEXT_NODE)
        ret += child.textContent;
    child = child.nextSibling;
}
return ret;
""", element) 

Я действительно использую этот код в тестовом наборе.

Ответ 2

Вам не нужно выполнять замену, вы можете получить длину текста для детей и вычесть из общей длины и отрезать в исходный текст. Это должно быть значительно быстрее.

Ответ 3

def get_true_text(tag):
    children = tag.find_elements_by_xpath('*')
    original_text = tag.text
    for child in children:
        original_text = original_text.replace(child.text, '', 1)
    return original_text