Автоматическое скачивание файлов через Playwright: примеры и обработка ошибок

📥 Кратко: Playwright умеет перехватывать загрузки — даже если файл создаётся после нажатия кнопки. Покажу, как сохранить его в нужную папку и убедиться, что загрузка завершена.
Автоматическое скачивание файлов через Playwright

Когда я начал автоматизировать сбор отчётов с внутренних панелей, столкнулся с проблемой: файлы не имеют прямых ссылок — они генерируются динамически и скачиваются только после клика.

Библиотека requests здесь бессильна. Но Playwright решает задачу элегантно: он запускает браузер, нажимает кнопку и перехватывает событие загрузки, даже если это PDF, CSV или ZIP-архив.

В этой статье вы узнаете, как с помощью python playwright скачать файл в реальных сценариях: от простого примера до обработки ошибок, массовой загрузки и интеграции в скрипты мониторинга. Всё — с полным кодом и пояснениями.

Подготовка: демо-сайт и настройка среды

Для практики используем проверенный ресурс:
👉 https://the-internet.herokuapp.com/download

Там можно скачать любые файлы — идеально для тестов.

Установка и базовая настройка

pip install playwright
playwright install chromium

Создайте папку для загрузок:

import os

DOWNLOAD_DIR = os.path.abspath("downloads")
os.makedirs(DOWNLOAD_DIR, exist_ok=True)

⚠️ Обязательно включите accept_downloads=True в контексте

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    context = browser.new_context(accept_downloads=True)
    page = context.new_page()

Без этого Playwright проигнорирует все загрузки.

Пример 1. Скачивание одного файла с сохранением оригинального имени

page.goto("https://the-internet.herokuapp.com/download")

with page.expect_download() as download_info:
    page.click("text='some-file.txt'")

download = download_info.value
original_name = download.suggested_filename
full_path = os.path.join(DOWNLOAD_DIR, original_name)

download.save_as(full_path)
print(f"✅ Сохранён: {full_path}")
  • suggested_filename — имя, предложенное сервером
  • save_as()обязательный метод для физического сохранения

Пример 2. Скачивание с переименованием (например, с датой)

from datetime import datetime

timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
custom_name = f"report_{timestamp}.csv"
download.save_as(os.path.join(DOWNLOAD_DIR, custom_name))

Полезно, если вы запускаете скрипт ежедневно и не хотите перезаписи.

Пример 3. Обработка ошибок и таймаутов

Загрузка может зависнуть или завершиться ошибкой. Оборачивайте в try/except:

try:
    with page.expect_download(timeout=10000) as download_info:
        page.click("button#export")
    download = download_info.value
    download.save_as(os.path.join(DOWNLOAD_DIR, "data.csv"))
except Exception as e:
    print(f"❌ Ошибка загрузки: {e}")
    # Отправить уведомление в Telegram или лог

💡 Используйте timeout — по умолчанию 30 секунд, но для больших файлов нужно больше.

Пример 4. Массовое скачивание всех файлов на странице

page.goto("https://the-internet.herokuapp.com/download")
links = page.query_selector_all("a[href]")

for i, link in enumerate(links):
    filename = link.text_content().strip()
    if not filename or filename == "Parent Directory":
        continue
        
    try:
        with page.expect_download() as download_info:
            link.click()
        download = download_info.value
        safe_name = f"file_{i:03d}_{filename}"
        download.save_as(os.path.join(DOWNLOAD_DIR, safe_name))
        print(f"📥 {safe_name}")
    except Exception as e:
        print(f"Пропущен {filename}: {e}")

💡 Добавьте page.wait_for_timeout(500) между загрузками, чтобы не перегружать сервер.

Пример 5. Скачивание через форму (динамическая генерация)

Часто файл создаётся после отправки формы:

page.goto("https://example.com/reports")
page.fill("#start_date", "2025-01-01")
page.fill("#end_date", "2025-04-01")

with page.expect_download() as download_info:
    page.click("#generate_report")

download = download_info.value
download.save_as(os.path.join(DOWNLOAD_DIR, "monthly_report.csv"))

Playwright не различает источник загрузки — главное, чтобы действие было обёрнуто в expect_download().

Пример 6. Интеграция с уведомлениями (Telegram + логирование)

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

def send_alert(message):
    # ваша функция из статьи про Telegram
    pass

try:
    with page.expect_download() as download_info:
        page.click("#export")
    download = download_info.value
    path = os.path.join(DOWNLOAD_DIR, "report.csv")
    download.save_as(path)
    
    if os.path.getsize(path) > 100:  # минимум 100 байт
        print("✅ Отчёт скачан")
    else:
        raise ValueError("Пустой файл")
        
except Exception as e:
    send_alert(f"Ошибка загрузки отчёта: {e}")

Функция send_alert() использует Telegram Bot API. Как её настроить — подробно описано в статье python telegram api send message .

Теперь вы всегда в курсе, даже если скрипт работает на сервере.

Советы для продвинутых

  • Проверяйте MIME-тип через download.url() — иногда сервер возвращает HTML вместо файла
  • Для PDF в Chrome добавьте:
context = browser.new_context(
    accept_downloads=True,
    bypass_csp=True,
    viewport={"width": 1920, "height": 1080}
)
  • Используйте абсолютные пути, особенно в cron-задачах

Заключение

Вы теперь умеете:

✅ Перехватывать любые загрузки в Playwright
✅ Сохранять файлы с оригинальным или кастомным именем
✅ Обрабатывать ошибки и таймауты
✅ Скачивать десятки файлов подряд
✅ Интегрировать в системы мониторинга

Это мощный инструмент для:

  • Автоматизации отчётности
  • Тестирования функций экспорта
  • Парсинга динамических сайтов

🐍 Playwright делает загрузку файлов простой — без внешних зависимостей и костылей.

🔁 Если вы используете Playwright для автоматизации, посмотрите также:
python playwright заполнить форму — работа с input, кнопками и ожиданиями
playwright proxy python — смена IP и User-Agent для защиты от блокировок
python playwright автологин — вход на сайт и сохранение сессии через cookies
💬 Остались вопросы? Пишите в комментариях — с радостью уточню, дополню или помогу с вашим кодом.
📢 Подписывайтесь на Telegram-канал PythonAuto, чтобы не пропустить новые гайды по автоматизации, парсингу и Python.
👉 Ваш интерес — лучшая мотивация для новых статей!

Оставьте комментарий