ElementHandle
Низкоуровневый API для работы с DOM-элементами: query_selector, действия, состояние, скриншоты и выполнение JavaScript на элементе.
Обзор ElementHandle
ElementHandle — это представление DOM-элемента в Playwright. В отличие от Locator, который использует ленивое вычисление и автоматическое ожидание, ElementHandle даёт прямой доступ к элементу и его методам. Обычно ElementHandle получают через page.query_selector() и page.query_selector_all().
Важно: Playwright рекомендует использовать Locator вместо ElementHandle в большинстве случаев. Locator автоматически ожидает появления элемента и повторяет действия при неудаче. ElementHandle не имеет такого поведения.
Получение ElementHandle
# Получить первый элемент, соответствующий селектору button = page.query_selector("button.submit") # Получить все элементы items = page.query_selector_all("li") # Внутри фрейма frame = page.frame("main") header = frame.query_selector("h1")
Основные действия
# Клик по элементу button.click() # Заполнение текстового поля input_element.fill("Hello, World!") # Получение текстового содержимого text = element.text_content() inner = element.inner_text() html = element.inner_html() # Получение атрибута href = element.get_attribute("href")
Проверка состояния
# Проверка видимости element.is_visible() element.is_hidden() # Проверка доступности element.is_enabled() # Проверка состояния чекбокса/radio element.is_checked()
Продвинутые взаимодействия
# Наведение мыши element.hover() # Фокус element.focus() # Нажатие клавиши element.press("Enter") element.press("Control+a") # Отправка пользовательского события element.dispatch_event("click", "{ bubbles: true }") # Скролл до элемента element.scroll_into_view_if_needed() # Выделение текста element.select_text() # Загрузка файлов element.set_input_files("file.txt") element.set_input_files(["file1.pdf", "file2.pdf"])
Координаты и размеры
# Получение bounding box (x, y, width, height) box = element.bounding_box() if box: print(f"X: {box['x']}, Y: {box['y']}") print(f"Width: {box['width']}, Height: {box['height']}")
Выполнение JavaScript на элементе
Метод evaluate() выполняет JS-функцию на переданном элементе, а evaluate_handle() возвращает JSHandle.
# Выполнение JS — возвращает Python-значение text = element.evaluate("el => el.textContent") styles = element.evaluate("el => window.getComputedStyle(el)") rect = element.evaluate("el => el.getBoundingClientRect()") # evaluate_handle — возвращает JSHandle js_handle = element.evaluate_handle("el => el.style") color = js_handle.get_property("color") print(await color.json_value())
Скриншот элемента
# Скриншот конкретного элемента element.screenshot(path="element.png") # Скриншот с кастомными опциями element.screenshot( path="element.png", type="jpeg", quality=80, omit_background=True )
Ожидание состояния элемента
Метод wait_for_element_state() ожидает, пока элемент не достигнет указанного состояния. В отличие от автоматического ожидания Locator, здесь ожидание явное.
# Ожидание видимости element.wait_for_element_state("visible") # Ожидание скрытия element.wait_for_element_state("hidden") # Ожидание стабильности (не анимируется) element.wait_for_element_state("stable") # Ожидание включения element.wait_for_element_state("enabled") # Ожидание отключения element.wait_for_element_state("disabled")
Совет: Если вам нужно просто подождать появления элемента на странице, используйте page.wait_for_selector(css) — он вернёт ElementHandle, дождавшись появления элемента в DOM.
ElementHandle vs Locator
| Характеристика | ElementHandle | Locator |
|---|---|---|
| Автоожидание | Нет (кроме wait_for_element_state) | Автоматическое |
| Повтор при неудаче | Нет | Есть (retry) |
| Ленивое вычисление | Нет (жёсткая ссылка на элемент) | Да (поиск при действии) |
| Stale-элементы | Устаревают при изменении DOM | Автоматически переищет |
| Использование | Низкоуровневые сценарии, JS-интеграция | Основной API для тестов |
| Производительность | Быстрее для однократных операций | Небольшие накладные расходы |
Когда использовать ElementHandle
Несмотря на рекомендацию использовать Locator, есть сценарии, где ElementHandle удобнее:
- Однократные операции — нужно быстро прочитать атрибут или текст без повторных попыток
- Выполнение JS на элементе —
evaluate()иevaluate_handle()работают напрямую с ElementHandle - Работа с фреймами — некоторые сценарии с iframe требуют ElementHandle
- Кастомные события —
dispatch_event()для нестандартных событий - Скриншоты конкретных элементов — быстрый скриншот без автоожидания
Внимание: ElementHandle может стать "stale" (устаревшим), если DOM изменился после его получения. При каждом изменении страницы нужно запрашивать новый ElementHandle. Locator лишён этого недостатка.
Примеры
Чтение данных из таблицы
def get_table_data(page): rows = page.query_selector_all("table tr") data = [] for row in rows: cells = row.query_selector_all("td, th") data.append([cell.inner_text() for cell in cells]) return data
Проверка CSS-свойств
def test_button_color(page): page.goto("https://example.com") btn = page.query_selector("button.primary") color = btn.evaluate("el => window.getComputedStyle(el).color") assert color == "rgb(255, 0, 0)"
Скриншот динамического элемента
def test_captcha_screenshot(page): page.goto("https://example.com/login") captcha_img = page.query_selector("img.captcha") captcha_img.screenshot(path="captcha.png")