Поиск IT-железа по 30+ дистрибьюторам сразу: как мы собрали 114k SKU

от автора

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

Проблема, которую мы решали

Если вы хоть раз закупали IT-железо в B2B — вы знаете этот ритуал.

Приходит заявка: «Cisco WS-C2960S-48LPS-L, нужно 5 штук, в течение недели». Дальше — открываются 15–30 вкладок: личный кабинет Merlion, NetLab, Treolan, Marvel, плюс десяток мелких поставщиков. У каждого свой логин, своя структура каталога, своя политика «звоните узнавайте». Час времени уходит просто на то, чтобы собрать табличку «кто, по чём, когда».

Мы посмотрели на это и подумали: а что если один поиск по всем дистрибьюторам сразу, с реальными ценами и сроками, без регистраций и просмотра флэш-баннеров? Так появился Поиск IT (PoiskIT.ru).

Под капотом — 30+ источников, ~114 тысяч SKU в наличии. В этой статье — как мы это собираем, нормализуем и группируем.

Под капотом — 30+ источников, ~114 тысяч SKU в наличии. В этой статье — как мы это собираем, нормализуем и группируем.

Архитектура источников

Источники бьются на три категории:

1. Прямые API дистрибьюторов (4 канала, основная масса).

  • Merlion — самый большой каталог, retail + SMB-сегмент, 57k+ SKU

  • NetLab — смешанный IT/retail, 13k SKU

  • Marvel — retail + проектные позиции, 4k+ SKU «в наличии» из 6.7k всего, плюс ~692 млн ₽ складских остатков

  • Treolan — enterprise-сегмент (закрыт для внешних, но мы с ним работаем)

API у всех разные. Marvel отдаёт XML-фид с категориями в формате WITH RECURSIVE-дерева (родители + дети + leaf), NetLab — JSON с плоским списком и тегом категории, Merlion — REST с пагинацией. Внутри одной нашей таблицы distributor_categories мы храним их единообразно: distributordist_cat_idparent_dist_cat_idlevelis_leafvendors (jsonb), sku_countsku_in_stockstock_value_rub.

Раз в 6 часов — синк всего. Раз в сутки — пересборка дерева категорий и пересчёт остатков. Обновлённое время хранится в synced_at и показывается публично в UI («Обновлено 6 ч назад»).

2. Десятки B2B-поставщиков с прайсами по email. Это та категория, где «API» — это менеджер, который раз в неделю присылает Excel/CSV в почту. Мы их парсим автоматически, нормализуем колонки (артикул / наименование / цена / сроки / наличие), складываем в общий индекс. Парсинг каждой почты — отдельный кейс, и про граффли с кодировками cp1251 в Excel-фидах можно отдельную статью писать.

3. Розничные сигналы. Для популярных позиций мы дополнительно подтягиваем розничные источники как контрольную точку — чтобы видеть, насколько B2B-прайс адекватен текущему рынку.

Итого получается 30+ источников. У всех разный формат, разная частота обновлений, разная глубина каталога.


Нормализация партномеров: самая болезненная часть

Если думаете «ну подумаешь — артикул он и есть артикул», вот вам пять записей одной и той же Cisco WS-C2960S-48LPS-L из реальной БД:

WS-C2960S-48LPS-LWS-C2960S-48LPS-L=ws-c2960s-48lps-lWS-C2960S 48LPS-LWS-C2960S-48LPS-L_REF

Это всё один и тот же коммутатор, но у разных поставщиков он записан по-разному: с =-суффиксом (Cisco-нотация для «бесшасийной поставки»), пробелом вместо дефиса, с _REF для refurbished, в нижнем регистре.

Простой LOWER + TRIM тут не работает. Поэтому мы делаем многоэтапную нормализацию:

  1. Приведение к UPPER с сохранением латиницы (русские «С/О» в артикулах англоязычных вендоров — это отдельный ад)

  2. Удаление шумовых суффиксов=, , (NEW)(REF)_REF-USED

  3. Извлечение состояния в отдельное поле state (NEW / USED / REF) — чтобы потом можно было фильтровать

  4. Сохранение оригинального RAW-артикула — потому что иногда поставщику нужно прислать заказ ровно в том написании, как у него в системе

После нормализации все 5 строк выше схлопываются в один canonical_pn = WS-C2960S-48LPS-L, но каждая строка сохраняет свой raw_pn и state. Это критично для двух следующих фич.


Сгруппированный vs Плоский вид

Поиск может отдать результаты в двух режимах — переключатель прямо над таблицей.

Сгруппированный (дефолт): схлопывает все офферы с одинаковым canonical PN в одну строку. Видна минимальная цена, количество офферов, состояние.

Этот вид отвечает на вопрос «один SKU подешевле»: для каждого артикула — лучшая цена + сколько ещё дистров его предлагают (можно раскрыть строку и сравнить). Хорошо когда ты знаешь чёткий артикул и хочешь его купить.

Плоский — раскрывает каждый оффер в отдельную строку. Видны все дистрибьюторы рядом, можно отсортировать по цене / срокам / валюте прайса.

На скрине — 27 офферов Cisco WS-C2960S-48LPS-L от 15+ разных поставщиков. Минимум 20 740 ₽ (USED), максимум 276 427 ₽ (NEW, проектная цена). Видно нативные цены в USD у части дистров (484, 627, 700 USD), сроки транзита (43д, 39д, «под заказ»), даты прайса.

Чипы-фильтры наверху подтягиваются динамически из выдачи: можно отфильтровать по состоянию (NEW 20 / USED 6 / REF 1), бренду (CISCO 17 / Cisco 8), поставщикам (РУСТРЕЙДКОМ 7, UPGRADE 3 и т.д.).


Маркер «цена ниже рынка»

В плоском виде у некоторых строк рядом с ценой появляется значок ⚠ — это автоматическая пометка «оффер сильно ниже медианы по группе». Сейчас порог — ≤50% от медианы, считается отдельно для каждого canonical_pn по нативной валюте прайса (чтобы курсовые скачки не давали ложных срабатываний).

Пара слов про природу таких офферов — это полезно для понимания, что вы видите в выдаче.

Иногда — это реально остатки проекта. Заказчик отказался от поставки, у дистрибьютора зависло 20 коробок на складе, менеджер режет цену в два раза, чтобы сразу слить. Такие оффера обычно живут 1–3 дня и исчезают — отгрузил, и нет. Если успели — значок ⚠ ваш друг: можно купить нормальный товар вдвое дешевле рынка.

Но чаще — это лид-магнит. У всех картридж W1510A стоит 13–14 тыс. ₽, у одного — 825 ₽. Все звонят именно ему. Дальше начинается сценарий «здравствуйте, по вашему прайсу — есть в наличии?» и три типичных ответа:

  1. «Ой, эту строчку забыли убрать, у нас сейчас по 14 тыс. ₽» — прайс был приманкой

  2. «Есть, но он в резерве под другого клиента — могу записать вас в очередь, если откажется» — товара по этой цене как бы нет, но лид уже зацепили

  3. «Есть, но только в комплекте с принтером / партией от 50 штук / при предоплате 100%» — условия, которые в чистом виде на сайте не показаны

  4. «Перезвоните менеджеру, он уточнит» — заявку зафиксировали, лид в работе

Цель — собрать входящие звонки. Особенно это любят небольшие региональные поставщики, которым иначе никак не пробиться в топ выдачи рядом с Merlion/NetLab/Marvel.

Мы такие оффера из выдачи не вычищаем — они формально валидны, и иногда честные. Но  рядом с ценой + видимая медиана по группе в тултипе позволяют закупщику за полсекунды решить: тратить ли на этот звонок 15 минут или сразу идти к строке с реалистичной ценой.


AI-сводка по нечётким запросам

Не все запросы — точные артикулы. Часто человек пишет «Cisco коммутатор 48 портов PoE» — и не знает, какая именно модель ему нужна. На точный артикул мы выдаём таблицу. На нечёткий запрос — даём короткое описание того, что нашлось, и подсказки.

Текст сводки: «У нас представлены коммутаторы Cisco Catalyst серий 9200, 9300 и 3850 с 48 портами PoE — это управляемые L2/L3 модели для корпоративных сетей. Ключевые параметры: бюджет PoE (от 370 до 1440 Вт), поддержка uplink-портов 1G/10G/25G и стекирования. Обратите внимание на актуальность модели: серия 3850 уже снята с производства, рекомендуем аналоги из 9200 или 9300.»

Это не пересказ выдачи и не маркетинг — это попытка дать закупщику минимальный контекст, прежде чем он начнёт сравнивать цены. Особенно полезно когда серия EoL: вместо того, чтобы заказчик случайно купил снятую с производства модель, мы прямо в выдаче подсказываем «бери 9200/9300, а не 3850».

Сводка не показывается, если запрос — точный артикул (там она бессмысленна): бэк отвечает {skip: true} и блок просто не появляется.


AI-справка по партномеру

Когда вы уже нашли нужный артикул, у него рядом с PN в таблице есть иконка 🔍. Клик — открывается модалка «Справка по партномеру», которая параллельно делает 4 запроса:

  1. Изучает сайт вендора

  2. Читает datasheet (PDF, если доступен)

  3. Сверяет EoL-статус

  4. Ищет аналоги (если позиция снята с производства / refurb)

После того как все 4 шага завершились — модалка показывает:

  • описание модели

  • характеристики (порты, скорость, PoE-бюджет)

  • EoL-статус (Active / EoS / EoL) — цветной бейдж

  • декодинг артикула (если у вендора есть схема названий — какие части артикула что означают)

  • список аналогов (если EoL — что брать вместо)

Это закрывает типичную боль «купил, привёз заказчику — а оно снято с производства полтора года назад». Лучше узнать про EoL до отгрузки, а не после.

Результат справки кэшируется на стороне нашего бэка (pn_info_cache) — повторный клик на тот же PN отдаёт ответ мгновенно.


Карточки дистрибьюторов

Помимо общего поиска есть отдельный раздел /distributors — там можно «провалиться» в каталог любого из 4 прямых дистров и посмотреть его дерево категорий целиком.

Полезно, когда вам нужно понять, что вообще есть у этого поставщика. Например, Marvel — 399 категорий, 6 688 SKU, ~692.8 млн ₽ совокупного склада. Профиль смешанный: retail/consumer + проектные позиции, ёмкие категории — мультимедийное оборудование, телефоны/аудио, бытовая техника, ноутбуки и т.д.

Особенность карточки Marvel — рядом со счётчиком SKU мы показываем стоимость склада в ₽ по каждой категории. Этого пока нет у других дистрибьюторов (Marvel единственный отдаёт цены в категорийном фиде). Удобно, когда подбираешь поставщика под бюджет проекта: видно сразу, в какую категорию имеет смысл идти — две SKU за 50 тыс. ₽ или две тысячи SKU за 200 млн ₽ — разный разговор.

В остальном — количество SKU «в наличии» по каждой категории, как и в других карточках. Это не дамп каталога с битым стоком, это реальные товары на полке.


Лента новостей под поиском

Под основным поиском у нас крутится лента новостей. Правило одно: не повторяем то, что и так у всех. Если новость уже разнесли CNews, Хабр и ваш Telegram-канал — у нас её не будет.

Берём в основном то, что взлетело на западе — Bloomberg, FT, Reuters, CNBC, отраслевые блоги — но в русскоязычном сегменте либо вообще не выходило, либо вышло мелкой заметкой. И при одном условии: новость напрямую влияет на закупки у нас.

Идея простая: закупщику IT-железа полезно знать, что произойдёт с рынком через 2–4 недели — раньше, чем это станет «новой реальностью» в прайс-листе. Запад про это пишет уже сейчас, мы переводим, упаковываем в 2–3 абзаца с акцентом «что это значит для закупок в РФ» и выкладываем.

Каждая новость — со ссылкой на первоисточник. Не пересказ-в-пересказе, а адаптация под аудиторию закупщиков.


Цифры на сегодня

  • 30+ источников (4 прямых API + 20+ B2B-поставщиков по email + розничные сигналы)

  • 114 171 SKU в текущем активном индексе

  • ~4613 млн ₽ складских остатков, видимых через прямые API

  • 12 мс — медианное время ответа на поиск (DB-cache по нормализованному PN, TTL 15 мин)

  • 1.9 сек — то же время без кэша

Цифры не «продающие», а текущие — мы стартовали недавно и сами понимаем, что каталог нужно ещё расширять.


Что дальше

В ближайших планах:

  • Пакетный поиск — закидываете 50–500 артикулов одним списком, на выходе таблица «по каждому артикулу — лучшая цена + поставщик + срок», экспорт в Excel/CSV. Закрывает основной сценарий тендерной заявки на десятки SKU

  • Email-алерты по PN — подписка «уведомь меня, когда у любого из дистров появится в наличии X артикул дешевле Y₽»

И главное — мы открыты к подключению новых дистрибьюторов. Если вы дистрибьютор IT-железа и хотите быть в индексе — нам нужно от вас API или регулярный прайс. Пишите на info@poiskit.ru, разберёмся за день-два.


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

— Дмитрий Никонов, poiskit.ru

Это личный опыт работы над продуктом. Все упомянутые цифры и данные дистрибьюторов либо публичные, либо публикуются с согласия партнёров. AI-сводка — справочная, не заменяет официальные datasheets.

ссылка на оригинал статьи https://habr.com/ru/articles/1046067/