# Аудит источников и парсеров Дата последней проверки: **5 сентября 2026 года**. Аудит охватывает код репозитория, контрольные запросы к публичным HTML-страницам и публично описанные возможности потенциальных источников. Владелец RF4 Spotter подтвердил наличие разрешений на получение данных RF4DB и RF4-STAT; для новых кандидатов такого подтверждения пока нет. ## Итог Сейчас у проекта **два реально работающих канала данных**, но только **один автоматический внешний источник**: | Канал | Статус | Что даёт | Координаты | Доверие | |---|---|---|---|---| | Официальная таблица `rf4game.de` | подключена, HTML-импорт | рекорд, рыба, вес, водоём, приманка, игрок, дата | нет | 100 | | Собственная форма RF4 Spotter | подключена, после модерации | обычный улов, точка, снасть, игрок, скриншот | да | назначается приложением | `manual_import` существует в модели и seed, но отдельного пользовательского CSV/JSON-импортера нет. Seed — демонстрационные данные, а не источник. MinIO хранит доказательство пользовательской записи и также не является самостоятельным источником. ## Текущие парсеры В репозитории два HTML-парсера одной официальной таблицы: 1. `rf4_research.records.parse_records_html` — исследовательский адаптер и CLI; 2. `app.importer.parse_html` — продуктивный адаптер с HTTP-кэшем, повторами, журналом и сохранением. Оба ожидают один DOM-контракт `div.records.flex_table`, одинаковый порядок шести колонок и одинаково нормализуют вес, дату и пустые поля. Добавлен общий контрактный тест: на одной фикстуре парсеры обязаны вернуть одинаковые кортежи полей и оба обязаны отклонить изменённую структуру колонок. Контрольный HTML `https://rf4game.de/records/region/RU/` имел размер 1 147 837 байт. Оба парсера успешно прочитали **1260 записей**, результаты по восьми общим полям полностью совпали. Временный HTML в репозиторий не добавлен. ### Обнаруженные ограничения согласования - Дублирование кода двух парсеров остаётся риском. Контрактный тест защищает результат, но при следующем рефакторинге общую чистую функцию разбора лучше вынести в пакет, доступный и исследовательскому CLI, и API-контейнеру. - Источник настроен на немецкий домен. Регион `RU` фильтрует игроков, но названия рыб, водоёмов и приманок остаются немецкими. Они не совпадают с русскими названиями пользовательской формы и могут создать параллельные сущности. - Русский URL `https://rf4game.ru/records/region/RU/` при контрольном запросе вернул небольшую JavaScript-защитную страницу без таблицы; текущий парсер корректно завершился ошибкой `records table not found`. Обход защиты не рассматривается. - `source_external_id` надёжно убирает повтор одной и той же локализованной строки, но локализованные копии одной записи получат разные хеши. Нельзя считать разные языковые домены независимыми подтверждениями. - Официальная запись не содержит координат и поэтому не участвует в индексе конкретной точки. Автоматически связывать её с точкой нельзя. - Для новых агрегаторов одного enum `source_type` недостаточно: нужен стабильный `source_system`, внешний ID внутри этого источника, исходная ссылка и отдельное правило доверия. ## Где можно получить новые данные ### Приоритет A — тот же официальный источник Официальная навигация публикует абсолютные и недельные таблицы, а также категории `records`, `ultralight`, `recordslight`, `bottomlight`, `sea` и `telestick`. Это расширение охвата существующего источника, а не независимые подтверждения. Текущий DOM-парсер, вероятно, можно переиспользовать, но каждую комбинацию нужно сначала проверить отдельной фикстурой. Регулярный обход нельзя включать без согласования допустимой частоты с владельцем сайта. Рекомендуемый первый эксперимент — **недельные RU-рекорды одной категории**. Они полезнее абсолютных для свежести, не требуют новой схемы, но всё ещё не дают координат. ### Приоритет A — согласованные каналы сообщества Telegram, Discord и VK могут давать свежие координаты, оснастку, игровое время и скриншоты. Подключать следует только конкретные каналы, администраторы которых письменно разрешили импорт. Для каждого сообщения нужны permalink/message ID, время публикации, имя канала, версия правил и возможность удалить запись по запросу. Наиболее безопасная реализация — бот или форма, куда автор сам пересылает сообщение и подтверждает распознанные поля. Это лучше скрытого чтения групп и позволяет использовать существующую очередь модерации. ### Приоритет B — RF4DB (разрешение подтверждено владельцем проекта) `https://rf4db.com/ru` показывает актуальные пользовательские уловы, координаты, игровое время, погоду, снасть и изображения; публичная страница заявляет 19 водоёмов, 252 вида рыб и тысячи точек. Страница об источниках поясняет, что игровые справочники взяты из игры, а точки и комментарии собраны игроками в открытом доступе. Серверный HTML пригоден для адаптера; пилотный fail-closed парсер добавлен. Перед регулярным запуском нужно сохранить подтверждение разрешения и его условия: атрибуцию, частоту, удаление и допустимость ссылок на изображения. ### Приоритет B — RF4-STAT (разрешение подтверждено владельцем проекта) `https://rf4-stat.ru/help/` сообщает, что рекорды берутся с официального сайта, а точки и посты — из VK, Discord, Telegram и собственной формы. Сервис обновляет записи регулярно, часть доступа является Premium. Пилотные парсеры публичных `/fishing/` и `/posts/` добавлены с соблюдением `Crawl-delay`. Заблокированные координаты, погода, комментарии и интерактивная статистика не извлекаются. Данные, пришедшие туда с официального сайта, нельзя считать вторым независимым подтверждением. ### Исследовательские адаптеры — RF4MAP и RF4 Posts Публичная detail-страница RF4MAP содержит в серверном HTML устойчивый ID наблюдения, координаты, ID и название рыбы, ID водоёма, дату, клипсу, необязательные приманку, автора и изображения. Контрольная точка содержала **30 отдельных наблюдений**. Веса нет. `robots.txt` разрешает публичные страницы и запрещает `/api/`; исследование использует только HTML одной страницы. Публичная detail-страница RF4 Posts содержит устойчивый UUID точки, координаты, slug водоёма, список slug рыб, способ ловли, оснастку, клипсу, дату и ссылки на доказательства. Русская локализация позволяет связать slug с отображаемым названием. Контрольный пост дал **6 записей видов рыб из одной точки**. Это инструкция по точке, а не шесть доказанных индивидуальных уловов, поэтому вес остаётся `null`, а происхождение сохраняет общий UUID поста. Оба fail-closed парсера добавлены только в read-only исследовательский CLI. Они совместимы с `ExternalCatch`, но не включены в `data_source`, staging или расписание: сначала нужны разрешение, лимиты, правила атрибуции/изображений и решение о том, допустимо ли считать RF4 Posts наблюдением улова. Также проверены два менее пригодных кандидата: - `rf4pro.com` отдаёт минимальную SPA-оболочку, а `robots.txt` запрещает `/api/` и JSON; защищённые маршруты не исследовались, адаптер не добавлен; - `rr4farmtrof.com/RF4Records/` загружает таблицу клиентским запросом и по смыслу агрегирует официальные рекорды; это не независимое подтверждение, endpoint не запрашивался и адаптер не добавлен. ### Приоритет C — справочники Списки рыб, водоёмов, снастей, трофейных весов и переводов полезны для канонизации, но не для оценки текущего клёва. Источниками-кандидатами являются официальные страницы/патчноуты и разрешённый справочный экспорт партнёра. Нужны версия игры, язык и устойчивый внутренний ключ; сопоставление только по отображаемому имени недостаточно. ## Что не использовать - перехват трафика клиента, внедрение в игру и закрытые протоколы; - боты автоматической рыбалки и данные, полученные с нарушением правил игры; - обход JavaScript-защиты, CAPTCHA, авторизации или Premium-доступа; - массовое копирование чужих изображений и пользовательских постов без разрешения; - разные локализации официальной записи как разные подтверждения. ## Схема согласования новых адаптеров Каждый адаптер должен выдавать промежуточную запись со следующими группами полей: ```text provenance: source_system, source_external_id, source_url, observed_at, fetched_at identity: fish_external_id/name/language, waterbody_external_id/name/language catch: weight_g, caught_at, game_time, bait, method, rig, retrieve spot: x, y или null actor: player_name или null evidence: screenshot_url/key, raw_payload quality: moderation_status, source_confidence ``` До записи в `catch_report` должны последовательно выполняться: 1. валидация контракта источника; 2. нормализация единиц, времени и пустых значений; 3. сопоставление рыб/водоёмов по таблице алиасов с языком и версией игры; 4. дедупликация внутри `source_system`; 5. выявление кросс-источниковых копий без автоматического объединения сомнительных записей; 6. назначение доверия и модерации по политике источника; 7. сохранение происхождения и минимально необходимого сырого фрагмента. ## Рекомендуемый порядок работ 1. Добавить сущности `data_source` и `entity_alias`; включить источник в уникальный ключ внешней записи. 2. Вынести общий официальный DOM-парсер и оставить два тонких клиента вокруг него. 3. Добавить фикстуру недельной таблицы и проверить одну официальную категорию без расписания. 4. Согласовать экспорт/API с RF4DB и RF4-STAT; до ответа не писать их парсеры. 5. Выбрать один добровольный Telegram/Discord/VK-канал для пилота и зафиксировать согласие/правила удаления. 6. Только затем добавлять адаптер, контрактные тесты и калибровку `source_confidence`. ## Проверенные ссылки - официальный абсолютный рейтинг: - официальный недельный рейтинг: - RF4DB: и - RF4-STAT: - RF4MAP: - RF4 Posts: - отложенные кандидаты: и - исследовательский проект: