Бесплатный ИИ-агент для HH.ru: Python, Playwright, Ollama, Telegram | Гайд 2026 | AiManual
AiManual Logo Ai / Manual.
05 Июл 2026 Гайд

Пишем бесплатного ИИ-агента для автооткликов на HH.ru: Python, Playwright, Ollama и Telegram

Пошаговый гайд по созданию бесплатного ИИ-агента для автоматических откликов на HH.ru с использованием Python, Playwright, локальной LLM (Ollama) и Telegram.

Ручной поиск работы — это боль. Особенно отклики

Вы сидите, открываете HH, видите 20 вакансий, подходящих под ваш скилл Python/DevOps. На каждую нужно писать сопроводительное письмо. Через час у вас глаза на лбу, а откликнулись на три. Потом еще неделю ждете ответа — тишина. Знакомо?

Я прошел это в прошлом году и подумал: а почему бы не заставить нейросеть делать это за меня? Не вручную копипастить шаблоны, а по-настоящему интеллектуально анализировать вакансию и генерировать уникальное письмо под каждую. И все это бесплатно, локально, без облака и подписок.

Ранее мы уже разбирали похожие архитектуры в статье про российского локального AI-агента — там использовался похожий стек, но с фокусом на универсальность. Сегодня сделаем специализированного бойца для HH.

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

Архитектура агента: что под капотом

Нам нужно решить три задачи:

  • Парсинг вакансий — Playwright открывает HH, ищет вакансии по фильтрам, собирает данные (заголовок, описание, требования).
  • Генерация сопроводительного письма — Ollama с локальной LLM (например, Qwen2.5-7B-Instruct или Mistral Small 22B) получает промпт и генерирует персонализированный текст.
  • Отправка отклика и уведомление — Playwright заполняет форму и кликает «Откликнуться», а Telegram-бот пишет вам лог.

Всё на Python, без Docker (хотя для продакшна я бы завернул в контейнер). Связка: playwright → pydantic → ollama → python-telegram-bot.

Шаг 1: Поднимаем Ollama с моделью

Ollama — это, пожалуй, лучший способ запустить LLM локально. На 5 июля 2026 года актуальны модели Llama 4, Qwen3, Mistral Small 22B. Для автооткликов хватит 7-9B параметров — не гонитесь за гигантами, иначе ваш ноутбук расплавится.

Установка (Linux/Mac/WSL):

curl -fsSL https://ollama.ai/install.sh | sh
ollama pull qwen2.5:7b-instruct  # или mistral-small:22b
ollama serve

Проверяем, что модель отвечает:

curl http://localhost:11434/api/generate -d '{
  "model": "qwen2.5:7b-instruct",
  "prompt": "Напиши краткое сопроводительное письмо для Python-разработчика.",
  "stream": false
}'

Готово. Если у вас слабое железо, можно использовать внешний API, например AITunnel — он предоставляет стабильный доступ к мощным моделям через один шлюз. Но наша философия — полная бесплатность и локальность.

Шаг 2: Playwright — управляем браузером как бог

Playwright (версия 1.50+) умеет эмулировать реальный браузер, обходить простые антибот-системы. Установка:

pip install playwright
playwright install chromium

Критический момент — сохранение сессии. Каждый раз логиниться через смс/капчу — путь к безумию. Сохраняем куки после первого ручного входа:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=False)
    page = browser.new_page()
    page.goto('https://hh.ru/account/login')
    # тут вы логинитесь руками через 30 секунд
    page.wait_for_timeout(30000)
    # сохраняем куки и localStorage
    storage = page.context.storage_state(path='hh_auth.json')
    browser.close()

При следующем запуске просто загружаем storage_state — сессия восстановится. Без смс, без капчи (если не сменится IP).

Ошибка: Никогда не сохраняйте storage_state в открытом виде в репозитории. Используйте .env и шифрование. Один мой знакомый выложил сессию на GitHub — HH забанил аккаунт за час.

Шаг 3: Парсинг вакансий — не тупи, Playwright

Ищем вакансии по запросу «Python developer» с фильтром «удаленная работа» и зарплатой от 200 000 руб. Селекторы могут меняться, поэтому используем гибкий подход через текст и data-атрибуты. Пишем функцию, которая собирает все карточки с текущей страницы:

def parse_vacancies(page):
    page.goto('https://hh.ru/search/vacancy?text=python+developer&schedule=remote&salary_from=200000')
    page.wait_for_selector('[data-qa="vacancy-serp__vacancy"]')
    
    vacancies = []
    cards = page.query_selector_all('[data-qa="vacancy-serp__vacancy"]')
    for card in cards:
        title_el = card.query_selector('[data-qa="serp-item__title"]')
        link = title_el.get_attribute('href')
        title = title_el.inner_text()
        # также можно достать компанию, зарплату, описание
        vacancies.append({'title': title, 'link': link})
    return vacancies

Парсим N страниц (но не больше 5, чтобы не спамить HH).

Шаг 4: Генерация письма — момент истины

Переходим на страницу каждой вакансии, читаем полное описание. Затем отправляем промпт в Ollama:

def generate_cover_letter(vacancy_description, candidate_info):
    prompt = f"""Ты — опытный Python-разработчик, откликаешься на вакансию.
Информация о кандидате: {candidate_info}
Описание вакансии: {vacancy_description}

Напиши сопроводительное письмо (3-5 предложений), кратко и по делу.
Упомяни конкретные технологии из описания, покажи опыт.
Не используй шаблонные фразы."""
    
    import requests
    response = requests.post('http://localhost:11434/api/generate', json={
        'model': 'qwen2.5:7b-instruct',
        'prompt': prompt,
        'stream': False,
        'options': {'temperature': 0.7, 'max_tokens': 512}
    })
    return response.json()['response'].strip()

Кандидат-инфо — это ваш заранее заготовленный профиль (скиллы, опыт, GitHub, ключевые проекты). Лучше хранить в отдельном файле конфига.

Шаг 5: Отправка отклика через Playwright

На странице вакансии ищем кнопку «Откликнуться» или открываем форму отклика. Поле для сопроводительного (обычно textarea) и кнопка отправки:

def apply_to_vacancy(page, vacancy_link, cover_letter):
    page.goto(vacancy_link)
    # ждем загрузки
    page.wait_for_selector('[data-qa="vacancy-response-link-top"]')
    page.click('[data-qa="vacancy-response-link-top"]')
    # ждем появления поля для сопроводительного
    page.wait_for_selector('[data-qa="vacancy-response-letter"]')
    page.fill('[data-qa="vacancy-response-letter"]', cover_letter)
    page.click('[data-qa="vacancy-response-submit"]')
    # ждем подтверждения
    page.wait_for_timeout(2000)
    return page.url  # если перебросило — отлично

Снова важно: между откликами ставьте случайные задержки (3-15 секунд), иначе HH решит, что вы бот. Забавно, что мы и есть бот, но не надо так явно.

Шаг 6: Telegram-уведомления — вы в курсе

Установите python-telegram-bot (v21+). Создайте бота через @BotFather, получите токен. Отправляйте сообщение после каждого отклика:

import asyncio
from telegram import Bot

TELEGRAM_TOKEN = 'your_token'
CHAT_ID = 'your_chat_id'

async def notify(text):
    bot = Bot(token=TELEGRAM_TOKEN)
    await bot.send_message(chat_id=CHAT_ID, text=text)

# в основном потоке:
asyncio.run(notify(f'Откликнулся на {vacancy_title}: {vacancy_link}'))

Если вы хотите telegram-бота, который умеет давать команды «старт» и «стоп» — читайте наш подробный гайд Как превратить обычный Telegram-аккаунт в автономного ИИ-агента. Там показана интеграция Pyrogram для обхода ограничений.

Шаг 7: Собираем всё в систему

Агент должен работать циклически: раз в N часов запускать парсинг свежих вакансий и откликаться на непросмотренные. Используем schedule или apscheduler. Запускаем как service через systemd — подробнее в материале AI-агент, который не спит.

Примерный цикл:

def run_agent():
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True)
        context = browser.new_context(storage_state='hh_auth.json')
        page = context.new_page()
        
        vacancies = parse_vacancies(page)
        for v in vacancies:
            # читаем описание
            description = get_vacancy_description(page, v['link'])
            # генерируем письмо
            letter = generate_cover_letter(description, CANDIDATE_INFO)
            # откликаемся
            apply_to_vacancy(page, v['link'], letter)
            # задержка + уведомление
            time.sleep(random.randint(3, 10))
            asyncio.run(notify(f'Отклик на {v["title"]} отправлен'))
        
        browser.close()

Совет: Сделайте файл .env с переменными: HH_COOKIES_PATH, TELEGRAM_TOKEN, CHAT_ID, OLLAMA_URL, CANDIDATE_INFO. Тогда агента можно запускать на любом сервере, подменяя конфиг.

Грабли и нюансы (которые я наступил)

Капча

Time to time HH выкидывает капчу. Решений два: либо вставлять сервис распознавания (например, 2captcha — платно), либо снизить скорость и использовать headful режим с реальным браузером, рандомным user-agent и прокси. В 95% случаев, если не флудить, капча не появляется.

Лимиты на отклики

HH ограничивает число откликов в день (для обычного аккаунта в районе 15-20). Если превысить — аккаунт могут заморозить на сутки. Сделайте счетчик и стоп-кран.

Качество писем

Локальная 7B модель не всегда пишет идеально. Иногда она галлюцинирует технологии. Лучше использовать модель побольше (22B+), но это уже вопрос ресурсов. Мой рекорд — письмо с упоминанием «Django 6.0» которого еще не вышло. Рецепт: добавьте в промпт «проверь, что все указанные технологии существуют и соответствуют описанию».

Playwright и память

Каждый запуск браузера жрет ОЗУ. Если крутить агента каждые 15 минут — утечка неминуема. Используйте browser.close() и перезапускайте скрипт через cron раз в час.

Кстати, похожий проект мы описывали в статье Бесплатный ИИ-агент для HH.ru, но там упор на промпт-инжиниринг, а здесь — полный код.

А что насчет безопасности и этики?

HH — это бизнес, они продают рекрутерам доступ к базе. Массовый спам от автоматических откликов вредит их модели. Поэтому я не советую запускать агента на полную катушку. Лучше использовать его для точечного отклика на вакансии, которые реально интересны, а низкокачественные отклики фильтровать самому.

Если вы хотите сделать агента «невидимым» — эмулируйте поведение человека: скроллите, перемещайте мышь, кликайте с разной задержкой. В нашем гайде Как запустить AI-агента на старом Android-телефоне мы разбирали обход антибот-систем на эмуляторе Android — некоторые техники применимы и тут.

Небольшой прогноз в никуда

Через пару лет такие агенты станут стандартом поиска работы. Но вот парадокс: когда все будут использовать ИИ для откликов, HR-менеджеры перестанут читать сопроводительные. Тогда агент обесценится. Единственный способ оставаться в топе — создавать личный бренд и контент, а не спамить откликами. Агент — это инструмент для первого контакта, а не замена стратегии.

Не рекомендую запускать агента без тестирования на первом десятке вакансий. Проверьте, что письма не содержат бреда, что форма отправляется, что уведомления приходят. И помните: настоящий оффер приходит от живого общения, а не от автоматических откликов.

Подписаться на канал