Skip to content

Тестовое с использованием Playwright и RabbitMQ

Notifications You must be signed in to change notification settings

LuchnikKek/test_playwright

Repository files navigation

Тестовое задание (Playwright, RabbitMQ, PostgreSQL)

wakatime

Парсер видео с каналов YouTube.

Стек:

  • Python 3.11.
  • Управление браузером: Playwright+Chromium (асинхронный api).
  • Хранилище: PostgreSQL (asyncpg).
  • Брокер очередей: RabbitMQ (aio-pika).
  • Запуск: Docker, Docker-compose.
  • asyncio, pydantic-settings, msgspec.
  • Управление зависимостями: Poetry.
  • Линтер, форматтер: ruff.

Краткое описание

Архитектурно система делится на два компонента: Crawler и Loader.

Crawler (Сборщик) асинхронно, в разных вкладках парсит данные и записывает в Rabbit.

Loader (Загрузчик) читает распаршенные данные из очереди и пишет в PostgreSQL.

Чтение и запись поддерживается в любом количестве вкладок (параметр BROWSER_MAX_WORKERS). Он же, но BROWSER_MAX_WORKERS+1 отвечает за максимальное количество соединений в пуле PostgreSQL.

Quickstart

Сразу после установки нужно разово запустить:

cp .env.template .env

Это установит переменные окружения для локальных запусков + поверх них докер будет писать свои.

Playwright поддерживает работу в Docker ТОЛЬКО в Headless режиме. Поэтому для локального использования нагляднее будет взять локальный вариант запуска.

Локальный вариант запуска (предпочтителен, поддерживает Headful)

В корне проекта запустить

make local_clean

К сожалению, он далеко не у всех просто ставится. Мне пришлось поставить ещё и в систему, а не только в окружение. Могу лишь дать ссылку на офф. доку :(

Docker-вариант запуска (Headless only, у меня собирался 180 секунд)

В корне проекта запустить

make up_clean

Make-команды

Прописал в Makefile несколько команд для работы с полученными образами.

Команда Описание
make down удаляет ВСЕ образы и volume
make up_loader запускает Loader, загружающий video_id в PostgreSQL
make up_crawler запуск Crawler в Докере
make up запускает Crawler и Loader в Докере,
БД остаётся та же
make up_clean запускает Crawler и Loader в Докере,
предварительно сносит БД
make local запускает Crawler локально и Loader в Докере,
БД остаётся та же
make local_clean запускает Crawler локально и Loader в Докере,
предварительно сносит БД

Большинство команд - чистый Docker Compose. В Makefile есть ещё комментарии.

Описание основных концепций

Изменение списка ссылок на каналы

Список ссылок можно посмотреть в write_links.py. С причинами отсутствия гибкой конфигурации списка ссылок можно ознакомиться там же.

PostgreSQL

Базовые DDL-операции по созданию структуры происходит через монтирование init.sql в Docker Compose. От себя добавил поля created_at (время создания записи) и updated_at (время обновление записи). Они проставляются автоматически.

Обновление updated_at происходит через триггер. Создаётся также в init.sql. Запись новых данных осуществляется с помощью создания временной таблицы и её MERGE с основной.

Подгрузка страниц

Playwright иногда присылает неполный список видео. Это не было частью задания, но я немного поработал над этим. Дополнительный таймаут после загрузки BROWSER_PAGE_ADDITIONAL_LOADING_TIME_MS позволяет получить больше данных.

Кроме того, иногда происходят запросы на гугл-сервисы, из-за чего вкладка бесконечно грузится и вылетает по таймауту. Частично решить проблему удалось с помощью их блокировки. BROWSER_REQUEST_ABORTION_CODE - код, имитируемый от них, можно брать из доки.

Иногда переходы по ссылке всё-таки отлетают по таймауту. Страница в таких случаях уже получена, поэтому просто мьючу ошибку и обрабатываю страницу.

Асинхронность

Самой медленной частью системы является Playwright и получение данных из сети. Для решения проблемы, я использовал официальный асинхронный модуль Playwright.

При запуске всё работает так:

  • Создаётся один браузер.
  • В рамках одной TaskGroup создаются воркеры-таски в количестве BROWSER_MAX_WORKERS
  • У каждого из воркеров есть своя вкладка в браузере и доступ к: входной очереди (ссылки на каналы) и выходной очереди (списки ссылок на видео с канала).
  • Воркеры работают бесконечно, вычитывая одну очередь и перекладывая в другую.

Таким образом всё выполняется в рамках одного потока и процесса. И без простоя, который был бы при полной параллельности.

RabbitMQ

Для каждого канала Сборщиком в Кролика передаётся только список id видео (не включая "v="), а в хедерах username канала, начиная с @. Загрузчик при прочтении самостоятельно собирает ссылки на видео.

Это уменьшает объём сообщений, которые нужно сериализовать, отправить, принять, десериализовать.

About

Тестовое с использованием Playwright и RabbitMQ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published