Парсинг / RPA-автоматизация

JobCatcher

Десктопное приложение под Windows, которое в реальном времени отслеживает появление новых вакансий и фриланс-заказов одновременно на нескольких крупнейших площадках (hh.ru, freelance.ru, fl.ru), фильтрует их по гибко настраиваемым критериям и мгновенно доставляет пользователю единую персональную ленту релевантных предложений с возможностью отклика в один клик.
C# WPF

Задача

Поиск работы и заказов на разрозненных площадках - это рутина, в которой решает скорость. На фрилансе отклик, отправленный одним из первых, кратно повышает шанс получить заказ; релевантная вакансия, найденная через час после публикации, уже собрала десятки откликов. При этом каждая площадка живет по своим правилам: собственная авторизация, своя верстка, свои форматы дат и зарплат, активная защита от автоматизированного доступа.
Требовалось построить систему, которая:
  • объединяет несколько независимых площадок в единую ленту новых предложений;
  • обнаруживает новинки с минимальной задержкой и фильтрует их по зарплате, ключевым словам, свежести, формату работы и региону;
  • работает стабильно и автономно сутками, переживая разрывы сессий, редиректы, смену кодировок и анти-бот-проверки;
  • ведет отдельные изолированные профили под разные специализации и аккаунты, не смешивая их данные и сессии;
  • гарантирует отсутствие дублей - каждое предложение показывается ровно один раз.

Решение

Реализовано единое приложение-агрегатор с двумя независимыми конвейерами сбора (вакансии и фриланс-заказы), общим ядром доступа к сети и централизованным хранилищем.
Ключевые возможности:
  • Профили и мультиаккаунт. Каждый профиль хранит собственный поисковый запрос, фильтры (зарплата, удаленка, ключевые слова), учетные данные, индивидуальный прокси и набор целевых площадок. Профили обрабатываются независимо и параллельно.
  • Реальное время. Фоновые таймеры с раздельными интервалами опроса (фриланс-лента - каждые 30 секунд, вакансии - каждые 5 минут) обеспечивают появление нового заказа в интерфейсе в течение 30–60 секунд после публикации.
  • Умная фильтрация. Отсев по порогу зарплаты, OR-фильтр по списку ключевых слов (имя + описание), окно свежести (заказы старше 2 дней отбрасываются), исключение нерелевантных регионов.
  • Гарантированная уникальность. Многоуровневая дедупликация: по URL и по композитному ключу «название + зарплата + компания», что снимает повторы при перепубликациях и «премиум-поднятии» объявлений.
  • Мгновенное реагирование. Всплывающие уведомления, иконка в трее, email-оповещения и отклик/переход к заказу в один клик с автоматической подстановкой шаблона сопроводительного письма в буфер обмена.

Архитектура и сложности

Собственный HTTP-движок вместо браузерной автоматизации. Ядром системы стал написанный сетевой слой поверх HttpWebRequest (ParserWc : Parser), вынесенный в переиспользуемую библиотеку. Отказ от тяжелых браузерных решений дал на порядок меньшее потребление ресурсов и возможность работать сутками в фоне. Движок самостоятельно решает задачи, которые в браузере скрыты «под капотом»:
  • Ручная обработка редиректов (AllowAutoRedirect = false, разбор заголовка Location, разрешение относительных URL в абсолютные) - для полного контроля над цепочкой переходов и сохранения cookie на каждом шаге.
  • Файловый персистентный cookie-jar с собственным парсингом и сериализацией Set-Cookie, изолированный по аккаунтам. Сессии переживают перезапуск приложения, повторная авторизация не требуется.
  • Корректная работа с кодировками - автоопределение windows-1251 / utf-8 по метатегам и принудительное URL-кодирование кириллицы в теле запросов (типичная боль рунет-площадок).
  • Прозрачная декомпрессия (gzip/deflate), TLS 1.2, индивидуальный прокси на запрос, поддержка multipart-загрузки и асинхронного скачивания файлов.
Каждая площадка - отдельный «контракт». Площадки не имеют единого API, поэтому под каждую реализован свой адаптер: разные схемы авторизации (извлечение CSRF-токена, региональные редиректы hh.ru через cookie redirect_host, JSON-логин на id.freelance.ru), разная DOM-структура, разбираемая через XPath (HtmlAgilityPack), разные форматы выдачи.
Устойчивость к анти-бот-защите. Чтобы стабильно собирать данные, движок эмулирует поведение реального браузера: ротация из пула 10 000+ User-Agent, реалистичные заголовки (Sec-Fetch-*, client hints sec-ch-ua), корректные referer-цепочки, троттлинг запросов, изоляция cookie и прокси по аккаунтам, а также интеграция с сервисами распознавания (anti-captcha / rucaptcha) для автоматического прохождения защитных проверок.
Парсинг относительных дат на русском. Отдельный модуль RussianRelativeDateParser приводит человекочитаемые метки времени («30 минут назад», «2 часа 15 минут назад», «1 июня, 00:20») к точному DateTime - это основа фильтра свежести и корректной сортировки ленты.
Конкурентность и отзывчивый UI. Два независимых конвейера (StartWork / StartFl) запускаются на DispatcherTimer + Task с защитой от наложения запусков (новый цикл не стартует, пока выполняется предыдущий). Вся работа с сетью и БД вынесена из UI-потока, обновление интерфейса выполняется через Dispatcher.BeginInvoke - окно остается отзывчивым при непрерывном фоновом сборе.
Надежное хранилище. Persistence построен на Entity Framework 6 (Code First с автомиграциями) поверх MS SQL Server, с индексами на полях, по которым идет частая выборка (статус «просмотрено», тип). Схема эволюционирует без ручных миграций.

Результат

  • 3 разнородные площадки объединены в одну ленту с единой моделью данных, фильтрацией и дедупликацией.
  • Задержка обнаружения нового предложения - 30–60 секунд: время реакции на заказ сокращено с десятков минут ручного мониторинга до секунд, что напрямую повышает конверсию откликов на конкурентном фрилансе.
  • До 500 позиций за один запрос страницы поиска с автоматическим постраничным обходом всей выдачи.
  • Близкая к нулю доля дублей благодаря многоуровневой дедупликации - лента не «зашумляется» повторными публикациями.
  • Автономная работа 24/7 в фоне с самостоятельным поддержанием авторизованных сессий и устойчивостью к редиректам, сменам кодировок и анти-бот-проверкам.
  • Полная изоляция профилей и аккаунтов (отдельные cookie, прокси, фильтры) - одна установка обслуживает несколько специализаций одновременно.
  • Сетевое ядро спроектировано как переиспользуемая библиотека и применимо за рамками этого продукта в любых задачах сбора данных.

Стек

  • Язык и платформа: C#, .NET Framework 4.8
  • UI: WPF / XAML, системный трей (NotifyIcon), всплывающие окна уведомлений
  • Доступ к данным: Entity Framework 6 (Code First, Automatic Migrations), MS SQL Server
  • Сбор и разбор данных: собственный HTTP-движок поверх HttpWebRequest (cookies, proxy, редиректы, кодировки, multipart, async-загрузка), HtmlAgilityPack (XPath)
  • Многопоточность: TPL (Task), DispatcherTimer, маршалинг в UI-поток
  • Интеграции: MailKit / MimeKit (SMTP-уведомления), сервисы распознавания капчи (anti-captcha / rucaptcha)
  • Прочее: Newtonsoft.Json (конфигурация и сериализация профилей), регулярные выражения для разбора дат, зарплат и токенов
 
Сюда Туда