Всем привет!

Сегодня я расскажу, как наша студенческая команда из СПбПУ разработала систему для сбора и анализа данных о российском IT-рынке труда с помощью платформы hh.ru. Вместо громоздкого монолита мы построили модульное асинхронное приложение на Python, сфокусировавшись на высокой производительности при массовом сборе данных, устойчивости к ошибкам и построении чёткого аналитического конвейера.

Если вам интересно, как эффективно собрать и обработать сотни тысяч записей из публичного API, построить отказоустойчивый пайплайн и сгенерировать аналитические отчёты — устраивайтесь поудобнее. Поехали!

Идея проекта

Рынок IT-вакансий невероятно динамичен. Чтобы понимать реальные тренды — какие навыки востребованы, какие компании больше всего нанимают и какие зарплаты предлагают — нужны данные. Много данных. Нашей целью был переход от домыслов к фактам. Мы решили создать систему, которая могла бы автономно:

  1. Собирать актуальные данные о вакансиях с hh.ru через его публичный API.

  2. Обрабатывать и очищать эти данные, устойчиво справляясь с ограничениями и ошибками API.

  3. Надёжно хранить данные для анализа.

  4. Выполнять сложные агрегации и генерировать визуальные отчёты по ключевым метрикам рынка.

  5. Быть масштабируемой и поддерживаемой, позволяя расширять функциональность.

Мы выбрали модульную, сервис-ориентированную архитектуру на Python, потому что это позволило:

  • Чётко разделить ответственность (сбор данных, хранение, анализ, визуализация).

  • Масштабировать компоненты независимо (например, запускать несколько сборщиков данных).

  • Легко тестировать и отлаживать отдельные части системы.

  • Сделать проект легковесным и сфокусированным на его основной задаче — обработке данных.

Архитектура решения

Наша система построена по принципу чёткого разделения ответственности. Каждый модуль выполняет одну задачу и общается с другими через простые интерфейсы. Это классический пайплайн ETL (Extract, Transform, Load), адаптированный под особенности hh.ru API.

Вот из каких ключевых компонентов состоит система:

Ядро системы (Python 3.10):

  • data_collector: Асинхронный сборщик данных, взаимодействующий с API hh.ru.

  • db_manager: Менеджер для работы с базой данных SQLite.

  • analytics: Модуль для анализа данных и генерации графиков.

  • models: Pydantic-модели для валидации и структурирования данных.

Вспомогательные технологии:

  • httpx: Для асинхронных HTTP-запросов к API.

  • pydantic: Для валидации и парсинга сырых JSON-данных в строгие модели.

  • pandas: Для оперативной агрегации и анализа данных в памяти.

  • matplotlib/seaborn: Для построения всех графиков и визуализаций.

  • SQLite: В качестве ��адёжного и лёгкого хранилища для структурированных данных.

Схема работы данных

Всё начинается с источника данных — публичного API hh.ru (версия 1.0.0). Далее данные проходят несколько этапов:

  1. Сбор и Валидация: Модуль collector асинхронно запрашивает вакансии. Полученный JSON проходит строгую проверку через Pydantic-модель Vacancy, которая отсеивает некорректные записи и приводит данные к единому формату. Только после этого данные попадают в Базу данных (SQLite).

  2. Трансформация и Анализ: Модуль analyzer загружает данные из БД в pandas.DataFrame. Здесь происходит основная «магия»: группировка вакансий по ролям, расчёт медианных зарплат, подсчёт частоты навыков и анализ трендов.

  3. Визуализация: На основе готовых датафреймов модуль infographics генерирует набор статических, но информативных графиков, готовых для включения в отчёт или дашборд.

Рис1. - Перемещение данных.
Рис1. - Перемещение данных.

Почему именно такой стек?

  • Асинхронность (httpxasyncio): Критически важна для обхода тысяч страниц вакансий без многодневного ожидания.

  • Валидация (pydantic): Гарантирует целостность данных при сохранении. Мы точно знаем, что в БД попали только данные правильного формата.

  • SQLite: Для одноразового аналитического пайплайна с данными в ~500k записей — это идеальный выбор, работает быстро и надёжно.

  • pandas: Фактический стандарт для анализа табличных данных в Python. Позволяет за несколько строк кода выполнить сложные агрегации, на которых в SQL ушло бы гораздо больше времени.

Такой подход позволил нам создать не «чёрный ящик», а прозрачную, ремонтопригодную систему, где каждый этап обработки данных можно проверить и доработать.

Технические детали реализации

Давайте заглянем под капот и посмотрим, как реализованы ключевые модули системы. Весь код доступен в нашем открытом репозитории на GitHub.

1. Асинхронный сборщик данных (Collector)

Сердце системы — модуль collector.py, который обходит API hh.ru. Главные задачи: масштаб (сотни тысяч вакансий) и устойчивость (API имеет лимиты и может возвращать ошибки).

Ключевые решения:

  • Асинхронность: Используем asyncio и httpx для одновременной обработки множества запросов. Это ускорило сбор по сравнению с синхронным подходом.

  • Контроль ошибок: Система обрабатывает HTTP-ошибки 429 (слишком много запросов) и 403 (запрещено), делая паузы и логируя проблемные ID вакансий для повторной попытки.

  • Валидация на лету: Каждый полученный JSON-объект сразу проходит проверку через Pydantic-модель. Это защищает базу данных от "мусора".

# Упрощённый пример асинхронного запроса с обработкой ошибок
import httpx
from models.vacancy_model import Vacancy

async def fetch_vacancy(session: httpx.AsyncClient, vacancy_id: int) -> Vacancy | None:
    url = f"https://api.hh.ru/vacancies/{vacancy_id}"
    try:
        response = await session.get(url, timeout=10.0)
        response.raise_for_status()
        # Парсинг и валидация через Pydantic
        return Vacancy.parse_obj(response.json())
    except httpx.HTTPStatusError as e:
        if e.response.status_code == 404:
            # Вакансия не найдена - это нормально, пропускаем
            return None
        logger.warning(f"HTTP error for {vacancy_id}: {e}")
        return None

2. Модель данных и работа с БД

Pydantic-модель Vacancy — это строгий контракт, описывающий, как должны выглядеть наши данные. Она автоматически приводит типы (например, строку с зарплатой к числу) и отбрасывает лишние поля.

# Упрощённая схема модели Vacancy
from pydantic import BaseModel

class Vacancy(BaseModel):
    id: int
    name: str
    salary_from: Optional[int] = None
    salary_to: Optional[int] = None
    employer_name: str
    key_skills: Optional[str] = None
    # ... другие поля

Работа с SQLite организована через модуль db_manager. Мы сознательно не использовали ORM, чтобы сохранить полный контроль над запросами и производительностью. Все взаимодействия с БД — через параметризованные SQL-запросы.

3. Анализ и визуализация

После загрузки данных из SQLite в pandas.DataFrame анализ становится простым и выразительным:

# Пример расчёта медианной зарплаты по ролям
import pandas as pd

def calculate_median_salaries(df: pd.DataFrame) -> pd.DataFrame:
    # Создаём условную "среднюю" зарплату для анализа
    df['salary_mid'] = df[['salary_from', 'salary_to']].mean(axis=1)
    # Группируем по профессиональной роли и считаем медиану
    median_by_role = df.groupby('professional_role')['salary_mid'].median()
    return median_by_role.sort_values(ascending=False).head(15)

Модуль infographics.py использует matplotlib и seaborn для превращения этих датафреймов в готовые для публикации графики. Мы создали единый стиль для всех графиков, чтобы визуализация выглядела профессионально.

4. Особенности и "фишки" реализации

  • Конфигурация через переменные окружения: Все чувствительные настройки (например, задержки между запросами) вынесены в private_settings.py, который не попадает в Git.

  • Детальное логирование: Каждый этап — от сбора до визуализации — подробно логируется. Это позволило легко отлаживать систему и понимать, на каком этапе возникла проблема.

Производительность

  • Сбор данных: Обработка ~11 миллионов страниц вакансий для фильтрации 393 тысяч IT-вакансий заняла несколько суток непрерывной работы. Использование асинхронности позволило загружать CPU на 80-90%.

  • Аналитика: Расчёт всех метрик (топ навыков, зарплаты, распределение) для финального датасета занимает менее 5 минут на обычном ноутбуке.

  • Память: Пиковое использование памяти не превышает 2-3 ГБ благодаря потоковой обработке и эффективной работе pandas.

Результаты и выводы

После нескольких суток непрерывного сбора данных и их обработки мы получили детальную картину российского IT-рынка на 2025 год. Вот какие инсайты удалось извлечь из 393 тысяч вакансий.

Что увидели в данных?

1. Концентрация рынка: всё решают гиганты
Анализ данных показал впечатляющую концентрацию спроса. На первую десятку компаний-работодателей (Сбер, Ozon, Яндекс, Т1 и другие) приходится свыше 70% всех IT-вакансий. Это говорит о том, что рынок в значительной степени формируется стратегиями найма крупнейших игроков.

2. «Обязательный минимум» разработчика универсален
Самые востребованные технические навыки оказались вполне предсказуемыми, но от этого не менее важными. Абсолютным лидером стал SQL (упоминался в десятках тысяч вакансий), за ним следуют LinuxPythonGit и PostgreSQL. Этот набор можно считать новым «джентльменским набором» IT-специалиста широкого профиля. Среди soft skills лидируют «Клиентская коммуникация» и «Аналитическое мышление».

3. Рынок труда для джуниоров сужается
Несмотря на общий объём вакансий, данные подтвердили тренд, о котором много пишут: сложный вход в IT для новичков. Большинство вакансий (около 96%) — на полную занятость, и более 82% требуют опыта работы от 1 года. Абсолютно доминирует формат полного рабочего дня в офисе (72.3%), в то время как доля полностью удалённых вакансий составляет около 23%.

4. Зарплаты: ожидаемая иерархия
Расчёт медианных зарплат подтвердил логику рынка. На верхушке находятся руководители направлений (250 000+ руб.) и DevOps-инженеры (215 000+ руб.). Специалисты в области Data Science и системные аналитики также входят в топ с зарплатами от 200 000 руб. Интересно, что разрыв между middle и senior-уровнем во многих специализациях не такой большой, как между junior и middle.

Кому может быть полезен этот проект?

  • Начинающим data-инженерам и дата-сайентистам: Весь код в открытом доступе и может служить учебным примером построения end-to-end ETL/ELT пайплайна на Python.

  • HR-специалистам и аналитикам рынка: Методология и готовые скрипты могут быть адаптированы для конкурентного анализа или исследования нишевых сегментов рынка.

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

Исходный код проекта доступен на GitHub

Если у вас есть вопросы по реализации, предложения по улучшению кода или идеи для совместного исследования — добро пожаловать в issues или дискуссии в репозитории!