Playwright позволяет Python управлять настоящим браузером и одновременно проверять, что пользовательский сценарий завершился правильно. Вместо движения мыши по координатам скрипт находит поле по подписи, кнопку по роли, ждёт результат и сохраняет скриншот. Соберём такой сценарий на локальной странице, чтобы сеть и чужой сайт не мешали понять механику.
Автоматизация браузера часто выглядит как магия: окно само открывается, текст появляется в форме, кнопка нажимается без человека. На деле здесь есть точная цепочка. Python запускает движок Chromium, Playwright создаёт страницу, локаторы находят элементы по смыслу, а ожидания синхронизируют действия с интерфейсом.
Запускаем отдельный Chromium и загружаем локальный demo.html без зависимости от интернета.
Находим поле по label, вводим имя и нажимаем кнопку по доступной роли.
Проверяем текст результата и сохраняем полноэкранный PNG после успешного сценария.
Как Playwright видит страницу и действия
Проект состоит из двух файлов. demo.html является маленьким приложением: в нём есть связанная с полем подпись, кнопка и область результата с data-testid. main.py запускает Playwright в синхронном режиме и открывает HTML через file URL. Затем сценарий выполняет ровно те действия, которые сделал бы человек.
| Этап | Что происходит | Признак результата |
|---|---|---|
| Запуск | Python создаёт Chromium и новую страницу | Окно браузера готово |
| Поиск | Локатор находит поле и кнопку по смыслу | Найден ровно один элемент |
| Действие | fill и click вызывают события страницы | Появляется приветствие |
| Проверка | expect сравнивает текст, screenshot пишет PNG | Тест завершён без ошибки |
У проекта есть один главный маршрут: получить входные данные, проверить их, выполнить действие и показать результат. Если каждый этап можно проверить отдельно, ошибка перестаёт быть загадкой.

От входных данных до видимого результата. Сначала действие, затем ожидание и доказательство
Пишем форму и первый Python-сценарий
Создайте каталог и выполните uv init browser-lab, затем uv add playwright и uv run playwright install chromium. Последняя команда загружает совместимый браузер. Положите рядом demo.html из исходников статьи и main.py. Запускайте через uv run python main.py. Значение headless=False оставляет окно видимым; когда сценарий станет стабильным, поменяйте его на True для фонового запуска.
from pathlib import Path
from playwright.sync_api import expect, sync_playwright
page_url = Path("demo.html").resolve().as_uri()
with sync_playwright() as playwright:
browser = playwright.chromium.launch(headless=False)
page = browser.new_page(viewport={"width": 1100, "height": 720})
page.goto(page_url)
page.get_by_label("Имя").fill("Аня")
page.get_by_role("button", name="Проверить").click()
result = page.get_by_test_id("result")
expect(result).to_have_text("Привет, Аня!")
page.screenshot(path="result.png", full_page=True)
print("Готово: приветствие проверено, result.png сохранён")
browser.close()- Открывается отдельное окно Chromium с локальной формой.
- В поле появляется имя «Аня», после клика выводится «Привет, Аня!».
- Если текст отличается, expect останавливает сценарий с понятным сравнением.
- После успеха рядом с main.py появляется полноэкранный result.png.
Сценарий не содержит sleep и координат. Playwright сам ждёт, пока поле станет доступным, кнопка перестанет двигаться и элемент сможет принять действие. Это делает тест быстрее на хорошем компьютере и устойчивее на медленном.

Что отличает устойчивый проект от случайного успеха. Хороший локатор описывает назначение, а не положение
Почему локаторы надёжнее координат
Локатор не является найденным DOM-элементом, сохранённым навсегда. Это описание того, как Playwright должен найти элемент в момент действия. get_by_label связывает текст подписи с input через атрибут for, get_by_role использует доступную роль button и имя, а get_by_test_id обращается к стабильному служебному атрибуту.
| Часть | Ответственность | Что проверить |
|---|---|---|
| Browser | Отдельный процесс Chromium | Закрывается даже после проверки |
| Page | Одна вкладка и её viewport | Открыт правильный URL |
| Locator | Правило поиска элемента | Совпадает ровно один узел |
| Action | Ввод, клик или выбор | Событие действительно сработало |
| Assertion | Ожидание проверяемого состояния | Получен ожидаемый текст |
CSS-селектор вроде div:nth-child(3) привязан к форме страницы, а роль и подпись описывают назначение элемента. Если дизайнер добавит обёртку, семантический локатор продолжит работать. Если на странице две одинаковые кнопки, Playwright специально сообщит о неоднозначности.
Ломаем сценарий и учимся читать ошибку
Запустите готовый сценарий, затем намеренно замените ожидаемое имя на «Борис». Посмотрите, как expect показывает полученный и ожидаемый текст. Верните правильное значение и удалите атрибут for у label в demo.html: теперь get_by_label не должен находить поле. Исправьте связь. После этого добавьте чекбокс «Писать официально» и второй вариант ответа.
- Запустите браузер в видимом режиме и убедитесь, что result.png создаётся только после текста.
- Поменяйте имя в assert, прочитайте ошибку и верните корректное ожидание.
- Добавьте задержку setTimeout на странице и убедитесь, что expect дождался результата без sleep.
- Создайте вторую кнопку с тем же именем и разберите ошибку strict mode.
- Уточните локатор через область формы, а не через
.first(). - Переключите headless=True и повторите запуск из терминала.
- Скрипт стабильно проходит два запуска подряд.
- Локаторы используют label, role и test id.
- Неверное ожидание даёт читаемую ошибку.
- После изменения формы вы можете поправить тест сами.
Главный результат этой практики не скриншот, а воспроизводимый сценарий. Он либо подтверждает нужное состояние, либо останавливается в точной строке. Теперь браузерная автоматизация стала проверкой, а не записью движений мыши.

Четыре проверки перед следующим шагом. Падение должно объяснять, какой шаг не выполнен
Куда развивать браузерную автоматизацию
Следующий шаг зависит от задачи. Для тестирования оформите сценарий как pytest-тест и создавайте новую страницу для каждого случая. Для рутинной автоматизации добавьте входные данные из JSON и отчёт, но не храните пароли в коде. Секреты передавайте через переменные окружения, а чувствительные поля маскируйте на скриншотах.
Как изучить тему в Кодике
В Кодике начните с функций, путей к файлам и контекстных менеджеров Python. Затем закрепите HTML-формы и события на простом примере. После этого API Playwright читается естественно: объект page получает команды, локатор описывает элемент, а expect проверяет состояние.
| Шаг | Что изучить в Кодике | Мини-проверка |
|---|---|---|
| 1 | Функции и with в курсе Python | Открыть и гарантированно закрыть ресурс |
| 2 | HTML-форма и label | Связать подпись с полем через for и id |
| 3 | Локаторы Playwright | Найти элементы тремя семантическими способами |
| 4 | Ожидания и assert | Намеренно получить и объяснить падение |
| 5 | Структура автотеста | Разделить подготовку, действие и проверку |
После статьи повторите только demo.html и первые четыре действия main.py в тренажёре Кодика. На следующий день соберите их по памяти и добавьте второй сценарий. Так вы учите не список методов, а модель: найти элемент, выполнить действие, дождаться состояния, доказать результат.
Пакет Python и бинарник Chromium устанавливаются отдельно. Выполните playwright install chromium в том же окружении.
Размер окна или новая плашка сдвинут кнопку. Ищите элемент по роли, подписи или стабильному test id.
Фиксированная пауза либо замедляет тест, либо оказывается слишком короткой. Используйте ожидания Playwright.
Контекст with и явный browser.close помогают не оставлять процессы после локального запуска.
Что получится в итоге

Python открывает локальную форму, вводит имя, проверяет приветствие и сохраняет PNG только после успешного сценария.
Почему get_by_role лучше случайного CSS-пути?
Роль и доступное имя описывают назначение элемента и меньше зависят от вложенности разметки.
Зачем нужен expect, если можно сразу прочитать inner_text?
expect повторяет проверку до тайм-аута и учитывает асинхронное обновление интерфейса.
Когда включать headless=True?
После отладки, когда сценарий стабилен и его нужно запускать без видимого окна.
Как понять, что проект действительно работает?
Проверьте основной сценарий, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.
Можно ли начать с готового кода из статьи?
Да. Добейтесь результата, измените одно правило и соберите ключевой файл заново без копирования.
Основы функций, файлов и обработки ошибок закрепите в курсе Python. Работу с терминалом освежите в статье про терминал VS Code.
Затем сравните окружения в материале про uv и сохраните проект по инструкции про GitHub.