📖 Теория: Локаторы Selenium

← К оглавлению урока

⚡ Суть: найти элемент — значит описать его уникально

  • Локатор — описание элемента, по которому Selenium его находит
  • CSS-селекторы — быстро, лаконично: #id, .class, [attr=val], parent child
  • XPath — мощнее, медленнее: можно искать по тексту [text()="..."] и вверх по дереву
  • find_element() → первый или исключение; find_elements() → список или []
  • is_displayed() — проверяет видимость; .text — читает видимый текст

Что такое локатор веб-элемента

Локатор веб-элемента — это способ однозначно определить нужный элемент на веб-странице. Он используется в автоматизированном тестировании и веб-скрапинге для взаимодействия с HTML-элементами: кнопками, полями ввода, ссылками и другими тегами.

Локаторы помогают найти элемент по его ID, имени, классу, атрибутам, тексту или структуре вложенности. Они применяются в инструментах Selenium, Playwright, Puppeteer и других.

Аналогия: локатор — как адрес элемента на странице. Так же, как почтовый адрес однозначно указывает на конкретный дом, хороший локатор однозначно указывает на конкретный HTML-элемент.

Как найти локатор в DevTools

Для определения локатора используйте инструменты разработчика (DevTools) в браузере.

Как открыть DevTools

  • Правый клик по элементу → «Просмотреть код» (Inspect)
  • Или нажать F12 / Ctrl + Shift + I (Windows) / Cmd + Option + I (Mac)
  • Переключиться на вкладку Elements (Элементы)

Как быстро скопировать локатор

Кликнуть правой кнопкой по элементу в панели Elements → Copy (Копировать). Выбрать:

  • «Copy selector» — получить CSS-селектор
  • «Copy XPath» — получить XPath
Автоматически скопированный XPath из DevTools часто очень хрупкий — он строится по абсолютному пути в DOM (/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(), "Купить")]
CSS или XPath? По умолчанию предпочитайте CSS-селекторы — они быстрее и лаконичнее. XPath используйте тогда, когда нужно: найти по тексту, перейти к родительскому элементу, или CSS не справляется с нестандартными условиями.

Метод 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. Такой локатор сломается при любом изменении разметки.