С инженерной точки зрения поиск работы — это процесс с низкой энтропией. Есть входящий поток данных (JSON с вакансиями) и есть необходимость отправить ответный сигнал (POST-запрос с откликом). Задача кажется тривиальной для автоматизации: написал парсер, настроил cron, пошел пить кофе.

Однако, если вы попробуете автоматизировать отклики на крупных job-board платформах (особенно на hh.ru) в 2026 году, вы столкнетесь с серьезным противодействием. WAF (Web Application Firewall), анализ TLS-отпечатков, поведенческая биометрия и теневые баны — это реальность, которая убивает скрипты на requests за пару часов.

В этой статье разберем архитектуру решения, которое позволяет автоматизировать процесс отклика, используя подходы RPA (Robotic Process Automation), мимикрию под поведение пользователя (Human Mimicry) и LLM для обхода смысловых фильтров.

(Дисклеймер: Статья носит исследовательский характер. Мы не призываем нарушать правила площадок, а разбираем технические методы эмуляции браузера).

Проблема 1: Почему requests больше не работает

Эпоха, когда можно было притвориться браузером, просто подставив User-Agent в заголовки, прошла лет 5 назад.

Современные системы защиты (Akamai, Cloudflare, Qrator и самописные решения площадок) анализируют TLS Fingerprint (JA3/JA3S). Стандартный клиент Python (будь то requests, aiohttp или httpx) имеет характерный порядок шифров при SSL-рукопожатии, который кардинально отличается от реального Chrome или Safari.

Симптомы:

  • Вы получаете 403 Forbidden на первый же запрос.

  • Вам отдают страницу с бесконечной капчей.

Можно использовать библиотеки с подменой TLS (например, curl_cffi), но это решает проблему только для парсинга (GET-запросы). Для совершения отклика (нажатие кнопок, ввод текста, работа с динамическим JS) необходим полноценный браузер.

Проблема 2: Headless Browser и его детекты

Мы переходим к Selenium или Playwright. Запускаем браузер в режиме headless=True (без графического интерфейса), чтобы экономить ресурсы сервера.

И тут нас ловит защита на клиенте (в JS).

Существует сотни признаков, выдающих бота:

  1. navigator.webdriver = true — классика.

  2. WebGL Fingerprint: У серверных видеокарт (которые рендерят страницу в headless) вендоры — это Google SwiftShader или VMware, а не NVIDIA или Intel Iris.

  3. Отсутствие плагинов: У живого человека всегда есть какой-то мусор в объекте navigator.plugins.

  4. Размер окна: Дефолтный 800x600 сразу выдает бота.

Решение: Патчинг на уровне браузера

Использование stealth-plugin для Puppeteer/Playwright помогает, но ненадолго.

Для стабильной работы мы используем кастомные сборк�� Chromium, где на уровне исходного кода вырезаны флаги автоматизации. Плюс — жесткая привязка профиля:

  • Каждому воркеру выдается уникальный «цифровой слепок» (Fingerprint).

  • Используются резидентские прокси (Datacenter IP моментально флагаются).

Проблема 3: Поведенческая биометрия (Behavioral Analysis)

Допустим, мы обошли технические проверки. Браузер выглядит как настоящий. Мы находим кнопку «Откликнуться» и кликаем.

Бан.

Почему? Потому что скрипт наводит курсор мгновенно. Или по идеальной прямой линии.

Современные скрипты антифрода пишут трек движения мыши. Человеческая рука имеет тремор, инерцию, разгон и торможение.

Реализация Human Mimicry (Кривые Безье)

Чтобы обойти это, мы написали модуль движения курсора, основанный на кубических кривых Безье.

Псевдокод логики движения:

Python

import numpy as np

def generate_human_path(start_x, start_y, end_x, end_y):
    # Добавляем случайные контрольные точки для отклонения от прямой
    ctrl_1_x = start_x + np.random.randint(-50, 50)
    ctrl_1_y = start_y + np.random.randint(-50, 50)
    
    # Генерируем точки кривой Безье
    t = np.linspace(0, 1, num=50) # 50 шагов анимации
    path_x = (1-t)**3 * start_x + 3*(1-t)**2 * t * ctrl_1_x ... 
    
    # Важно: добавить "шум" (микро-дрожание)
    noise = np.random.normal(0, 1.5, size=len(path_x))
    return path_x + noise, path_y + noise

Кроме того, бот никогда не жмет кнопку сразу. Он:

  1. Скроллит страницу вниз (эмуляция чтения).

  2. Делает паузу (Random Sleep от 3 до 12 секунд).

  3. Выделяет текст (иногда).

  4. Только потом кликает.

Архитектура системы

Чтобы масштабировать это решение (один браузер потребляет до 1 ГБ RAM), мы пришли к следующей архитектуре:

  • Core (Python/FastAPI): API-шлюз и база данных (PostgreSQL).

  • Orchestrator: Очередь задач (Redis). Контролирует лимиты. Важно: мы не разрешаем отправлять более 20 откликов в сутки с одного аккаунта, чтобы не триггерить поведенческие аномалии на бэкенде платформы.

  • Browser Nodes: Docker-контейнеры с Playwright. Поднимаются on-demand, отрабатывают сессию и умирают, очищая память.

  • LLM Module: Self-hosted Llama (или API OpenAI) для генерации текста.

Зачем здесь LLM?

  1. Парсинг верстки: CSS-селекторы меняются. Мы скармливаем LLM кусок DOM-дерева и просим вернуть JSON с описанием вакансии. Это устойчивее к редизайну сайта.

  2. Генерация Cover Letter: Шаблонные письма («Прошу рассмотреть...») имеют низкую конверсию. Модель читает вакансию и пишет ответ, подсвечивая релевантный опыт из резюме.

Автоматизация карьерной рутины — это классическая задача "Red Team vs Blue Team". На каждое действие (улучшение скрипта) платформа отвечает противодействием (новые метрики детекта).

В 2026 году написать простой скрипт для поиска работы уже невозможно. Порог входа вырос до уровня разработки полноценной RPA-системы с элементами AI. Стоит ли оно того? Учитывая, что это экономит десятки часов на механический скроллинг ленты — определенно да.

P.S. Где посмотреть тесты?

Мы проводим открытое тестирование системы. Публикуем логи обхода защит, сравниваем конверсию «ручного» поиска против RPA и делимся статистикой по офферам в разных грейдах.

Кому интересна техническая сторона вопроса или хочется протестировать агента на своем профиле — welcome в наш канал: [Ссылка на ТГ-канал]