Допустим, есть задача написать парсер, который бы получал данные сайта и складывал их в локальную базу данных. На первый взгляд это очень простая и тривиальная задача, но при реализации оказывается, что многие сайты используют механизмы защиты от прямого парсинга. Такие защиты могут включать:
- Формирование HTML-страницы с помощью JavaScript.
- Ожидание специальных заголовков или куки.
- Блокировку «подозрительных» запросов.
Посмотрев на это, я немного приуныл и начал искать способ быстрее решить задачу. Мне нужно было решение, которое бы запускало парсер так, как если бы запрос выполнял обычный браузерный пользователь. В голову сразу пришла идея использовать Chromium как сервис внутри Docker. Я мог бы передавать ссылку страницы в этот сервис, а в ответ получать HTML уже после отработки JavaScript.
Выбор инструментов
Парсить я планирую на PHP. В качестве браузерного сервиса я выбрал Selenium. Также можно использовать Puppeteer, но он у меня не запустился под Docker, поэтому я отказался от него.
Selenium — это инструмент для тестировщиков, позволяющий автоматизировать действия на сайте с помощью эмуляции браузера. Мне достаточно одного браузера — Chrome, но Selenium поддерживает и другие браузеры. Подробнее можно прочитать на официальном сайте: https://www.selenium.dev
version: '3.8' services: selenium: image: selenium/hub:4.8.0 # Selenium Hub container_name: selenium_parser environment: - GRID_MAX_SESSION=5 - GRID_BROWSER_TIMEOUT=300 - GRID_TIMEOUT=300 networks: - network chrome: image: selenium/node-chrome:4.8.0 # Браузер Chrome shm_size: 2gb depends_on: - selenium environment: - SE_EVENT_BUS_HOST=selenium - SE_EVENT_BUS_PUBLISH_PORT=4442 - SE_EVENT_BUS_SUBSCRIBE_PORT=4443 networks: - network php: build: context: . dockerfile: Dockerfile container_name: parser_php volumes: - ./:/var/www/html depends_on: - selenium networks: - network networks: network: driver: bridge ipam: driver: default config: - subnet: 192.168.210.0/28
selenium — контейнер с нашим Selenium, который будет использоваться как сервис для запуска сайтов из браузера Chrome.
chrome — контейнер с браузером (можно добавить контейнеры с другими браузерами, если нужно).
php — контейнер с PHP-скриптом.
Поскольку я буду использовать стороннюю библиотеку Composer для взаимодействия с API Selenium, мне нужно, чтобы Composer был установлен в моем контейнере PHP. Для этого создаем дополнительный Dockerfile
для PHP.
# Используем базовый образ PHP 8.3 FROM php:8.3-fpm # Установка необходимых пакетов RUN apt-get update && apt-get install -y \ git \ unzip \ libpq-dev \ && docker-php-ext-install bcmath # Установка Composer COPY --from=composer:latest /usr/bin/composer /usr/bin/composer # Установка Symfony CLI RUN curl -sS https://get.symfony.com/cli/installer | bash \ && mv /root/.symfony*/bin/symfony /usr/local/bin/symfony # Установка прав доступа к директории WORKDIR /var/www/html
Запуск Docker Compose
Теперь все готово для запуска docker-compose
:
$ docker-compose up -f docker-compose.yaml
Обратите внимание, что я использую минимальный набор контейнеров. В реальном проекте для полноценного парсера потребуются контейнеры с HTTP-сервером, базой данных, Redis и т. д. Поскольку написание полноценного парсера выходит за рамки этого поста, здесь я привожу пример упрощенной конфигурации docker-compose
.
Заходим в контейнер PHP и инициализируем Composer:
$ docker exec -it parser_php bash docker# composer require php-webdriver/webdriver
После успешной инициализации Docker пишем небольшой скрипт на PHP для проверки работоспособности Selenium:
<?php require_once 'vendor/autoload.php'; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\Remote\DesiredCapabilities; // Подключение к Selenium Hub $host = 'http://selenium:4444/wd/hub'; // URL Selenium Hub $capabilities = DesiredCapabilities::chrome(); // Используем Chrome $driver = RemoteWebDriver::create($host, $capabilities); // Открываем страницу $driver->get('https://example.com'); // Получаем HTML страницы $html = $driver->getPageSource(); echo $html; // Закрываем браузер $driver->quit();
Все теперь можно из контейнера с php обращаться к любым сайтам через selenium как полноценный браузер Chrome, выполнять JS, можно эмулировать обычные действия пользователя на сайте, все зависит от вашей фантазии, задачи.
Теперь можно из контейнера PHP обращаться к любым сайтам через Selenium как полноценный браузер Chrome. Вы можете выполнять JavaScript, эмулировать действия пользователя на сайте — все зависит от ваших задач и фантазии.