Selenium Python: Как работать с выпадающим списком без select?

Проблема: нестандартные выпадающие списки без тега <select>

Современные веб-приложения часто реализуют выпадающие списки (dropdown menus) нестандартными способами, не используя традиционный HTML-тег <select>. Это делается для большей гибкости в стилизации и интерактивности.

Почему нельзя использовать Select class в таких случаях?

Класс Select в Selenium предназначен для работы исключительно с элементами <select>. При попытке использовать его с нестандартным выпадающим списком, он не сможет идентифицировать элементы и выдаст ошибку.

Цель статьи: как автоматизировать выбор элементов в таких списках

Эта статья предоставит вам практические методы и примеры кода для автоматизации взаимодействия с выпадающими списками, созданными без тега <select>, используя Selenium WebDriver на Python.

Анализ структуры нестандартного выпадающего списка

Общий HTML-шаблон выпадающего списка без <select>

Как правило, такой список состоит из:

  1. Триггера: Элемент, при клике на который список раскрывается (обычно кнопка, div или span).
  2. Контейнера: Элемент, содержащий видимые элементы списка (часто ul или div).
  3. Элементов списка: Фактические элементы, которые пользователь может выбрать (обычно li, div или a).

Определение триггера (кнопки) для открытия списка

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

Идентификация контейнера списка (ul, div)

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

Поиск элементов списка (li, div, a)

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

Методы работы с выпадающими списками без <select> в Selenium

Клик по триггеру для открытия списка

Используйте метод click() для открытия списка, получив элемент триггера с помощью find_element.

Поиск нужного элемента списка по тексту

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

Использование XPath для точного определения элемента

XPath предоставляет мощные инструменты для навигации по DOM и точного определения элементов, особенно если у них нет уникальных id или class.

Клик по найденному элементу для выбора

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

Примеры кода на Python с использованием Selenium

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver

def select_option_from_custom_dropdown(driver: WebDriver, trigger_locator: tuple, option_text: str) -> None:
    """Selects an option from a custom dropdown list.

    Args:
        driver: The Selenium WebDriver instance.
        trigger_locator: A tuple containing the By strategy and locator for the dropdown trigger (e.g., (By.ID, "dropdown_trigger")).
        option_text: The text of the option to select.
    """
    trigger = driver.find_element(*trigger_locator)
    trigger.click()

    option_locator = (By.XPATH, f"//div[contains(@class, 'dropdown-menu')]//div[text()='{option_text}']")
    option = driver.find_element(*option_locator)
    option.click()


# Пример использования:
# driver = webdriver.Chrome()
# driver.get("https://example.com/custom_dropdown") # Замените на URL вашей страницы
# select_option_from_custom_dropdown(driver, (By.ID, "myDropdown"), "Option 2")
# driver.quit()

Пример 1: Выбор элемента по видимому тексту

В этом примере мы ищем элемент списка, текст которого точно соответствует желаемому.

def select_option_by_exact_text(driver: WebDriver, trigger_locator: tuple, option_text: str) -> None:
    """Selects an option from a custom dropdown based on exact text matching.

    Args:
        driver: The Selenium WebDriver instance.
        trigger_locator: Locator for the dropdown trigger.
        option_text: The exact text of the option to select.
    """
    driver.find_element(*trigger_locator).click()
    option_locator = (By.XPATH, f"//li[text()='{option_text}']")
    driver.find_element(*option_locator).click()

Пример 2: Использование частичного совпадения текста

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

def select_option_by_partial_text(driver: WebDriver, trigger_locator: tuple, partial_text: str) -> None:
    """Selects an option from a custom dropdown based on partial text matching.

    Args:
        driver: The Selenium WebDriver instance.
        trigger_locator: Locator for the dropdown trigger.
        partial_text: A part of the text of the option to select.
    """
    driver.find_element(*trigger_locator).click()
    option_locator = (By.XPATH, f"//li[contains(text(), '{partial_text}')]")
    driver.find_element(*option_locator).click()

Пример 3: Работа со списками, где текст элемента хранится в атрибуте

В некоторых случаях текст элемента может быть невидимым, а храниться в атрибуте (например, data-value).

def select_option_by_attribute_value(driver: WebDriver, trigger_locator: tuple, attribute_name: str, attribute_value: str) -> None:
    """Selects an option from a custom dropdown based on an attribute value.

    Args:
        driver: The Selenium WebDriver instance.
        trigger_locator: Locator for the dropdown trigger.
        attribute_name: The name of the attribute containing the value.
        attribute_value: The value of the attribute to match.
    """
    driver.find_element(*trigger_locator).click()
    option_locator = (By.XPATH, f"//li[@{attribute_name}='{attribute_value}']")
    driver.find_element(*option_locator).click()

Пример 4: Использование Action Chains (если простой клик не работает)

Если элемент перекрыт или клик не срабатывает, можно использовать ActionChains.

from selenium.webdriver import ActionChains

def select_option_with_action_chains(driver: WebDriver, trigger_locator: tuple, option_text: str) -> None:
    """Selects an option from a custom dropdown using Action Chains.

    Args:
        driver: The Selenium WebDriver instance.
        trigger_locator: Locator for the dropdown trigger.
        option_text: The text of the option to select.
    """
    trigger = driver.find_element(*trigger_locator)
    ActionChains(driver).move_to_element(trigger).click().perform()

    option_locator = (By.XPATH, f"//li[text()='{option_text}']")
    option = driver.find_element(*option_locator)
    ActionChains(driver).move_to_element(option).click().perform()

Обработка сложных случаев и распространенные ошибки

Список не открывается: ожидание загрузки списка

Используйте WebDriverWait для ожидания появления контейнера списка после клика по триггеру.

Элемент не найден: проверка атрибутов и текста

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

Перекрытие элемента другими элементами: использование JavaScriptExecutor

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

driver.execute_script("arguments[0].click();", element)

Оптимизация поиска элементов: кеширование элементов списка

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

# Вместо постоянного поиска элементов списка
options = driver.find_elements(By.XPATH, "//li")
# Использовать закешированный список options

Добавить комментарий