Допустим, есть задача написать парсер, который бы получал данные сайта и складывал их в локальную базу данных. На первый взгляд это очень простая и тривиальная задача, но при реализации оказывается, что многие сайты используют механизмы защиты от прямого парсинга. Такие защиты могут включать:
- Формирование 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, эмулировать действия пользователя на сайте — все зависит от ваших задач и фантазии.
