🐛 Частые ошибки с локаторами
⚡ Топ-5 ошибок с локаторами
- Хрупкий XPath из DevTools — сломается при любом изменении HTML.
- CLASS_NAME с пробелом —
By.CLASS_NAME, "btn btn-primary"выбросит исключение. - find_element() без try-except — тест падает с необработанным
NoSuchElementException. - is_displayed() путают с существованием — элемент может быть найден, но скрыт.
- XPath @class с составным классом —
//*[@class="btn btn-primary"]не найдёт элемент с дополнительными классами.
Ошибка 1: Хрупкий XPath из DevTools
«Copy XPath» из DevTools генерирует абсолютный путь. Сломается при любом изменении HTML-структуры.
# ПЛОХО: XPath, скопированный из DevTools
driver.find_element(
By.XPATH,
"/html/body/div[2]/div[1]/div/form/div[1]/div/input"
)
# Упадёт, если между div добавить ещё один элемент
# ХОРОШО: XPath на основе стабильных атрибутов
driver.find_element(By.XPATH, "//*[@id='username']")
driver.find_element(By.XPATH, "//input[@name='username']")
driver.find_element(By.XPATH, "//button[text()='Login']")
Ошибка 2: By.CLASS_NAME с составным классом
By.CLASS_NAME принимает только один класс. Пробел вызовет InvalidSelectorException.
<!-- HTML -->
<button class="btn btn-primary">Login</button>
# ПЛОХО: составной класс вызовет исключение
driver.find_element(By.CLASS_NAME, "btn btn-primary")
# → InvalidSelectorException
# ХОРОШО: один класс
driver.find_element(By.CLASS_NAME, "btn-primary")
# ЕЩЁ ЛУЧШЕ: CSS-селектор с несколькими классами
driver.find_element(By.CSS_SELECTOR, ".btn.btn-primary")
Ошибка 3: find_element() без обработки исключения
# ПЛОХО: тест падает с необработанным исключением
element = driver.find_element(By.ID, "maybe-not-here")
# → NoSuchElementException: no such element
# ХОРОШО: явная обработка
from selenium.common.exceptions import NoSuchElementException
try:
element = driver.find_element(By.ID, "maybe-not-here")
assert element.is_displayed()
except NoSuchElementException:
assert False, "Элемент #maybe-not-here не найден на странице"
# ЕЩЁ ВАРИАНТ: find_elements() для проверки существования
elements = driver.find_elements(By.ID, "maybe-not-here")
assert len(elements) > 0, "Элемент не найден"
Ошибка 4: Путаница is_displayed() и существованием элемента
<!-- HTML: элемент есть в DOM, но скрыт -->
<button id="myButton" style="display: none;">Кнопка</button>
# ПЛОХО: think find_element() гарантирует видимость
button = driver.find_element(By.ID, "myButton")
# Элемент найден — но он скрыт!
button.click() # Может вызвать ElementNotInteractableException
# ХОРОШО: явная проверка видимости
button = driver.find_element(By.ID, "myButton")
assert button.is_displayed(), "Кнопка должна быть видима"
button.click()
Правило:
find_element() находит элемент даже если он скрыт. is_displayed() — отдельная проверка. В автотестах всегда проверяйте видимость перед кликом.
Ошибка 5: XPath @class с составным классом
<!-- HTML -->
<button class="btn btn-primary active">Login</button>
# ПЛОХО: точное совпадение @class требует ВСЕ классы в правильном порядке
driver.find_element(By.XPATH, "//*[@class='btn-primary']")
# → NoSuchElementException (класс не один!)
# ХОРОШО: contains() для частичного совпадения
driver.find_element(By.XPATH, "//*[contains(@class, 'btn-primary')]")
# ЕЩЁ ЛУЧШЕ: CSS-селектор
driver.find_element(By.CSS_SELECTOR, ".btn-primary")
Ошибка 6: Нет ожидания перед поиском
Страница ещё не загрузилась, а тест уже ищет элемент — получает
NoSuchElementException. Решение: явные ожидания (урок 07).
# ПЛОХО: нет ожидания
driver.get("https://some-page.com")
element = driver.find_element(By.ID, "dynamic-element")
# Упадёт, если элемент появляется динамически
# ХОРОШО: явное ожидание (подробнее — урок 07)
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "dynamic-element"))
)
Ошибка 7: find_elements() и доступ по индексу без проверки
# ПЛОХО: доступ к элементу без проверки длины
cards = driver.find_elements(By.CSS_SELECTOR, ".card")
first_card = cards[0] # IndexError если список пустой
# ХОРОШО: проверить длину перед доступом
cards = driver.find_elements(By.CSS_SELECTOR, ".card")
assert len(cards) > 0, "Карточки не найдены"
first_card = cards[0]