Все статьиРуководства6 мин

Парсинг вакансий с авторизацией: логин через форму и sticky-сессии

Как собирать данные с площадок с вакансиями, требующих входа: авторизация через js_actions, session_id для сессий, extract_rules и хранение учётных данных.

Команда InfraProxy

22 февраля 2026 г.

#вакансии#авторизация#session_id#js_actions#extract_rules#скрейпинг

Задача: парсинг закрытых разделов

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

Авторизация через js_actions

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

Базовая схема

  1. Отправить запрос на URL страницы входа
  2. Заполнить поля формы через действия type
  3. Нажать кнопку входа через click
  4. Дождаться перехода (например, появления элемента личного кабинета) через wait_for
  5. Сохранить cookies и использовать их для последующих запросов

Пример запроса на логин

{
  "url": "https://example.com/jobs/login",
  "use_js_render": true,
  "session_id": "my-auth-session-1",
  "js_actions": [
    {
      "action": "type",
      "selector": "#email",
      "text": "user@company.com"
    },
    {
      "action": "type",
      "selector": "#password",
      "text": "SecurePassword123"
    },
    {
      "action": "wait",
      "ms": 500
    },
    {
      "action": "click",
      "selector": "button[type='submit']"
    },
    {
      "action": "wait_for",
      "selector": ".dashboard-header",
      "timeout": 10000
    }
  ]
}

Типы действий в js_actions:

  • type — ввод текста в поле (selector, text)
  • click — клик по элементу (selector)
  • wait — пауза в миллисекундах (ms)
  • wait_for — ожидание появления элемента (selector, timeout)
  • scroll — прокрутка к элементу или по оси Y

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

session_id для sticky-сессий

После успешного входа cookies привязаны к IP-адресу и браузерной сессии. Если следующий запрос пойдёт с другого IP, сайт не узнает авторизованного пользователя. Параметр session_id решает эту проблему.

Все запросы с одинаковым session_id выполняются через один и тот же прокси. Cookies, установленные при логине, автоматически передаются в последующих запросах — вы остаётесь «залогиненным».

Сценарий: логин + сбор списка вакансий

import requests
import os

API_URL = "https://api.example.com/api/v1/scrape"
API_KEY = os.environ.get("SCRAPER_API_KEY")
EMAIL = os.environ.get("JOBS_PORTAL_EMAIL")
PASSWORD = os.environ.get("JOBS_PORTAL_PASSWORD")
SESSION_ID = "jobs-crawl-session-001"

headers = {
    "x-api-key": API_KEY,
    "Content-Type": "application/json"
}

# Step 1: Login
login_payload = {
    "url": "https://example.com/jobs/login",
    "use_js_render": True,
    "session_id": SESSION_ID,
    "js_actions": [
        {"action": "type", "selector": "#email", "text": EMAIL},
        {"action": "type", "selector": "#password", "text": PASSWORD},
        {"action": "click", "selector": "button[type='submit']"},
        {"action": "wait_for", "selector": ".user-menu", "timeout": 10000}
    ]
}
r1 = requests.post(API_URL, headers=headers, json=login_payload)
if not r1.json().get("success"):
    raise Exception("Login failed")

# Step 2: Scrape job listings (same session_id)
listings_payload = {
    "url": "https://example.com/jobs/search?page=1",
    "use_js_render": True,
    "session_id": SESSION_ID,
    "extract_rules": {
        "jobs": {
            "selector": ".job-card",
            "type": "list",
            "fields": {
                "title": "h3",
                "company": ".company-name",
                "salary": ".salary",
                "link": "a@href"
            }
        }
    }
}
r2 = requests.post(API_URL, headers=headers, json=listings_payload)
data = r2.json()
print(data.get("data", {}).get("extract", {}))

Для пагинации или обхода нескольких страниц передавайте тот же session_id в каждый запрос — сессия сохранится.

Извлечение структурированных данных (extract_rules)

После логина страницы личного кабинета рендерятся с полным контентом. Используйте extract_rules, чтобы получать готовый JSON вместо сырого HTML.

{
  "url": "https://example.com/jobs/my-saved",
  "use_js_render": true,
  "session_id": "my-auth-session-1",
  "extract_rules": {
    "job_title": "h1.job-title",
    "company": ".employer-name",
    "salary_range": ".salary-info",
    "description": ".job-description",
    "posted_date": ".posted-at"
  }
}

Для списков вакансий используйте type: "list" и вложенные fields — см. пример выше с jobs.

Важно: extract_rules применяются к HTML после выполнения js_actions. Если контент подгружается динамически, убедитесь, что в js_actions есть wait_for на контейнер с данными, либо укажите js_wait_for в основных параметрах запроса.

Безопасное хранение учётных данных

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

export SCRAPER_API_KEY="your_api_key"
export JOBS_PORTAL_EMAIL="user@company.com"
export JOBS_PORTAL_PASSWORD="SecurePassword123"

В production — секреты из HashiCorp Vault, AWS Secrets Manager, GitLab CI/CD variables или аналогов. В no-code (n8n, Make.com) — встроенные Credentials с типом «Secret».

Рекомендуется отдельный служебный аккаунт для скрейпинга, не совпадающий с личным. Так можно ограничить права и при компрометации не терять основной доступ.

Важные нюансы

rawHtml vs extract_rules при авторизации

  • rawHtml — возвращает полный HTML. Подходит для отладки (проверить, что вы действительно на странице после логина) или для сложной постобработки.
  • extract_rules — возвращает только указанные поля. Меньше трафика и проще интеграция. При изменении вёрстки сайта селекторы могут сломаться — настройте мониторинг пустых или неполных extract.

Резидентные прокси

Площадки с вакансиями часто используют антибот-защиту. Датацентровые IP нередко блокируются или показывают CAPTCHA. Включите резидентные прокси (use_residential: true) — доля успешных запросов заметно вырастет, особенно при первом входе и обходе CAPTCHA.

session_ttl

Сессия с привязкой к одному прокси имеет ограниченное время жизни (session_ttl, по умолчанию 1800 секунд — 30 минут). Если сбор занимает дольше, увеличьте session_ttl (максимум обычно 86400 — 24 часа). После истечения TTL следующий запрос с тем же session_id получит новый IP, и cookies логина перестанут действовать. В этом случае потребуется повторная авторизация.

2FA и капчи

При двухфакторной аутентификации или CAPTCHA при входе автоматизация усложняется. Часть API поддерживает параметр solve_captcha — включите его для автоматического решения. 2FA чаще всего требует ручного ввода кода или интеграции с отдельным сервисом (SMS, TOTP) — рассматривайте возможность использования «длинной» сессии с увеличенным session_ttl, чтобы не логиниться при каждом прогоне.

Резюме

  • Используйте js_actions для заполнения формы входа и клика по кнопке
  • Передавайте один и тот же session_id во всех запросах — сессия и cookies сохранятся
  • Извлекайте данные через extract_rules после успешного логина
  • Храните логин, пароль и API-ключ в переменных окружения или секрет-менеджерах
  • Учитывайте: резидентные прокси для защищённых площадок, session_ttl для длительных сборов, ограничения при 2FA и капчах

Читайте также

InfraProxy предоставляет резидентные прокси для стабильного парсинга площадок с вакансиями и другими защищёнными источниками. Оставьте заявку.

Нужны надёжные прокси для вашего проекта?

InfraProxy предоставляет серверные и резидентные прокси для российского бизнеса. Договор, постоплата, техподдержка.