Всем привет!
Сегодня я расскажу, как наша студенческая команда из СПбПУ разработала систему для сбора и анализа данных о российском IT-рынке труда с помощью платформы hh.ru. Вместо громоздкого монолита мы построили модульное асинхронное приложение на Python, сфокусировавшись на высокой производительности при массовом сборе данных, устойчивости к ошибкам и построении чёткого аналитического конвейера.
Если вам интересно, как эффективно собрать и обработать сотни тысяч записей из публичного API, построить отказоустойчивый пайплайн и сгенерировать аналитические отчёты — устраивайтесь поудобнее. Поехали!
Идея проекта
Рынок IT-вакансий невероятно динамичен. Чтобы понимать реальные тренды — какие навыки востребованы, какие компании больше всего нанимают и какие зарплаты предлагают — нужны данные. Много данных. Нашей целью был переход от домыслов к фактам. Мы решили создать систему, которая могла бы автономно:
Собирать актуальные данные о вакансиях с hh.ru через его публичный API.
Обрабатывать и очищать эти данные, устойчиво справляясь с ограничениями и ошибками API.
Надёжно хранить данные для анализа.
Выполнять сложные агрегации и генерировать визуальные отчёты по ключевым метрикам рынка.
Быть масштабируемой и поддерживаемой, позволяя расширять функциональность.
Мы выбрали модульную, сервис-ориентированную архитектуру на 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). Далее данные проходят несколько этапов:
Сбор и Валидация: Модуль
collectorасинхронно запрашивает вакансии. Полученный JSON проходит строгую проверку через Pydantic-модельVacancy, которая отсеивает некорректные записи и приводит данные к единому формату. Только после этого данные попадают в Базу данных (SQLite).Трансформация и Анализ: Модуль
analyzerзагружает данные из БД вpandas.DataFrame. Здесь происходит основная «магия»: группировка вакансий по ролям, расчёт медианных зарплат, подсчёт частоты навыков и анализ трендов.Визуализация: На основе готовых датафреймов модуль
infographicsгенерирует набор статических, но информативных графиков, готовых для включения в отчёт или дашборд.

Почему именно такой стек?
Асинхронность (
httpx,asyncio): Критически важна для обхода тысяч страниц вакансий без многодневного ожидания.Валидация (
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 (упоминался в десятках тысяч вакансий), за ним следуют Linux, Python, Git и 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 или дискуссии в репозитории!
Комментарии (9)

JBFW
21.12.2025 18:26Linux, Python, Git и PostgreSQL
Помню времена, когда в топе был PHP.
Но это не означало, что нужны были специалисты по PHP, это означало "я слышал что веб сайты делаются на PHP, Mysql и какой-то лампе, мне нужно вебсайт для лапшичной и поэтому я пишу в вакансии умное профессиональное слово PHP"Теперь "ИИ" делаются на Python. Если кому нужен ИИ для лапшичной - ну вы поняли...

SurMaster
21.12.2025 18:26ХХ помойкой стало в последнее время. Очень много фейковых вакансий, много всякого мусора и откровенного фуфла

kaichou
21.12.2025 18:26Если вам интересно, как эффективно собрать и обработать сотни тысяч записей
Извините, я не очень хорошо понял.
Сотни тысяч? Вы хотели сказать "сотни миллиардов"?
Удивляюсь, потому что вопрос "эффективной обработки" сотен тысяч структурированных текстовых записей - это уровень dBase IV от 1988 года, а не того стека, который вы тут нагородили...

ViseMoD
21.12.2025 18:26Обработка ~11 миллионов страниц вакансий для фильтрации 393 тысяч IT-вакансий заняла несколько суток непрерывной работы.
Правильно ли я понял смысл предложения: были выгружены все вакансии и лишь затем среди них отобраны относящиеся к ИТ?

souls_arch
21.12.2025 18:26То есть вы, уподобляясь минстату и прочим, анализируете данные фейковой помойки, которую можно использовать, разве что, как пример массовой дезинформации? Однако...
milssky
Что не сходится с вашей репой
В докерфайле так
> RUN apt-get install -y python3.12 python3-setuptools python3-pip python3.12-venv
а в статье питон3.10 =) Тоже самое и код пайдантика намекает на 1 версию (всякие parse_obj), а в репе в requirements.txt уже вторая версия pydantic.