/rootКодинг медитация→ Обход защиты сайтов от парсинга данных или anti-anti-scraping

, ,

12 января, 2025

Обход защиты сайтов от парсинга данных или anti-anti-scraping

Допустим, есть задача написать парсер, который бы получал данные сайта и складывал их в локальную базу данных. На первый взгляд это очень простая и тривиальная задача, но при реализации оказывается, что многие сайты используют механизмы защиты от прямого парсинга. Такие защиты могут включать:

  • Формирование 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, эмулировать действия пользователя на сайте — все зависит от ваших задач и фантазии.

Так же может быть интересно:

Расширение всех файлов в XML формате
Создаем систему для партнерских программ в WordPress
URL без завершающих слэшей и www
Очистка кэша Open Graph для VK и Telegram