Commit Graph

11 Commits

Author SHA1 Message Date
Дмитрий 46426d586e feat(autopodbor): шов TwoGisReader + HtmlTwoGisReader + TwoGisJsonReader (TDD)
Фазы 2-3 плана self-render. Только новые файлы — существующий код не тронут,
xf4-путь цел. 281/281 юнит-тестов зелёные, Pint чисто.

- TwoGisReader — интерфейс разбора 2ГИС (3 метода: listing/card/branchList),
  единый контракт поверх HTML (xf4) ИЛИ initialState-JSON (self-render).
- HtmlTwoGisReader — xf4-путь: тонкий делегат к CategoryListingParser/
  DirectoryParser, поведение 1:1 (4 теста контракт-идентичности на реальных
  фикстурах 2gis-*-kraslombard).
- TwoGisJsonReader — self-render путь: разбор window.initialState по карте
  путей спайка (pagination-список → entity.profile), фильтр type=branch
  (фирма-в-фирму, без зданий/улиц). 5 тестов на реальных фикстурах: 12 фирм
  листинга, телефон+сайт карточки, 2 пути поиска-по-телефону, деградация.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 18:40:39 +03:00
Дмитрий df83fa836c feat(автоподбор): Конкурентное поле — финальный проход склейки, вскрыть всё, группы дублей, телефоны, отсев рекламных номеров 2ГИС
Шаг 1 «Конкурентное поле» — чекпоинт:
- Финальный проход «Найти и объединить дубли» на поле и предложениях; клиент решает по каждой группе, ничего не склеиваем молча.
- Тихая склейка только по сайту и коду справочника; телефон и людный номер у более чем 4 фирм — на решение клиента.
- Колонка phones jsonb; телефон-дубли видны уже на «Предложениях».
- Sonar даёт только имя и тип, сайт всегда через EXA; вскрываем все карточки без гейта «есть сайт».
- Яндекс-карточки через локальный Playwright параллельно; рубрика из заголовка идёт в описание.
- Фикс рекламных номеров: 2ГИС-парсер разбирает телефоны пообъектно и выкидывает рекламные кнопки с platforms/caption чужих фирм.

Тесты: автоподбор 224/224 unit, 105/105 feature; фронт-спеки зелёные. Времянки app/scripts/diag-*/probe-* в гит не входят.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-03 17:34:03 +03:00
Дмитрий cb688c334f fix(автоподбор шаг2): не плодить фальшивки из обрезков + надёжнее парсер 2ГИС
Два бага, вскрытых живым прогоном по КрасЛомбару (оба в обработке, не в xfetch):

1. Достройка коротких номеров лепила фальшивку из обрезка полного номера:
   сайт делит номер на tel:+7 (391) 271 и tel:271-33-33. Обрезок 7391271
   (страна+код города) ошибочно достраивался в 73917391271. Теперь обрезок
   «7/8 + код города» распознаётся и выкидывается; настоящие локальные
   (включая московские 771-..) — целы. Логику вынес в classifyShort/areaCode.

2. parseBranchList брал ссылку филиала только из href — на части прорисовок
   2ГИС ссылка лежит в JSON-данных, филиалы терялись. Берём путь /city/firm/<id>
   откуда угодно (с дедупом).

TDD: Autopodbor 49/49.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 13:27:27 +03:00
Дмитрий 1b76cfec15 feat(автоподбор шаг2): справочники 2ГИС через xfetch.ru
Антибот 2ГИС бьём сервисом xfetch.ru (render:true, timeout:20 —
без timeout страница не дорисовывается). Доказано на живом КрасЛомбаре:
поиск → 12 филиалов → телефон + адрес каждой карточки.

- PageFetcher — граница «достать HTML» (тестируется без сети)
- XfetchClient — POST к xfetch, декод base64; без ключа молча пусто
- XfetchDirectoryFetcher — список→филиалы→карточки через DirectoryParser
- DirectoryParser — чтение списка и карточки 2ГИС (был в хвостах)
- config services.xfetch + .env.example; ключ только в .env (gitignored)

Яндекс.Карты — отдельно (другой формат URL карточек). TDD: Autopodbor 46/46.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:38:18 +03:00
Дмитрий be92afebd3 test(автоподбор шаг2): достройка номеров не привязана к региону
Москва 495, Питер 812, Екатеринбург 343 — код города берётся со страницы
конкурента или из города запроса, никакой привязки к Красноярску. Защита
от регрессии. Autopodbor 41/41.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:16:18 +03:00
Дмитрий b78c3edb8c fix(автоподбор шаг2): не терять номера офисов, написанные без кода города
Сканер кода сайта выкидывал короткие локальные номера (271-33-33,
2-828-828 и т.п.) как мусор — терялись реальные телефоны филиалов.
Теперь короткий номер из tel:/schema/microdata достраивается кодом
города: сперва по преобладающему коду полных номеров той же страницы,
иначе по коду региона запроса; если код не определить — номер не
теряется, а помечается «требует проверки» (phoneKind=uncertain).
Из тела текста короткие формы не достраиваются (защита от ложных).

TDD: 6 новых тестов, весь Autopodbor 40/40.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:11:27 +03:00
Дмитрий 5ad50d8b8d feat(автоподбор): CandidateBuilder — код/подменный/пул/контакты/справочники
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:42:05 +03:00
Дмитрий d93404bc62 feat(автоподбор): SourceAggregator — дедуп, классификация, скрытие пула, сортировка + live-фикстура
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:16:48 +03:00
Дмитрий 0a450bf679 feat(автоподбор): CalltrackingDetector + DTO CollectedSource — детект подмены и источник с провенансом
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:16:35 +03:00
Дмитрий d50a3d5108 feat(автоподбор): HtmlPhoneScanner — номера из кода (tel/schema/microdata/тело/email)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:16:22 +03:00
Дмитрий bc462d25fa feat(автоподбор): PhoneType — тип номера по коду
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:16:05 +03:00