Selenium как найти элемент внутри элемента

I am trying to search for an element in a sub-element with Selenium (Version 2.28.0), but selenium des not seem to limit its search to the sub-element. Am I doing this wrong or is there a way to use element.find to search a sub-element?

For an example I created a simple test webpage with this code:

<!DOCTYPE html>
<html>
    <body>
        <div class=div title=div1>
            <h1>My First Heading</h1>
            <p class='test'>My first paragraph.</p>
        </div>
        <div class=div title=div2>
            <h1>My Second Heading</h1>
            <p class='test'>My second paragraph.</p>
        </div>
        <div class=div title=div3>
            <h1>My Third Heading</h1>
            <p class='test'>My third paragraph.</p>
        </div>
    </body>
</html>

My python (Version 2.6) code looks like this:

from selenium import webdriver

driver = webdriver.Firefox()

# Open the test page with this instance of Firefox

# element2 gets the second division as a web element
element2 = driver.find_element_by_xpath("//div[@title='div2']")

# Search second division for a paragraph with a class of 'test' and print the content
print element2.find_element_by_xpath("//p[@class='test']").text 
# expected output: "My second paragraph."
# actual output: "My first paragraph."

If I run:

print element2.get_attribute('innerHTML')

It returns the html from the second division. So selenium is not limiting its search to element2.

I would like to be able to find a sub-element of element2. This post suggests my code should work Selenium WebDriver access a sub element but his problem was caused by a time-out issue.

Can anyone help me understand what is happening here?

Hi I want to hold element references in files somewhere. and then in run time search for elements withing referenced elements in Selenium how to do that.


For example- a Frame contains multiple text boxes -and multiple frames of similar properties exist where the textboxes are also duplicate. Something like I wanna reference the text box under a particular frame. But i wanna predefine the frame. and the specify that search under that frame[Something like Aliases in Testcomplete]


For Example — similar concept exist in Cheezy’s Page-Objects. but not quite.

asked Jul 12, 2015 at 19:46

Makjb lh's user avatar

1

if you have a structure like this:

<div class='some class'>
  <input class='input-button' value='submit'>Submit</input>
</div>
<div class='some class2'>
  <input class='input-button' value='submit'>Submit</input>
</div>

and you want to find the first ‘Submit’ which is within the ‘some class’ div, you can do this:

parent_element = driver.find_element(:xpath, "//div[@class='some class']")
child_element = parent_element.find_element(:xpath, ".//input")

p.s. this is ruby code.

answered Jul 13, 2015 at 16:05

Nora's user avatar

NoraNora

1,4128 silver badges9 bronze badges

0

We can find an element in a sub-element with Selenium webdriver. First of all we need to identify the element with help of any of the locators like id, class, name, xpath or css. Then we have to identify the sub-element with the findElements(By.xpath()) method.

We can identify the sub-element from the element, by localizing it with the element and then passing the expression (./child::*) as a parameter to the findElements(By.xpath())

Syntax

element.findElements(By.xpath("./child::*"))

Let us identify the tagname of the sub-elements of element ul in below html code−

Example

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.concurrent.TimeUnit;

public class SubElement{
   public static void main(String[] args) {
System.setProperty("webdriver.chrome.driver","C:Usersghs6korDesktopJavachromedriver.exe");
      WebDriver driver = new ChromeDriver();
      driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
      driver.get("https://www.tutorialspoint.com/about/about_careers.htm");
      // identify element
      WebElement t=driver.findElement(By.xpath("//ul[@class='toc chapters']"));
      //identify sub-elements with ./child::* expression in xpath
      List c = t.findElements(By.xpath("./child::*"));
      // iterate sub-elements
      for ( WebElement i : c ) {
         //getTagName() to get tag of sub-elements
         System.out.println(i.getTagName());
      }
      driver.close();
   }
}

Output

При работе с Selenium если элемент на веб-странице не обнаруживаются общеизвестными локаторами locators, использующими значения атрибутов дерева DOM таких как id, class и name, то для его поиска используют либо CSS селекторы, либо локаторы XPath (XML Path).

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

В этом руководстве мы познакомимся с некоторами особенностями языка ХРath применительно к практике использования выражений XPath для поиска сложных или динамически подгружаемых элементов, атрибуты которых также могут динамически изменяться (обновляться).

При рассмотрении примеров, я буду использовать следующий скрипт, который осуществляет поиск элементов на странице поиска Яндекса:

from selenium.webdriver import Chrome
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By

import os
import time
from pprint import pprint

# тестовая страница, на которой мы ищем
target_page = "https://yandex.ru/" 
# то самое выражение XPath, которое мы тестируем
xpath_testing = "//div[contains(@class, 'home-logo')]//child::*"  


dir_current = os.getcwd()
driverLocation = dir_current + "chromedriver.exe"
chrome_options = Options()
chrome_options.add_argument("--headless")

driver = Chrome(driverLocation, chrome_options=chrome_options)
data_text = driver.get(target_page)
time.sleep(3)

try:   
    elements_ = driver.find_elements(By.XPATH, xpath_testing)
    
    for element_ in elements_:
        pprint(f"Выбран элемент с тегом: "{element_.tag_name }"")
        pprint(f"Содержимое атрибута class: "{element_.get_attribute('class')}"")
        pprint(f"Текстовое содержимое элемента: {'Нет содержимого' if not element_.text else element_.text}")   
        
except:
    print('Элемент по заданному XPath выражению не найден :(')
    
finally:
    driver.quit()

Переменной target_page присваивается строковое значение, содержащие адрес страницы, на которой мы будем осуществлять поиск элементов. Критерий поиска будем задавать с использованием XPath выражения, которое также в виде строки присваиваем переменной xpath_testing.

Содержание

  • Коротко о XML и XPath
  • Маршруты поиска
    • Абсолютные пути
    • Относительные пути
    • Подстановочные выражения
  • Предикаты
  • Используем индексы для указания позиции элемента
  • Используем логические операторы OR и AND в выражения XPath
  • Используем функции языка XPath
    • Функция text()
    • Функция contains()
    • Функция starts-with()
    • Функция last()
    • Функция position()
  • Используем полные маршруты поиска элементов
    • Ось предков (ancestor axis)
    • Ось следующих одноуровневых узлов (following-sibling axis)
    • Ось дочерних элементов (child axis)
    • Ось следующих узлов (following axis)
    • Ось предыдущих одноуровневых узлов (preceding-sibling axis)
    • Ось предыдущих узлов (preceding axis)
    • Ось потомков (descendant axis)
    • Ось потомков, включая контекстный узел (descendant-or-self axis)
    • Ось предков, включая контекстный узел (ancestor-or-self axis)

Коротко о XML и XPath

Некоторые разработчики ошибочно полагают, что язык Html является подмножеством XML, но на самом деле это не так, код на обоих языка не возможно комбинировать в одном документе. Так язык XML предназначен для хранения и передачи структурированных данных. В свою очередь HTML предназначен для их более или менее читаемого отображения. Самое существенное различие между HTML и XML в том, что в HTML есть предопределенные элементы и атрибуты, поведение которых так предопределено и ожидаемо, в то время как в XML такого нет. Кроме того существуют определенные различия в синктаксисе инструкций этих внешне схожих языков.

Однако есть у этих двух языков одно основное сходство, которое, в нашем случае, мы можем эффективно использовать для поиска маршрутов к нужным элементам на странице.

  1. HTML и XML документы состоят из элементов, каждый из которых включает «начальный тэг» (<element>), «конечный тэг» (</element>), а также информацию, заключенную между этими двумя тэгами (содержимое элемента).
  2. Элементы могут быть аннотированы атрибутами, содержащими метаданные об элементе и его содержимом.
  3. Любой документ представляет собой дерево, состоящее из узлов (элементов). Некоторые типы узлов могут содержать другие узлы.
  4. Существует единственный корневой узел, который в конечном счете включает в себя все остальные узлы.

Для выбора узлов и наборов узлов дерева документа и последующей обработки Xml использует особый язык XPath. XPath – это отличный от XML язык, используемый для идентификации определенных частей XML документов (элементов страницы). Применительно к html страницам XPath позволяет писать выражения, позволяющие получить, например, ссылку на первый элемент li неупордоченного списка ul, седьмой дочерний элемент третьего элемента div, ссылку а, содержащую строку «Купить по акции» и т. д. XPath позволяет получать ссылки на элементы по их положению на странице (дереве документа), положению относительно другого элемента, тегу, текстовому содержимому и другим критериям.

Согласно методологии XPath существует пять типов узлов, которые могут находиться в дереве документа на обычной html странице:

  1. Корневой узел;
  2. Узлы элементов;
  3. Текстовые узлы;
  4. Узлы атрибутов;
  5. Узлы комментариев.

В дальнейшем при формировании путей поиска к искомым элементам страницы мы будем иметь дело с первыми четырьмя типами узлов. И хотя технически мы можем обратиться, также и к узлу комментариев, расположенного в определенном элементе, рационального применения этой возможности при парсинге страниц нет и поэтому далее рассматриваться не будут.

Маршруты поиска

И хотя выражения XPath в Xml могут также возвращать числа, логические и строковые выражения, то есть производить обработку элементов и их содержимого. В Selenium используется лишь подмножество выражений XPath, называемых маршрутами поиска. Маршруты поиска указывают на определенный узел или набор узлов документа (элементов страницы), отвечающих заданным критериям поиска. Каждый маршрут поиска использует как минимум один шаг для идентификации узла или набора узлов документа. Этот набор может быть пустым, содержать один или содержать несколько узлов. Узел может быть корневым, узлом определенного элемента, атрибута, текста или комментария.

Абсолютные пути

Простейшим маршрутом поиска является тот, который указывает на корневой узел документа (страницы). Этот маршрут представляется простой наклонной чертой / и всегда обозначает одно и то же: корневой узел документа. Каждый документ имеет только один корневой узел, являющийся общим корнем дерева узлов. Корневой узел не имеет родительских узлов. Значением корневого узла является значение элемента документа.

С наклонной черты / всегда начинается абсолютный путь к элементу (маршрут поиска). Получить его можно используя либо специальные расширения браузера, либо так как это делается в браузере Chrome. Вызвать окно Chrome DevTools, выделить нужный элемент, кликнув правой клавишей мыши, вызвать контекстное меню, выбрать команду Copy , а затем Copy full XPath.

Абсолютный путь представляет собой полный и уникальный путь к элементу, начиная от корневого узла. Путь полученный выше описанным способом будет иметь следующий вид:

/html/body/div[1]/div[3]/div[3]/div/edvrt/aqwf/ftgr/fdpprt/fgn/dbgrsae/fwap/fwap/ftgr/div/fgn/dhtaq/div/div/div[1]/div[1]/a/div

Если вы используете в качестве тестируемого выражения XPath этот путь, и запустите на выполнение скрипт приведенный выше, то получите ссылку на логотип Яндекса, который находится на главной странице поисковика.

Абсолютный путь, по аналогии с абсолютным путем к любому файлу в файловой системе операционной системы, всегда однозначно указывает на нужный элемент. Однако у него есть один существенный недостаток: если разметка страницы изменится, то он с большой вероятностью может перестать работать. Особенно это актуально если на странице используется много различных интерактивных возможностей Javascript или анимаций элементов.

Отметим, что корневой элемент страницы имеет абсолютный путь (маршрут) /html и если в качестве XPath выражения мы введем просто ‘/’, то будет возбуждено исключения типа InvalidSelectorException с сообщением «Селектор некоректен. Результат поиска с использованием XPath выражения не возвратил объект элемента. Элемент не найден».

Вывод. Символ / объединяет различные шаги в составной маршрут поиска. Каждый шаг в маршруте является относительным по отношению к предшествующему. Если маршрут начинается с /, то путь является абсолютным, а его первый шаг является относительным по отношению к корневому узлу.

Относительные пути

Относительный путь начинается с двух наклонных черт и следующим за ним одиночным тегом нужного нам элемента. Он может идентифицировать элементы в любом месте веб-страницы. И это позволяет избегать необходимости писать весь длинный абсолютный XPath путь, и вы можете начать его с середины структуры документа страницы (DOM). Он позволяет выбрать все элементы, по заданному тегу на странице, удовлетворяющие указанному критерию поиска. Например, выражение XPath //li ссылается на все элементы li находящиеся на странице (в дереве DOM). Так относительный путь к логотипу Яндекса на странице поиска будет выглядеть следующим образом:

//div[@role = 'img']

Пусть вас пока не смущает выражение в квадратных скобках. Они называются предикатами и служат для сужения диапазона поиска элементов, то есть придания специфичности нашему маршруту поиска. Синтаксис предикатов и их использование мы рассмотрим в нашем руководстве далее. А пока отметим, выражение в квадратных скобках говорит нам о том, что искомый элемент div, должен иметь атрибут role со значением img.

Логично было бы думать, что при задании относительных путей можно задавать начальную точку поиска нужных элементов страницы или, как принято говорить в терминологии XPath контекстный узел. В этом случае маршрут поиска будет иметь следующий вид:

//ol[@class = 'list news__list']/li/a

Это XPath выражение позволяет получить пути к ссылкам из списка новостей, размещенного на главной странице поисковика Яндекс. Отметим, этот маршрут получился намного короче чем маршрут, использующий абсолютный путь, а также более понятна его логика. Также отметим, что значение атрибута класса элемента упорядоченного списка ol представляет собой строковое значение состоящее из двух имен соответствующих CSS классов. Если вы укажете в выражении наименование только одного из них, например, так //ol[@class = 'news__list'] ,то получите пустой набор элементов.

Попробуем теперь переписать выражение выше следующим образом:

//ol[@class='list news__list']//a

И мы получим точно такой же результат, как и для выражения выше. Фактически мы заменили все промежуточные элементы из пути к ссылкам на две наклонные черты // и упростили его вид. Таким образом можно убирать из пути к искомому элементу любое количество промежуточных шагов (элементов).

Вывод. В начале выражения XPath символы // по сути позволяют выбрать всех потомков корневого узла с указанным тегом. Например, выражение XPath //div выбирает в документе все элементы div. Если мы будем использовать символ // в маршруте для разделения отдельных шагов, то можем опускать промежуточные шаги сокращая при этом запись маршрута. Относительный путь Xpath всегда предпочтительнее, так как он является более логичным и понятным, а также устойчивым к динамическому изменению структуры дерева DOM страницы средствами движка Javascript.

Подстановочные выражения

Подстановочные выражения позволяют выбирать несколько типов элементов одновременно. Существуе два следующих вида подстановочных выражений, которые выможете использовать при парсинге страниц: * , @ *.

Звездочка * или астерикс соответствует любому узлу элемента, независимо от его типа. Звездочка * является одним из наиболее часто используемых подстановочных выражений, используемых в XPath выражениях в Selenium.

Символ @ указывает, что слдующий за ним идентификатор является наименованием атрибута элемента и используется для задания предикатов. Так выражение @ * мы можем использовать вместо любого имени атрибута.

Приведем некоторые примеры их использования.

  • //* – соответствует всем элементам, находящимся на странице (включая тег html).
  • //div/* – соответствует всем элементам, являющимися непосредственными потомками элемента с тегом div .
  • //input[@*] – соответствует всем элементам с тегом input, которые имеют хотя бы один любой атрибут, при этом значение атрибута может быть любым, присутствовать или отсутствовать.
  • //*[@*] – соответствует всем элементам на странице, имеющим хотя бы один атрибут.

Предикаты

Как мы уже знаем, что в общем случае выражение XPath может ссылаться более чем на один узел (элемент страницы), то есть метод, в котором оно используется будет возвравращать массив элементов. Иногда это именно то, что нам нужно, однако в некоторых случаях приходится «просеивать» его по определенным критериям, чтобы выбрать только некоторые из них. Для этих целей в XPath используется синктаксис предикатов. Каждый шаг в маршруте поиска может иметь свой предикат или даже несколько, который задает свой критерий выбора из текущего списка узлов на каждом шаге маршрута поиска. То есть на каждом шаге поиска могут существовать один или более предикатов. По сути предикат содержит логическое выражение, которое проверяется для каждого узла в полученном по указанному пути наборе элементов страницы. Если выражение ложно, этот узел удаляется из набора, в противном случае соответствено сохраняется.

Предикат – это часть выражения XPath, заключенная в квадратные скобки, которое следует в инструкции для шага поиска за критерием выбора узла (элемента). В общем виде выражение с предикатом будет выглядеть следующим образом:

//выбор_элементов[правило_предиката1][правило_предиката2][правило_предиката3]  

Предположим, требуется найти кнопку для отправки поискового запроса на главной странице Яндекса. XPath выражение, которое позволяет это осуществить будет выглядеть следующим образом:

//div[@class='search2__button']/button[@role='button'] 

В начале на первом шаге выбираем все элементы div, для которых справедливо следующее логическое значение предиката: значение атрибута класса соответствует строке search2__button. На втором шаге выбираем у них элементы с тегом button, являющиеся их непосредственными потомками, у которых значение атрибута role содержит строковое значение button.

В следующем примере выбираем ссылку на корзину Яндекс Маркет, которая находится также на основной странице поисковика. Использование нескольких атрибутов в выражении XPath сужает поиск нужного элемента на странице до одного.

//а[@title='Корзина на Маркете'][@class='home-link market-cart']

Вывод. Механизм предикатов весьма полезен для сужения диапазона выбираемых на странице элементов по заданным критериям, который основан на логических выражениях. Используя предикаты мы можем задавать сколь угодно специфичные идентификаторы для искомых элементов.

Используем индексы для указания позиции элемента

С помощью синтаксиса индексов можно выбрать из набора элементов нужный, указав его номер в квадратных скобках по аналогии с синтаксисом массивов. В примере ниже мы получаем третий элемент из списка новостей на странице Яндекса.

//ol[@class='list news__list']/li[2]
//ol[@class='list news__list']/li[2]//span[@class='news__item-content']

Второе выражение XPath позволянт получить у выбранного элемента списка элемент с тегом span, который содержит текстовое содержимое заголовока новости. Отметим, что индексы элементов начинают отсчитываться от 1, а не от 0, как принято для индексации массивов в языке Python.

Используем логические операторы OR и AND в выражения XPath

Логические оператры используются в инструкциях предикатов для комбинирования критериев поиска нужных элементов на странице.

В примере ниже приведены выражения для фильтрации ссылок на новости, которые показывают на странице поиска Яндекс.

//a[@rel='noopener' or @target='_blank']
//a[@rel='noopener' and @target='_blank']
//a[@rel='noopener' and @target='_blank' and contains(@class, 'home-link_black_yes')]

Как видно в предикате для фильтрации элементов можно применять сколько угодно логических операторов, а также комбинировать их с XPath функциями, которые рассмотрим ниже.

Функция text()

Функция XPath text() – это встроенная в синтаксис XPath Selenium функция, которая используется для поиска элементов на основе строкового значения, содержащегося в его текстовом узле. То есть если элемент имеет текстовое содержимое в виде строки, то элемент можно найти следующим образом:

<span class="button__text">Найти</span>
​
//span[text()='Найти']

Функция contains()

Функция contains() часто используется в предикатах выражений XPath для случаев если значение атрибута элемента или его текстовое содержимое может динамически изменяться.

Например в значение атрибута класса элемента //element[@class='class1 class2'] средствами Javascript может быть добавлен для его анимации класс class3, а потом также динамически убран. При этом значение предиката в случае добавления нового класса станет ложным, то есть элемент не будет выбран. Для этого случая мы можем использовать функцию contains() следующим образом:

//element[contains(@class, 'class1 class2')]

Если выражение выбора элемента переписать в указанном выше виде, то мы ориентируясь на атрибут класса элемента будем выбирать его в любом случае.

Функция contains() позволяет находить элемент по текстовой подстроке значения атрибута или его текстового содержимого, как показано в примере XPath ниже.

//a[contains(@title, 'Корзина')]
//span[contains(text(),'Найти')]

В примере мы нашли ссылку на корзину Яндекс маркета из примера выше по части значения атрибута title. А также по части текстового содержимого кнопку отправки запроса поисковику.

Функция starts-with()

Эта функция используется если нам известна первая часть (начальная подстрока) текстового содержимого искомого элемента на странице, либо часть значения его атрибута.

//a[starts-with(@title, 'Корзина')]
//span[starts-with(text(),'Найти')]

Функция last()

Эта функция позволяет выбрать последний элемент (указанного типа) из набора элементов. Пример ее использования представлен ниже.

//ol[@class='list news__list']/li[last()]//span[@class='news__item-content']

Это выражение возвращает элемент, содержащий наименование последней новости из списка новостей со страницы поисковика Яндекс.

В следующем примере показано как можно получить предпоследнюю новость.

//ol[@class='list news__list']/li[last()-1]//span[@class='news__item-content']

Функция position()

Эта функция позволяет выбирать из полученного набора элементы в зависимости от указанного номера позиции. Начало отсчета позиции элемента, по аналогии с индексами также начинается с 1. Действие этой функции полностью идентично индексам, о которых мы говорили выше. В примере ниже представлены два эквивалентных по результату выполнения выражения.

//ol[@class='list news__list']/li[position()=1]"))
//ol[@class='list news__list']/li[1]

Используем полные маршруты поиска элементов

До этого момента мы говорили о том, что в терминологии языка XPath называется сокращенными маршрутами поиска. Эти маршруты значительно проще для набора, менее многословны и знакомы большинству разработчиков. Кроме того, они являются именно теми выражениями XPath, которые лучше всего подходят для использования в простейших шаблонов поиска. Однако в XPath также предлагается полный синтаксис для маршрутов поиска, который более многословен, но, возможно, менее загадочен и определенно более гибок.

Так каждый шаг в полном маршруте поиска имеет две обязательные части: так называю ось и критерий узла (тег элемента), а также необязательную часть – предикаты. Ось указывает направление перемещения от контекстного узла для поиска следующих узлов. Критерий узла определяет, какие узлы будут выбраны на текущем шаге поиска вдоль этой оси. В полном маршруте они разделяются двумя двоеточиями ::.

По сути в сокращенном маршруте поиска ось и критерий узла объединены вместе. Например, следующий сокращенный маршрут поиска состоит из трех шагов.

//ol/li/a[@rel='noopener']

Первый шаг выбирает на странице элементы упорядоченных списков ol по оси дочерних узлов, второй – элементы li вдоль оси дочерних узлов, третий шаг – так же по оси дочерних узлов выбирает элементы ссылок a, а затем с помощью предиката выбирает из них только содержащие атрибут rel='noopener' с заданным значением . Если переписать это выражение в полной форме тот же маршрут поиска будет выглядеть следующим образом:

//child::ol/child::li/child::a[@rel='noopener']

Полные несокращенные маршруты поиска, как и сокращенные, могут быть также абсолютными, если начинаются с корневого узла.

В целом полная форма очень многословна и мало используется на практике. Однако она предоставляет одну исключительную возможность, которая делает эту форму записи XPAth выражений достойной внимания. Это единственный способ использования направлений осей поиска, по которым выражения XPath осуществляют выбор нужных элементов.

Так сокращенный синтаксис позволяет перемещаться по оси непосредственно дочерних узлов (child), оси атрибутов (attribute) и оси всех его потомков с включением контекстного узла (descendant-or-self). Полный синтаксис добавляет еще восемь осей, которые применимы для использования в XPath выражениях и поиска элементов на страницах с использованием Selenium:

Ось предков (ancestor axis)

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

//div[text()='Маркет']//ancestor::a
//div[text()='Маркет']//ancestor::*

В данном примере мы получаем ссылку на Яндекс Маркет по текстовому содержимому элемента div находящегося внутри нее. А следующее выражение позволяет выбрать последовательность всех предков этого элемента до корня документа /html.

Ось следующих одноуровневых узлов (following-sibling axis)

Все узлы элементов страницы, следующие за контекстным узлом и содержащиеся в том же узле родительского элемента, в том же порядке, в каком элементы расположены в документе.

//div[contains(@class, 'home-logo')]//following-sibling::div

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

Ось дочерних элементов (child axis)

Ось содержит все дочерние узлы текущего контекстного, то есть выбирает все элементы, содержащиеся в текущем узле. В примере ниже будут выбраны все элементы находящиеся внутри блока div содержащего логотип Яндекса.

//div[contains(@class, 'home-arrow__search-wrapper')]//child::*

Ось следующих узлов (following axis)

Все узлы, следующие после контекстного узла, в том же порядке, в каком узлы присутствуют в документе. Отличием поиска вдоль этой оси от оси following-sibling является то, что будут выбраны все узлы (элементы) находящиеся в документе за закрывающим тегом контекстного узла. Так в аналогичном примере ниже будут выбраны все элементы div, следующие в документе за разметкой логотипа Яндекс. Сравните результаты поиска с примером выше.

//div[contains(@class, 'home-logo')]//following::div

Ось предыдущих одноуровневых узлов (preceding-sibling axis)

Выбирает все узлы, предшествующие контекстному узлу и содержащиеся в том же узле родительского элемента последовательно в обратном порядке.

//div[contains(@class, 'search2__input')]//preceding-sibling::input[@type='hidden']

В этом примере выражение позволяет выбрать скрытые поля в блоке со строкой основного поиска Яндекса.

Ось предыдущих узлов (preceding axis)

Все узлы, предшествующие началу контекстного узла, в порядке, обратном порядку в документе. Отличием поиска вдоль этой оси от оси following-sibling является то, что будут выбраны все узлы (элементы) находящиеся в документе перед открывающим тегом контекстного узла. Так в аналогичном примере ниже будут выбраны все элементы div, следующие в документе перед разметкой логотипа Яндекс. Сравните результаты поиска с примерами выше.

//div[contains(@class, 'home-logo')]//preceding::div

Ось потомков (descendant axis)

Поиск вдоль оси потомков descendant выбирает все дочерние элементы, а также их дочерние элементы «внуков». В примере ниже мы выбираем все элементы находящиеся в блоке со строкой поиска на главной странице Яндекса.

//div[contains(@class, 'home-arrow__search-wrapper')]//descendant::*

Ось потомков, включая контекстный узел (descendant-or-self axis)

Ее действие аналогично оси потомков descendant за исключением того, в набор будет включен и сам контекстный узел.

//div[contains(@class, 'home-arrow__search-wrapper')]//descendant-or-self ::*

Ось предков, включая контекстный узел (ancestor-or-self axis)

Все предки контекстного узла, включая сам контекстный узел. В примере ниже будут выбраны все предки элемента div блока с логотипом Яндекса, а также сам элемент.

//div[contains(@class, 'home-arrow__search-wrapper')]//ancestor-or-self::*

В этой статье мы рассмотрели основы использования синтаксиса XPath при составлении выражений для поиска элементов на странице. Отличительной особенностью такого поиска является то, что используется информация о структуре документа страницы, что позволяет более гибко составлять выражения маршрутов к искомым элементам в любом направлении от заданного контекстного узла. В отличии от использования CSS селекторов, которые позволяю осуществлять поиск только в глубину, выражения XPath позволяют выбирать как родительские узлы так и узлы предков выше до любого уровня вложенности.

Использование функций языка XPath позволяет находить элементы как по их текстовому содержимому, так и по содержимому их атрибутов. Существенно расширяют их возможности возможность использования логических выражений для комбинирования различных условий формирования маршрута поиска.

Надеюсь, что это руководство поможет вам разобраться с принципом использования XPath выражений при работе в Selenium Python. А также в дальнейшем послужит справочным пособием для разработки.

#1

fenixx

    Новый участник

  • Members
  • Pip

  • 29 сообщений
  • Город:Москва

Отправлено 14 мая 2014 — 13:30

Selenium v.2.41.0.0

Драйвер использую FirefoxDriver

Поиск элемента по XPath в элементе по XPath.

Пример:

// Получаю коллекцию
var tabs = D.FindElementsByXPath(XPathTabs); - работает

// Обращаюсь ко второму элементу в коллекции, и ищу внутри его все теги "а" через By.XPath
var tab3 = tabs[1].FindElements(By.XPath(@"//a")); // НЕ работает как надо. Возвращает коллекцию всех ссылок на странице

// Обращаюсь ко второму элементу в коллекции, и ищу внутри его все теги "а" через By.TagName.
var tab2 = tabs[1].FindElements(By.TagName("a")); // работает как надо. Возвращает коллекцию тегов "а" внутри "tabs[1]"

// Обращаюсь ко второму элементу в коллекции, и ищу внутри его все теги "а" через By.XPath
var tab3 = tabs[1].FindElements(By.XPath(@"./*" + "//a")); // работает как надо. Возвращает коллекцию тегов "а" внутри "tabs[1]"

Не понимаю почему при таком XPath-е:

XPath проверяю в FireFoxe через расширение FirePath

./*//a — возвращает коллекцию внутри элемента. — ничего не находит при проверке через FirePath

//a — А при таком ищет на всей странице

Подскажите почему так и буду очень благодарен, если ссылки предоставите где это будет описано.

  • 0

  • Наверх


#2

vmaximv

Отправлено 14 мая 2014 — 13:44

http://www.w3.org/TR/xpath/#node-tests

// is short for /descendant-or-self::node()/. For example, //para is short for /descendant-or-self::node()/child::para and so will select any para element in the document (even a para element that is a document element will be selected by //para since the document element node is a child of the root node); div//para is short for div/descendant-or-self::node()/child::para and so will select all para descendants of div children.

A location step of . is short for self::node(). This is particularly useful in conjunction with //. For example, the location path .//para is short for
self::node()/descendant-or-self::node()/child::para

and so will select all para descendant elements of the context node.

Или на примерах

//para selects all the para descendants of the document root and thus selects all para elements in the same document as the context node
.//para selects the para element descendants of the context node

  • 0

  • Наверх


#3

fenixx

fenixx

    Новый участник

  • Members
  • Pip

  • 29 сообщений
  • Город:Москва

Отправлено 14 мая 2014 — 14:24

http://www.w3.org/TR/xpath/#node-tests
 

// is short for /descendant-or-self::node()/. For example, //para is short for /descendant-or-self::node()/child::para and so will select any para element in the document (even a para element that is a document element will be selected by //para since the document element node is a child of the root node); div//para is short for div/descendant-or-self::node()/child::para and so will select all para descendants of div children.

A location step of . is short for self::node(). This is particularly useful in conjunction with //. For example, the location path .//para is short for
self::node()/descendant-or-self::node()/child::para

and so will select all para descendant elements of the context node.

Или на примерах

//para selects all the para descendants of the document root and thus selects all para elements in the same document as the context node
.//para selects the para element descendants of the context node

Почему тогда это работает правильно Driver.FindElementsByXPath(@»//div»)[1].FindElement(By.XPath(@»//a»))?

На сколько понимаю, FindElements если применяется к указанному элементу, то и поиск в указанном элементе должен проходить.

Получается что в Seleniume для FindElement и FindElements — нужно использовать разное написание XPath селекторов при поиске внутри элемента, т.к. этот вариант работать уже не будет Driver.FindElementsByXPath(@»//div»)[1].FindElement(By.XPath(@»./*//a»))

Не понимаю почему в FindElement и FindElements работает по разному?

Где это может пригодиться при использовании?

  • 0

  • Наверх


#4

vmaximv

Отправлено 14 мая 2014 — 15:47

Повезло! =работает правильно. В плане механики между findElements и findElement разницы нету.
Если нашли разницу — давайте код и сорс, т. к. либо вы заблуждаетесь, либо это баг.

  • 0

  • Наверх


#5

fenixx

fenixx

    Новый участник

  • Members
  • Pip

  • 29 сообщений
  • Город:Москва

Отправлено 15 мая 2014 — 06:24

Повезло! =работает правильно. В плане механики между findElements и findElement разницы нету.
Если нашли разницу — давайте код и сорс, т. к. либо вы заблуждаетесь, либо это баг.

  • 0

  • Наверх


#6

fenixx

fenixx

    Новый участник

  • Members
  • Pip

  • 29 сообщений
  • Город:Москва

Отправлено 15 мая 2014 — 06:50

Повезло! =работает правильно. В плане механики между findElements и findElement разницы нету.
Если нашли разницу — давайте код и сорс, т. к. либо вы заблуждаетесь, либо это баг.

Прикрепленный файл
 15-05-2014 9-40-44.png   18,47К
  3 Количество загрузок:

string XPathActivityTab = @"//*[@id='PortfolioEditFormtab1']";
string XPathAllLabel = @"//*[contains(@class,'control-label')]";
string XPathParent = @"/..";

var AllControls = D.FindElementsByXPath(XPathActivityTab + XPathAllLabel + XPathParent);
var sel1 = AllControls[0].FindElement(By.XPath(@"//*[contains(@class,'control-label')]"));
var sel11 = AllControls[0].FindElements(By.XPath(@"//*[contains(@class,'control-label')]"));
var sel22 = AllControls[0].FindElements(By.XPath(@"./*//*[contains(@class,'control-label')]"));
var sel222 = AllControls[0].FindElement(By.XPath(@"/./*" + @"//*[contains(@class,'control-label')]"));// Если так то работает
var sel2 = AllControls[0].FindElement(By.XPath(@"./*" + @"//*[contains(@class,'control-label')]")); // Выдает ошибку

Прикрепленный файл
 15-05-2014 10-22-02.png   134,99К
  0 Количество загрузок:

var tabs = D.FindElementsByXPath(@"//*[@id='tabs']");
var sel1  = tabs[1].FindElement(By.XPath(@"//a"));
var sel2  = tabs[1].FindElement(By.XPath(@"./*//a"));
var sel11 = tabs[1].FindElements(By.XPath(@"//a"));
var sel22 = tabs[1].FindElements(By.XPath(@"./*//a")); // Отрабатывает без ошибки 

Страница HTML

Прикрепленный файл
 Test.7z   273,72К
  2 Количество загрузок:

Почему отрабатывает по разному, и как с этим быть?

  • 0

  • Наверх


#7

vmaximv

Отправлено 15 мая 2014 — 07:23

Отрабатывает одинаково и ошибки выдает правильно. «./*//*[contains(@class,’control-label’)]» — нет такого элемента, и findElements выдает size==0, а findElement эксепшен.
Еще раз: если вы используете findElement[s] и xpath в контексте WebElement, то:
1. Если xpath начинается с «./» — поисковым контентом будет являться искомый WebElement
2. Если xpath начинается с «/» — поисковым контентом будет являться root документа.

  • 2

  • Наверх


#8

fenixx

fenixx

    Новый участник

  • Members
  • Pip

  • 29 сообщений
  • Город:Москва

Отправлено 15 мая 2014 — 08:15

Отрабатывает одинаково и ошибки выдает правильно. «./*//*[contains(@class,’control-label’)]» — нет такого элемента, и findElements выдает size==0, а findElement эксепшен.
Еще раз: если вы используете findElement[s] и xpath в контексте WebElement, то:
1. Если xpath начинается с «./» — поисковым контентом будет являться искомый WebElement
2. Если xpath начинается с «/» — поисковым контентом будет являться root документа.

Большое спасибо за разъяснение!!!

var AllControls = D.FindElementsByXPath(@"//*[@id='PortfolioEditFormtab1']//*[contains(@class,'control-label')]/.."); 
string Selector = @"//*[contains(@class,'control-label')]");
var sel222 = AllControls[0].FindElement(By.XPath(@"." + Selector);//Так все работает верно )))Огромное спасибо!!!

  • 0

  • Наверх


Понравилась статья? Поделить с друзьями:
  • Как составить график консультаций
  • Как найти номер счета по номеру телефона
  • Attackers might be trying to steal your information from как исправить
  • Как найти частное решение системы линейных уравнений
  • Как найти длину волны в другой среде