Введение в локаторы Selenium WebDriver
Что такое локаторы и зачем они нужны?
Локаторы в Selenium WebDriver — это механизмы, позволяющие однозначно идентифицировать веб-элементы на странице. Они служат своеобразными координатами для Selenium, указывающими, какой именно элемент необходимо задействовать для выполнения тех или иных действий, таких как клик, ввод текста или чтение данных.
Роль локаторов в автоматизации тестирования
Автоматизация тестирования веб-приложений невозможна без надежных локаторов. Без них Selenium не сможет взаимодействовать с элементами интерфейса, что сделает автоматизацию бессмысленной. Правильно подобранные локаторы обеспечивают стабильность и надежность тестов, снижая количество ложных срабатываний и поддерживая актуальность тестового набора при изменениях в структуре веб-страницы.
Обзор Selenium WebDriver и его взаимодействие с веб-элементами
Selenium WebDriver – это инструмент для автоматизированного управления браузером. Он позволяет имитировать действия пользователя, такие как открытие страниц, заполнение форм, нажатие кнопок и т.д. Взаимодействие с веб-элементами осуществляется через объект WebElement
, который получается в результате поиска элемента по определенному локатору. WebDriver
использует локаторы для нахождения нужного WebElement
, после чего можно вызывать методы WebElement
(например, .click()
, .sendKeys()
, .getText()
).
Типы локаторов в Selenium WebDriver
Selenium WebDriver предоставляет несколько типов локаторов, отличающихся способом идентификации веб-элементов. Каждый тип имеет свои преимущества и недостатки, а также области применения.
ID: Поиск элемента по атрибуту ID
Самый быстрый и надежный способ поиска элемента, если у него есть уникальный id
.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
def find_element_by_id(driver: WebDriver, element_id: str) -> WebElement:
"""Находит элемент по его ID.
Args:
driver: Экземпляр WebDriver.
element_id: ID элемента.
Returns:
WebElement: Найденный элемент.
Raises:
NoSuchElementException: Если элемент с указанным ID не найден.
"""
element: WebElement = driver.find_element(By.ID, element_id)
return element
# Пример использования:
# element = find_element_by_id(driver, "login-button")
# element.click()
Name: Поиск элемента по атрибуту Name
Используется, когда у элемента есть атрибут name
. Не всегда уникален, поэтому может возвращать список элементов. В таком случае, нужно брать первый (или нужный по индексу).
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from typing import List
def find_elements_by_name(driver: WebDriver, element_name: str) -> List[WebElement]:
"""Находит все элементы по атрибуту name.
Args:
driver: Экземпляр WebDriver.
element_name: Значение атрибута name.
Returns:
List[WebElement]: Список найденных элементов.
"""
elements: List[WebElement] = driver.find_elements(By.NAME, element_name)
return elements
# Пример использования:
# elements = find_elements_by_name(driver, "user_email")
# if elements:
# elements[0].send_keys("test@example.com")
ClassName: Поиск элемента по атрибуту ClassName
Аналогично Name
, может возвращать список элементов. Часто используется для стилизованных элементов.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from typing import List
def find_elements_by_class_name(driver: WebDriver, class_name: str) -> List[WebElement]:
"""Находит все элементы по имени класса.
Args:
driver: Экземпляр WebDriver.
class_name: Имя класса.
Returns:
List[WebElement]: Список найденных элементов.
"""
elements: List[WebElement] = driver.find_elements(By.CLASS_NAME, class_name)
return elements
# Пример использования:
# elements = find_elements_by_class_name(driver, "btn")
# for element in elements:
# print(element.text)
TagName: Поиск элемента по тегу
Находит элементы по тегу, например, input
, div
, a
. Практически всегда возвращает список элементов. Редко используется сам по себе, чаще в комбинации с другими локаторами.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
from typing import List
def find_elements_by_tag_name(driver: WebDriver, tag_name: str) -> List[WebElement]:
"""Находит все элементы по имени тега.
Args:
driver: Экземпляр WebDriver.
tag_name: Имя тега.
Returns:
List[WebElement]: Список найденных элементов.
"""
elements: List[WebElement] = driver.find_elements(By.TAG_NAME, tag_name)
return elements
# Пример использования:
# inputs = find_elements_by_tag_name(driver, "input")
# print(f"Найдено {len(inputs)} input элементов")
LinkText: Поиск элемента по полному тексту ссылки
Используется для поиска ссылок (<a>
) по их точному текстовому содержимому.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
def find_element_by_link_text(driver: WebDriver, link_text: str) -> WebElement:
"""Находит элемент ссылки по полному тексту.
Args:
driver: Экземпляр WebDriver.
link_text: Полный текст ссылки.
Returns:
WebElement: Найденный элемент.
Raises:
NoSuchElementException: Если элемент с указанным текстом ссылки не найден.
"""
element: WebElement = driver.find_element(By.LINK_TEXT, link_text)
return element
# Пример использования:
# element = find_element_by_link_text(driver, "Подробнее")
# element.click()
PartialLinkText: Поиск элемента по частичному тексту ссылки
Аналогичен LinkText
, но ищет ссылки по частичному совпадению текста.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
def find_element_by_partial_link_text(driver: WebDriver, partial_link_text: str) -> WebElement:
"""Находит элемент ссылки по частичному тексту.
Args:
driver: Экземпляр WebDriver.
partial_link_text: Частичный текст ссылки.
Returns:
WebElement: Найденный элемент.
Raises:
NoSuchElementException: Если элемент с указанным частичным текстом ссылки не найден.
"""
element: WebElement = driver.find_element(By.PARTIAL_LINK_TEXT, partial_link_text)
return element
# Пример использования:
# element = find_element_by_partial_link_text(driver, "Подроб"))
# element.click()
XPath: Поиск элемента с использованием XPath-выражений
Мощный инструмент для поиска элементов, позволяющий строить сложные запросы, основываясь на структуре DOM, атрибутах и текстах. Подробнее об XPath ниже.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
def find_element_by_xpath(driver: WebDriver, xpath: str) -> WebElement:
"""Находит элемент по XPath выражению.
Args:
driver: Экземпляр WebDriver.
xpath: XPath выражение.
Returns:
WebElement: Найденный элемент.
Raises:
NoSuchElementException: Если элемент по указанному XPath не найден.
"""
element: WebElement = driver.find_element(By.XPATH, xpath)
return element
# Пример использования:
# element = find_element_by_xpath(driver, "//div[@id='content']/h1")
# print(element.text)
CSS Selector: Поиск элемента с использованием CSS-селекторов
Альтернатива XPath, также позволяющая строить сложные запросы к элементам. Обычно немного быстрее XPath. Подробнее о CSS Selector ниже.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium.webdriver.remote.webelement import WebElement
def find_element_by_css_selector(driver: WebDriver, css_selector: str) -> WebElement:
"""Находит элемент по CSS селектору.
Args:
driver: Экземпляр WebDriver.
css_selector: CSS селектор.
Returns:
WebElement: Найденный элемент.
Raises:
NoSuchElementException: Если элемент по указанному CSS селектору не найден.
"""
element: WebElement = driver.find_element(By.CSS_SELECTOR, css_selector)
return element
# Пример использования:
# element = find_element_by_css_selector(driver, "div#content > h1")
# print(element.text)
XPath: Подробное руководство
XPath (XML Path Language) – язык запросов для навигации по XML-документам, который также отлично подходит для HTML, так как HTML является разновидностью XML. Он позволяет точно указывать путь к элементу в DOM-дереве.
Абсолютный и относительный XPath
- Абсолютный XPath: Начинается с корневого элемента (
/html
) и указывает полный путь к элементу. Очень хрупкий, так как любое изменение в структуре страницы сломает локатор. Например:/html/body/div[1]/div/div/div/div[2]/form/div[1]/input
- Относительный XPath: Начинается с
//
, что означает поиск элемента в любом месте документа. Более гибкий и устойчивый к изменениям. Например://input[@id='username']
Использование атрибутов в XPath
Атрибуты элемента можно использовать для уточнения поиска. Например: //input[@type='text' and @name='email']
Использование функций XPath (contains, text, starts-with и др.)
contains(attribute, value)
: Проверяет, содержит ли атрибут указанное значение. Например://a[contains(@href, 'example.com')]
text()
: Получает текстовое содержимое элемента. Например://h1[text()='Welcome']
starts-with(attribute, value)
: Проверяет, начинается ли атрибут с указанного значения. Например://img[starts-with(@src, '/images/')]
Примеры сложных XPath-выражений
- Найти родительский элемент:
//button[@id='submit']/parent::div
- Найти следующий элемент-брат:
//h2[@class='title']/following-sibling::p
- Найти предыдущий элемент-брат:
//div[@id='content']/preceding-sibling::h1
Преимущества и недостатки использования XPath
- Преимущества: Гибкость, возможность поиска по сложным критериям, доступ к любому элементу. Полезен когда другие локаторы не работают.
- Недостатки: Может быть медленным, особенно сложные запросы. Абсолютные XPath очень хрупкие. Сложность в написании и поддержке.
CSS Selector: Подробное руководство
CSS (Cascading Style Sheets) селекторы – это шаблоны, используемые для выбора элементов HTML для применения стилей. Selenium WebDriver также использует CSS селекторы для поиска элементов.
Основные CSS-селекторы (по тегу, классу, ID)
tagname
: Выбирает все элементы с указанным тегом. Например:p
(выберет все параграфы)..classname
: Выбирает все элементы с указанным классом. Например:.highlight
(выберет все элементы с классомhighlight
).#id
: Выбирает элемент с указанным ID. Например:#login-form
(выберет элемент с IDlogin-form
).
Атрибутивные селекторы
[attribute]
: Выбирает все элементы с указанным атрибутом. Например:[title]
(выберет все элементы с атрибутомtitle
).[attribute=value]
: Выбирает все элементы с указанным атрибутом и значением. Например:[type='text']
(выберет все элементы с атрибутомtype
равнымtext
).[attribute*=value]
: Выбирает все элементы, атрибут которых содержит указанное значение. Например:[href*='example.com']
.[attribute^=value]
: Выбирает все элементы, атрибут которых начинается с указанного значения. Например:[src^='/images/']
.[attribute$=value]
: Выбирает все элементы, атрибут которых заканчивается указанным значением. Например:[src$='.jpg']
.
Псевдоклассы и псевдоэлементы
:hover
: Выбирает элемент при наведении курсора. В Selenium использовать нельзя.:focus
: Выбирает элемент в фокусе. В Selenium использовать нельзя.::before
: Вставляет контент перед элементом. В Selenium использовать нельзя.::after
: Вставляет контент после элементом. В Selenium использовать нельзя.
Комбинаторы (потомки, дочерние элементы, смежные и общие сестры)
element1 element2
: Выбирает все элементыelement2
, являющиеся потомкамиelement1
.element1 > element2
: Выбирает все элементыelement2
, являющиеся дочерними элементамиelement1
.element1 + element2
: Выбирает элементelement2
, непосредственно следующий заelement1
.element1 ~ element2
: Выбирает все элементыelement2
, следующие заelement1
на том же уровне.
Преимущества и недостатки использования CSS-селекторов
- Преимущества: Обычно быстрее XPath. Более простой синтаксис. Легче читаются и поддерживаются.
- Недостатки: Менее гибкие, чем XPath. Нельзя перемещаться вверх по DOM-дереву (к родительским элементам).
Приоритет локаторов и рекомендации по выбору
Ранжирование локаторов по стабильности и производительности
В порядке убывания приоритета (от наиболее предпочтительного к наименее):
ID
Name
CSS Selector
LinkText
/PartialLinkText
ClassName
TagName
XPath
Когда использовать ID, Name, ClassName и TagName
ID
: Если у элемента есть уникальный и стабильныйid
, это лучший выбор. Быстрый и надежный.Name
: Подходит для элементов форм, особенно еслиid
отсутствует. Проверяйте уникальностьname
.ClassName
: Используйте, когда нужно найти элементы с определенным стилем или поведением. Учитывайте, что классы могут меняться.TagName
: Используйте только в сочетании с другими локаторами для уточнения поиска, например, для поиска всехinput
внутри определенногоdiv
.
Когда использовать LinkText и PartialLinkText
Используйте для поиска ссылок, когда нужно кликнуть на конкретную ссылку или проверить ее наличие.
Когда использовать XPath и CSS Selector
Используйте, когда другие локаторы не подходят. CSS Selector
предпочтительнее XPath
из-за скорости и простоты синтаксиса, но XPath
более гибок.
Лучшие практики выбора локаторов для повышения надежности тестов
- Избегайте абсолютных XPath.
- Используйте относительные XPath или CSS-селекторы.
- Старайтесь использовать наиболее специфичные атрибуты.
- Избегайте локаторов, зависящих от позиционирования элементов (например,
nth-child
). - Регулярно проверяйте и обновляйте локаторы при изменениях в структуре веб-страницы.
- Используйте инструменты разработчика для проверки корректности локаторов.
Примеры применения различных типов локаторов
Примеры поиска элементов на реальных веб-страницах
Предположим, у нас есть HTML-код:
<div id="main">
<h1 class="title">Welcome to our website</h1>
<form id="login-form">
<input type="text" name="username" id="username" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<button type="submit" class="btn btn-primary">Login</button>
</form>
<a href="/about" class="link">About Us</a>
</div>
- Найти заголовок:
driver.find_element(By.CSS_SELECTOR, "div#main > h1.title")
илиdriver.find_element(By.XPATH, "//div[@id='main']/h1[@class='title']")
- Найти поле username:
driver.find_element(By.ID, "username")
илиdriver.find_element(By.CSS_SELECTOR, "input#username")
илиdriver.find_element(By.XPATH, "//input[@id='username']")
- Найти кнопку Login:
driver.find_element(By.CLASS_NAME, "btn-primary")
илиdriver.find_element(By.CSS_SELECTOR, "button.btn.btn-primary")
илиdriver.find_element(By.XPATH, "//button[@type='submit']")
- Найти ссылку About Us:
driver.find_element(By.LINK_TEXT, "About Us")
илиdriver.find_element(By.XPATH, "//a[text()='About Us']")
Использование локаторов для выполнения различных действий (клик, ввод текста, выбор из списка и т.д.)
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
# Открыть страницу
driver = webdriver.Chrome()
driver.get("https://www.example.com")
# Ввести текст в поле username
username_field = driver.find_element(By.ID, "username")
username_field.send_keys("testuser")
# Ввести текст в поле password
password_field = driver.find_element(By.NAME, "password")
password_field.send_keys("password123")
# Кликнуть на кнопку Login
login_button = driver.find_element(By.CSS_SELECTOR, "button.btn.btn-primary")
login_button.click()
# Выбрать опцию из выпадающего списка (предполагается, что на странице есть <select id="dropdown">)
dropdown = Select(driver.find_element(By.ID, "dropdown"))
dropdown.select_by_value("option1")
# Закрыть браузер
driver.quit()
Обработка динамически изменяющихся элементов
Если элементы на странице динамически изменяются (например, id
генерируется случайным образом), можно использовать:
- Относительные XPath или CSS-селекторы, основанные на стабильных атрибутах или тексте. Например, искать элемент по классу или по части текста, который не меняется.
- Ожидания (Explicit Waits) для дождаться появления или изменения элемента. Selenium предоставляет механизмы для ожидания, пока элемент не станет доступным.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Ожидание появления элемента с id, содержащим "dynamic-element"
dynamic_element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, "//*[contains(@id, 'dynamic-element')]"))
)
# Ожидание кликабельности элемента с текстом "Click Me"
click_me_button = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.LINK_TEXT, "Click Me"))
)
click_me_button.click()
Инструменты для определения локаторов
Использование инструментов разработчика в браузерах (Chrome DevTools, Firefox Developer Tools)
В инструментах разработчика можно:
- Просматривать HTML-код страницы и структуру DOM.
- Выделять элементы на странице и видеть их атрибуты.
- *Использовать консоль для проверки XPath и CSS-селекторов (
$x('xpath')
в Chrome,document.querySelector('selector')
). - Копировать XPath и CSS-селекторы, сгенерированные браузером (но часто их нужно корректировать). ПКМ на элементе -> Copy -> Copy XPath/Copy selector
Расширения для браузеров (SelectorHub, ChroPath и др.)
Расширения для браузеров упрощают процесс поиска и проверки локаторов. Они предоставляют удобный интерфейс для написания, тестирования и отладки XPath и CSS-селекторов.
Заключение
Ключевые выводы о локаторах Selenium WebDriver
- Локаторы – это основа автоматизации тестирования веб-приложений.
- Существует множество типов локаторов, каждый из которых имеет свои преимущества и недостатки.
- Выбор правильного локатора – залог стабильности и надежности тестов.
- Важно учитывать приоритет локаторов и лучшие практики при их выборе.
- Инструменты разработчика и расширения для браузеров облегчают процесс поиска и проверки локаторов.
Рекомендации по дальнейшему изучению темы
- Изучите документацию Selenium WebDriver.
- Практикуйтесь в написании различных типов локаторов на реальных веб-страницах.
- Изучите продвинутые возможности XPath и CSS-селекторов.
- Познакомьтесь с паттернами проектирования автоматизированных тестов (например, Page Object Model).
- Изучите другие инструменты автоматизации тестирования, такие как Cypress или Playwright.