Python: Selenium

Теория: Работа с окнами и фреймами

Переключение между окнами

При клике на ссылку или кнопку сайт может открыть новое окно или вкладку. Для человека это естественно: браузер просто добавляет новую вкладку в интерфейсе. Но для Selenium каждое окно — отдельная сессия взаимодействия, и тест работает только с одним активным окном за раз. Если не переключиться, драйвер «не видит» элементы в новой вкладке и выдаёт ошибку NoSuchElementException.

Каждое окно в браузере имеет уникальный идентификатор, называемый window handle. Список всех активных окон можно получить свойством driver.window_handles, а текущее — через driver.current_window_handle.

Пример переключения:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("https://the-internet.herokuapp.com/windows")

## Получаем идентификатор текущего окна
main_window = driver.current_window_handle

## Кликаем по ссылке, которая открывает новое окно
driver.find_element(By.LINK_TEXT, "Click Here").click()

## Ждём, пока браузер создаст новую вкладку
time.sleep(1)

## Получаем список всех открытых окон
all_windows = driver.window_handles
print("Все окна:", all_windows)

## Находим новое окно — это то, которое не совпадает с текущим
for handle in all_windows:
    if handle != main_window:
        driver.switch_to.window(handle)  # Переключаемся в новое окно
        break

## Проверяем, что переключение сработало
print("Заголовок новой вкладки:", driver.title)

## Закрываем новое окно
driver.close()

## Возвращаемся обратно в исходное окно
driver.switch_to.window(main_window)
print("Возврат в основное окно:", driver.title)

driver.quit()

Selenium всегда должен знать, с каким окном работает. После закрытия вкладки контекст нужно вернуть в существующее окно, иначе дальнейшие команды вызовут NoSuchWindowException. В проектах с множеством pop-up окон часто добавляют вспомогательную функцию, которая переключает по имени или индексу нужной вкладки.

Работа с alert'ами

Alert — это системное модальное окно, созданное браузером, а не DOM. Оно блокирует страницу до тех пор, пока пользователь не выберет действие. Selenium не может взаимодействовать с другими элементами, пока alert не будет закрыт.

Для работы с ним используется специальный объект:

driver.switch_to.alert

У alert'а есть три стандартных метода:

  • .accept() — нажимает “OK”;
  • .dismiss() — нажимает “Cancel”;
  • .send_keys("текст") — вводит текст, если alert содержит поле ввода (prompt).

Пример на реальной тестовой странице:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("https://the-internet.herokuapp.com/javascript_alerts")

## Нажимаем кнопку, вызывающую prompt
driver.find_element(By.XPATH, "//button[text()='Click for JS Prompt']").click()

## Переключаем контекст на системное окно alert
alert = driver.switch_to.alert

## Считываем текст сообщения
print("Сообщение в алерте:", alert.text)

## Вводим текст в поле alert'а
alert.send_keys("Selenium Test")

## Подтверждаем действие
alert.accept()

## Проверяем, что результат появился на странице
result = driver.find_element(By.ID, "result").text
print("Результат:", result)

driver.quit()

Если alert не обработать, Selenium выбросит UnhandledAlertException при попытке кликнуть или найти элемент на странице. Поэтому любая страница, где ожидается alert, должна иметь явную обработку сразу после действия, которое его вызывает.

Работа с фреймами

Фрейм (iframe) — это встроенное окно, содержащее другую HTML-страницу. С точки зрения браузера, каждый фрейм — отдельный документ. Selenium по умолчанию «видит» только основной документ, и если попытаться найти элемент внутри iframe без переключения, тест упадёт с NoSuchElementException.

Чтобы попасть внутрь фрейма, нужно явно переключить контекст:

driver.switch_to.frame(frame_element)

Фрейм можно выбрать по индексу, имени или найденному элементу. После завершения работы нужно вернуться обратно командой driver.switch_to.default_content().

Пример редактирования текста в фрейме TinyMCE:

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()
driver.get("https://the-internet.herokuapp.com/iframe")

## На странице есть iframe с редактором текста
frame = driver.find_element(By.ID, "mce_0_ifr")

## Переключаем контекст на iframe
driver.switch_to.frame(frame)
print("Перешли в iframe")

## Работаем внутри фрейма: очищаем и вводим новый текст
editor = driver.find_element(By.ID, "tinymce")
editor.clear()
editor.send_keys("Hello, Selenium inside iframe!")

## Возвращаем контекст на основную страницу
driver.switch_to.default_content()

## Проверяем, что кнопка на внешней странице доступна
bold_button = driver.find_element(By.CSS_SELECTOR, "button[title='Bold']")
print("Кнопка жирного доступна:", bold_button.is_displayed())

driver.quit()

Если фреймы вложенные, можно использовать switch_to.parent_frame(), чтобы подняться на уровень выше, не возвращаясь к корню.

Когда страница динамически подгружает iframe, Selenium может не успеть переключиться, и появится ошибка NoSuchFrameException. В таких случаях лучше дождаться фрейма через ожидание:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

WebDriverWait(driver, 10).until(
    EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe#editor"))
)

Команда не просто ждёт появления фрейма, но и сразу переключает контекст, как только он доступен.

Объединим всё

from selenium import webdriver
from selenium.webdriver.common.by import By
import time

driver = webdriver.Chrome()

## Работа с окнами
driver.get("https://the-internet.herokuapp.com/windows")
main = driver.current_window_handle
driver.find_element(By.LINK_TEXT, "Click Here").click()
time.sleep(1)
for h in driver.window_handles:
    if h != main:
        driver.switch_to.window(h)
        print("Новое окно:", driver.title)
        driver.close()
        driver.switch_to.window(main)

## Работа с alert
driver.get("https://the-internet.herokuapp.com/javascript_alerts")
driver.find_element(By.XPATH, "//button[text()='Click for JS Alert']").click()
alert = driver.switch_to.alert
print("Текст алерта:", alert.text)
alert.accept()

## Работа с фреймом
driver.get("https://the-internet.herokuapp.com/iframe")
frame = driver.find_element(By.ID, "mce_0_ifr")
driver.switch_to.frame(frame)
editor = driver.find_element(By.ID, "tinymce")
editor.clear()
editor.send_keys("Работа с iframe завершена успешно!")
driver.switch_to.default_content()

driver.quit()

Такой тест поочередно показывает, как Selenium управляет контекстом: переключает окна, обрабатывает системные алерты и работает с вложенными страницами внутри фреймов.

Рекомендуемые программы

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845