#!/usr/bin/env python3 """Работа с браузером: открытие вакансии, клик «Откликнуться», вставка текста.""" import os from playwright.sync_api import sync_playwright # Селекторы hh.ru (с запасными вариантами) RESPONSE_BUTTONS = [ '[data-qa="vacancy-response-link-top"]', '[data-qa="vacancy-response-link"]', 'button:has-text("Откликнуться")', ] MESSAGE_FIELDS = [ 'textarea[data-qa="vacancy-response-letter"]', 'textarea[data-qa="vacancy-response-popup-form"] textarea', 'textarea', ] # Живые браузерные контексты по аккаунтам: {account_name: context} _browsers = {} def launch_context(account_dir): """Запускает браузер с профилем аккаунта (видимое окно).""" p = sync_playwright().start() context = p.chromium.launch_persistent_context( user_data_dir=os.path.join(account_dir, "profile"), headless=False, viewport={"width": 1400, "height": 900}, ) return context def get_context(account_dir, account_name): """Возвращает живой контекст аккаунта, создавая при необходимости.""" if account_name not in _browsers: _browsers[account_name] = launch_context(account_dir) return _browsers[account_name] def close_context(account_name): if account_name in _browsers: try: _browsers[account_name].close() except Exception: pass _browsers.pop(account_name, None) def open_response_page(context, vacancy, message, resume_id=None): """Открывает вакансию, жмёт «Откликнуться», выбирает резюме и вставляет текст. Возвращает (ok, note): ok=True если текст вставлен автоматически.""" page = context.new_page() page.goto(vacancy["url"], timeout=45000) page.wait_for_timeout(2500) # Кнопка «Откликнуться» clicked = False for sel in RESPONSE_BUTTONS: try: btn = page.locator(sel).first if btn.is_visible(timeout=3000): btn.click() clicked = True break except Exception: continue if not clicked: return False, "Не нашёл кнопку «Откликнуться» — сделайте это вручную" # Ждём модалку page.wait_for_timeout(2000) # Выбор резюме (радио-кнопка name="resumeId" value="{hash}") if resume_id: try: radio = page.locator(f'input[name="resumeId"][value="{resume_id}"]').first if radio.is_visible(timeout=3000): radio.check(force=True) print(f" ✓ Резюме {resume_id} выбрано") except Exception: print(" ⚠ Не нашёл радио-кнопку резюме — выберите вручную") # Вставляем текст for sel in MESSAGE_FIELDS: try: field = page.locator(sel).first if field.is_visible(timeout=3000): field.fill(message) return True, "Текст вставлен. Проверьте и нажмите «Отправить»" except Exception: continue return False, "Не нашёл поле сообщения — вставьте текст вручную"