mirror of
https://gitverse.ru/kpa39l/vesti.git
synced 2026-09-29 09:55:03 +00:00
85 lines
6.6 KiB
Markdown
85 lines
6.6 KiB
Markdown
# Proposal: rss-crawler
|
||
|
||
## Why
|
||
|
||
В VESTI сейчас есть только telegram_crawler (Telethon, MTProto). RSS-источники —
|
||
самый массовый и дешёвый класс источников (по оценке PRD — ~80% объёма новостей):
|
||
веб-СМИ, блоги, IT-порталы публикуют RSS/Atom-ленты. Без RSS-краулера они недоступны.
|
||
|
||
Проблемы, которые решает модуль:
|
||
- **нет спроса на RSS вовсе**: в источники (sources.yaml) нельзя добавить ни одного
|
||
RSS-канала — краулер просто не умеет их обрабатывать (`get_enabled_sources(crawler="rss")` вернёт пусто);
|
||
- **негражданный режим опроса**: без If-None-Match/If-Modified-Since каждый запуск
|
||
тянет полные ленты — это лишний трафик для издателей и для нас;
|
||
- **мусорные ссылки**: URL из лент часто содержат UTM-метки, якоря, трекеры —
|
||
дедупликация по сырому URL даёт дубли одной статьи;
|
||
- **обрывки вместо текста**: многие ленты отдают summary вместо полного текста —
|
||
без дотягивания полного текста карточки кандидатов бедные;
|
||
- **нет состояния/здоровья**: нет etag/modified/last_error/status для RSS-источников.
|
||
|
||
Для пользователя это значит: можно добавить в VESTI новостные сайты/блоги и получать
|
||
их посты в конвейере (классификация → кандидаты → публикация) наравне с Telegram-каналами.
|
||
|
||
## What Changes
|
||
|
||
- Новый модуль краулера `crawler/rss_crawler.py` (feedparser + httpx):
|
||
- читает `sources.yaml` (crawler: rss), группирует по priority;
|
||
- HTTP GET c `If-None-Match`/`If-Modified-Since` из таблицы `rss_state` → 304 = пропуск;
|
||
- нормализует URL (UTM-параметры, якоря) → `canonical_url`, дедуп по sha256;
|
||
- извлекает полный текст через trafilatura, если запись — обрывок;
|
||
- пишет посты в `posts` через существующий `store_posts`-механизм (дедуп по sha256 текста);
|
||
- пишет метаданные ленты в `rss_state` (etag/modified/last_error/status, last_build_date);
|
||
- ведёт `runs` (source_id, task, trigger) — как telegram_crawler;
|
||
- CLI: `python -m crawler.rss_crawler --all | --direction | --source <slug>`.
|
||
- Новая таблица `rss_state` (etag, modified, last_error, status, last_build_date) —
|
||
аналог `tg_state` для RSS-лент.
|
||
- `requirements.txt`: + trafilatura (извлечение полного текста).
|
||
- `sources.yaml`: первый реальный RSS-источник для проверки — LWN (lwn.net) —
|
||
и один закомментированный пример (opennet.ru).
|
||
- `.env.example`: + `RSS_USER_AGENT` (информативный User-Agent).
|
||
- Cron (Hermes): `vesti-rss-crawler` (каждые 15 мин, P0) — тихий, no_agent, как telegram.
|
||
|
||
### Не меняется
|
||
|
||
- Дедуп и схема `posts` — как у telegram_crawler (sha256 текста; url — дополнительный ключ).
|
||
- Классификатор, веб, publisher — не затрагиваются (RSS-посты идут в тот же `posts`).
|
||
- `tg_state` — остаётся для Telegram; RSS использует `rss_state`.
|
||
- Никаких автопубликаций: посты попадают в кандидаты, подтверждение — человеком.
|
||
|
||
## Capabilities
|
||
|
||
### New Capabilities
|
||
- `rss-crawler`: Синхронный краулер RSS/Atom-лент: реестр из sources.yaml,
|
||
условные GET (etag/modified), нормализация URL, извлечение полного текста
|
||
(trafilatura), состояние и здоровье ленты в БД, интеграция с runs/posts.
|
||
|
||
### Modified Capabilities
|
||
- `news-store` (таблица `posts`): без изменений схемы; RSS-посты используют её как есть.
|
||
- `sources.yaml`: новые источники с `crawler: rss`.
|
||
- `vesti-web`: без изменений (RSS-посты автоматически видны как кандидаты).
|
||
|
||
## Impact
|
||
|
||
- Файлы:
|
||
- новый: `crawler/rss_crawler.py` (модуль-краулер);
|
||
- изменён: `db/schema.sql` (+CREATE TABLE rss_state), `requirements.txt`
|
||
(+ trafilatura), `sources/sources.yaml` (+lwn, пример opennet), `.env.example`
|
||
(+RSS_USER_AGENT), `config.py` (+RSS_USER_AGENT, +RSS_*);
|
||
- доки: STATUS.md, TODO.md, WALKTHROUGH.md, AGENT.MD (команда запуска).
|
||
- Данные: миграция — `CREATE TABLE IF NOT EXISTS`; существующие данные не трогаются.
|
||
- Секреты: не требует (RSS публичные). User-Agent — из .env.
|
||
- Сеть: исходящие HTTP-запросы к сайтам издателей (только к лентам, учтиво:
|
||
условные GET, рейт-лимит 1–2 с между источниками).
|
||
- Rollback: модуль не вызывается cron — просто не добавлять источники/не запускать.
|
||
|
||
## Risks
|
||
|
||
- Издатели режут по User-Agent / отдают капчу — лечится `RSS_USER_AGENT`
|
||
(честный, с контактом) и `enabled: false` для проблемных.
|
||
- Ленты с кривой датой (`published_parsed` None) — ставим `fetched_at`, не падаем.
|
||
- summary-only ленты — trafilatura может не найти полный текст; тогда сохраняем summary,
|
||
пост всё равно попадает в конвейер (пометка в content_type/text).
|
||
- Огромные ленты (мега-фиды): ограничение — первые N записей, остальные догонятся
|
||
следующими запусками (инкрементально), как в telegram_crawler.
|
||
- Троттлинг издателя: проставляем last_error и status='dead' после N=5 ошибок подряд
|
||
(правило фид-здоровья), watchdog молчит до перехода alive↔dead. |