📖 Теория: Локаторы Selenium
⚡ Суть: найти элемент — значит описать его уникально
- Локатор — описание элемента, по которому Selenium его находит
- CSS-селекторы — быстро, лаконично:
#id,.class,[attr=val],parent child - XPath — мощнее, медленнее: можно искать по тексту
[text()="..."]и вверх по дереву find_element()→ первый или исключение;find_elements()→ список или []is_displayed()— проверяет видимость;.text— читает видимый текст
Что такое локатор веб-элемента
Локатор веб-элемента — это способ однозначно определить нужный элемент на веб-странице. Он используется в автоматизированном тестировании и веб-скрапинге для взаимодействия с HTML-элементами: кнопками, полями ввода, ссылками и другими тегами.
Локаторы помогают найти элемент по его ID, имени, классу, атрибутам, тексту или структуре вложенности. Они применяются в инструментах Selenium, Playwright, Puppeteer и других.
Как найти локатор в DevTools
Для определения локатора используйте инструменты разработчика (DevTools) в браузере.
Как открыть DevTools
- Правый клик по элементу → «Просмотреть код» (Inspect)
- Или нажать F12 / Ctrl + Shift + I (Windows) / Cmd + Option + I (Mac)
- Переключиться на вкладку Elements (Элементы)
Как быстро скопировать локатор
Кликнуть правой кнопкой по элементу в панели Elements → Copy (Копировать). Выбрать:
- «Copy selector» — получить CSS-селектор
- «Copy XPath» — получить XPath
/html/body/div[3]/div/form/input[1]). Любое изменение HTML-структуры сломает такой локатор. Пишите XPath вручную на основе стабильных атрибутов.
CSS-селекторы
CSS-селекторы считаются быстрыми и удобными для поиска элементов. Они работают во всех браузерах и подходят для большинства задач автоматизации.
По ID — самый надёжный способ
Если у элемента есть уникальный ID — это лучший выбор.
<!-- HTML -->
<input id="username" type="text">
<!-- CSS-селектор -->
#username
По атрибуту name
Подходит, если у элемента есть атрибут name, но нет id.
<!-- HTML -->
<input name="email" type="text">
<!-- CSS-селектор -->
[name="email"]
По классу
Используется, если у элемента есть class. Важно: класс может быть не уникальным.
<!-- HTML -->
<button class="btn-primary">Login</button>
<!-- CSS-селектор -->
.btn-primary
По вложенности
Позволяет сузить поиск до элементов внутри определённого родителя.
<!-- HTML -->
<div class="container">
<button>Купить</button>
</div>
<!-- CSS: любой button внутри .container (любой уровень) -->
.container button
<!-- CSS: только прямой потомок -->
.container > button
По частичному совпадению атрибута
Оператор *= ищет подстроку в значении атрибута.
<!-- HTML -->
<a href="/products/view/123">Подробнее</a>
<!-- CSS-селектор -->
a[href*="/products/view/"]
Псевдокласс :nth-child()
Позволяет выбрать N-й элемент среди дочерних.
<!-- Первая карточка в сетке -->
.col-sm-4:nth-child(1)
<!-- Шестая карточка -->
.col-sm-4:nth-child(6)
XPath
XPath — язык запросов для поиска элементов в иерархической структуре HTML. Он мощнее CSS, но, как правило, медленнее. Основное преимущество XPath — возможность искать по текстовому содержимому элемента и перемещаться вверх по дереву DOM.
Базовый синтаксис
| Синтаксис | Смысл |
|---|---|
//* |
Любой элемент где угодно в документе |
//tag |
Все элементы tag где угодно |
/tag |
Прямой потомок (один уровень) |
[@attr="val"] |
Фильтр по атрибуту |
[text()="..."] |
Фильтр по точному тексту элемента |
[contains(@attr, "val")] |
Частичное совпадение атрибута |
Примеры XPath
<!-- По ID -->
//*[@id="username"]
<!-- По имени (name) -->
//*[@name="email"]
<!-- По классу (осторожно: может вернуть несколько!) -->
//*[@class="btn-primary"]
<!-- По тексту кнопки -->
//button[text()="Отправить"]
<!-- По вложенности — прямой потомок -->
//div[@class="container"]/button
<!-- По частичному совпадению атрибута -->
//a[contains(@href, "/products/view/")]
<!-- По частичному совпадению текста -->
//button[contains(text(), "Купить")]
Метод find_element()
Метод find_element() ищет первый элемент, соответствующий локатору. Возвращает объект WebElement. Если элемент не найден — выбрасывает NoSuchElementException.
# Синтаксис
element = driver.find_element(By.LOCATOR, "значение")
Примеры
# test_locators.py
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("http://example.com")
# По ID
element = driver.find_element(By.ID, "login-button")
# По CSS-селектору
element = driver.find_element(By.CSS_SELECTOR, "div.container > p")
# По XPath
element = driver.find_element(By.XPATH, "//button[text()='Отправить']")
# По атрибуту name
element = driver.find_element(By.NAME, "username")
# По тегу
element = driver.find_element(By.TAG_NAME, "h1")
print(element.text) # Читаем видимый текст
driver.quit()
Обработка NoSuchElementException
Если элемент не найден, Selenium выбрасывает NoSuchElementException. Используйте try-except, чтобы тест не упал с необработанным исключением.
# test_exception.py
from selenium.common.exceptions import NoSuchElementException
try:
element = driver.find_element(By.ID, "non-existent")
print("Элемент найден")
except NoSuchElementException:
print("Элемент не найден")
Свойство .text
Свойство .text возвращает видимый текст внутри элемента (включая дочерние элементы). Скрытый текст (display: none, visibility: hidden) не считывается.
# test_text.py
header = driver.find_element(By.TAG_NAME, "h1")
print(header.text) # Выведет текст заголовка h1
Метод is_displayed()
Метод is_displayed() проверяет, видим ли элемент пользователю в данный момент. Возвращает True или False.
Когда is_displayed() возвращает False
- Элемент скрыт через CSS:
display: noneилиvisibility: hidden - Элемент за пределами экрана:
position: absolute; left: -9999px - Элемент полностью прозрачен:
opacity: 0 - Элемент удалён из DOM
- Родительский элемент скрыт (наследуется)
# test_visibility.py
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("http://example.com")
element = driver.find_element(By.ID, "myElement")
if element.is_displayed():
print("Элемент виден на странице")
else:
print("Элемент скрыт")
driver.quit()
find_element() найдёт элемент, даже если он скрыт. is_displayed() нужно вызывать дополнительно, чтобы убедиться в его видимости.
Метод find_elements()
Метод find_elements() ищет все элементы, соответствующие локатору. В отличие от find_element(), он не выбрасывает исключение, если элементы не найдены — возвращает пустой список [].
# Синтаксис
elements = driver.find_elements(By.LOCATOR, "значение")
Сравнение методов
| Метод | Если не найден | Возвращаемый тип |
|---|---|---|
find_element() |
Выбрасывает NoSuchElementException |
WebElement |
find_elements() |
Возвращает пустой список [] |
list[WebElement] |
# test_find_elements.py
cards = driver.find_elements(By.CSS_SELECTOR, ".col-sm-4")
print(f"Найдено карточек: {len(cards)}")
# Проверка каждого элемента
for card in cards:
assert card.is_displayed(), f"Карточка скрыта: {card.text}"
Как выбирать надёжный локатор
1. Предпочитайте By.ID
Если элемент имеет уникальный стабильный id — это лучший выбор. ID не меняется при рефакторинге стилей.
2. Используйте By.CSS_SELECTOR
По умолчанию — CSS. Быстро, читаемо, поддерживается везде. Стройте на атрибутах data-testid, name, стабильных классах.
3. XPath — только при необходимости
Когда нужен поиск по тексту, переход к родителю или CSS не справляется. Избегайте абсолютных путей.
4. Избегайте хрупких локаторов
Никаких /html/body/div[3]/ul/li[2]/a. Такой локатор сломается при любом изменении разметки.