Матеріали до Уроку 4: Флот скрейперів (Telegram · Discord · WhatsApp)

Навігація курсу: Категорія: Довідники

Урок: Урок-04-Соцмережі-та-медіапростір
Курс: Соцмережі та медіапростір: збір, моніторинг, базовий аналіз
Тема: AI для OSINT і розвідки — практичний кейс: власний флот скрейперів
Кейс: telegram_crawler — дашборд + колектори Telegram · Discord · WhatsApp + Waydroid

Цей документ — довідка до лекції. Він підсумовує архітектуру, уроки й
обмеження на прикладі реального проєкту, а також дає орієнтири в коді та
домашнє завдання. Числа — зі стану продакшну на момент лекції.


1. Короткий огляд

Ми будуємо флот колекторів під єдиним дашбордом. Кожен колектор збирає
дані з однієї платформи й складає їх у спільну канонічну модель. Головне в
лекції — не «як витягнути все», а як збирати стійко й не отримати бан:
кеш, бюджети, ротація акаунтів, пейсинг, проксі-вихід.

Три наскрізні ідеї:

  1. Збирай так, як платформа дозволяє — офіційні шляхи + членство акаунта,
    без автоматичного «вступу» з дашборда.
  2. Міряй причину, не здогадуйся — головний баг (FloodWait) був не там, де
    здавалося.
  3. Акаунти — витратний матеріал — ротація, кулдауни, облік здоровʼя.

2. Термінологія

ТермінЗначення
Crawlingобхід джерела/посилань, щоб знайти, що саме збирати
Scrapingвитягання конкретних полів з уже знайденої сторінки/повідомлення
Monitoringповторний збір за розкладом + відстеження змін (change tracking)
Enrichmentзбагачення зібраного (нормалізація, звʼязки, мета) після збору
Backfillодноразовий добір історії джерела «назад у часі»
Cursorзнімок «де я зупинився» (останній id / snowflake) для інкрементного збору
Канонічна модельєдиний формат запису: author · url · date · text
Rate limit / FloodWaitліміт платформи; у Telegram — тимчасовий бан за перевищення
Self-botавтоматизація користувацького акаунта (проти ToS платформ)
Pool / rotationнабір акаунтів, між якими розподіляється навантаження
Egress / proxyвихідний IP збору; часто через VPN/резидентний проксі

3. Архітектура системи

Контейнери (прод: Portainer на apollonia):

  • Dashboard (FastAPI) — керування акаунтами, лімітами, здоровʼям; вебхуки;
    синхронізація членства; панелі статистики.
  • Crawler container (main.py) — розклад збору; виконує цикли Telegram і
    Discord у тому ж контейнері.
  • OpenWA bridge — окремий контейнер (whatsapp-web.js, headless Chrome),
    що віддає події WhatsApp у дашборд через вебхук.
  • Waydroid (Android) — контейнеризований Android для реєстрації/входу
    Telegram-акаунтів і витягання сесії.
  • SOCKS5 egress — виходи IPVanish + gost-relay (sidecar-контейнери).
  • MySQL (byteBard) — sources.* (конфіг і стан) + results.* (спільні
    таблиці результатів усіх колекторів).

Схема змін БД їде через ensure_*-функції на старті контейнера; файли
migrations/*.sql — паритетні копії.


4. Канонічна модель даних

Два простори імен:

  • sources.* — наша конфігурація та стан: акаунти, цілі, курсори,
    членство, події здоровʼя, кеш entity.
  • results.* — спільні, повнотекстово-індексовані таблиці результатів, які
    читають усі споживачі платформи:
    • results.telegram_channels
    • results.discord
    • results.whatsapp_messages

Спільний «кістяк» запису: author · url · date · text (+ added — час
захоплення; + медіа за потреби). Для Discord сервер і канал відновлюються з
permalink у полі url (discord.com/channels/{guild}/{channel}/{message}).


5. Telegram-колектор

Як працює: Telethon; пул із 6 номерів (round-robin + кулдаун); збір
інкрементний за per-channel курсором; результати → results.telegram_channels.

Головний урок — FloodWait:

  • Припущення: «банять за частоту запитів».
  • Реальність: банять за обсяг ResolveUsername (перетворення
    username → entity). Сотні нових resolve → аномалія → FloodWait ~24 год.
  • Рішення:
    1. Кеш entity — sources.telegram_entity_cache зберігає
      (peer_id, access_hash), тож повторний resolve не потрібен;
    2. Денний бюджет resolve на акаунт (напр. 60/день), рахується до
      спроби (мертві цілі не зливають бюджет);
    3. перевищив бюджет → мʼяко відкласти ціль (без помилки, без бана).
  • Наслідок: 1 452 цілі обслуговуються 6 акаунтами без банів за обсягом.

Код-орієнтир: crawl/functions/resolve.py → resolve_input_peer().


6. Discord-колектор

Як працює: пул user-token (self-bot, проти ToS). Читає лише сервери, де
акаунт уже є (GET /users/@me/guilds). Нічого не «join-имо» з дашборда.

  • Карта членства (sources.discord_guild_membership): account ↔ guild,
    can_read. Кожен член-сервер автоматично стає ціллю.
  • Ротація: якщо кілька акаунтів у тому самому сервері — вибір за LRU
    (last_used), щоб жоден токен не «світився».
  • Здоровʼя акаунта: помилки класифікуються —
    403 «не член» (без штрафу) · 401 (мертвий токен → invalid) ·
    429 / CAPTCHA (кулдаун саме цього акаунта) — і пишуться в
    sources.account_events (панель ризику: зелений/жовтий/червоний).

Код-орієнтири:
auth/discord_account_pool.py → acquire() (ротація), release()
(класифікація сигналів); crawl/functions/discord_crawl.py (цикл збору).


7. WhatsApp-колектор

Як працює: міст OpenWA (whatsapp-web.js); звʼязка акаунта через QR або
pairing-code (без пароля); збір пасивний — події message.received
приходять вебхуком → results.whatsapp_messages.

  • Цілі — read-only: синхронізуються зі списку груп/каналів, де номер вже
    є
    . Нову групу додають у застосунку на телефоні.
  • Проксі: лише через relay — Chromium не вміє авторизацію SOCKS5; сесійний
    проксі незмінний після створення.
  • Backfill (одноразово на чат):
    • канал — не E2E: читаються останні пости (вкл. до підписки);
    • група/спільнота — E2E: лише те, що номер отримав після вступу;
      історію до вступу не віддає жоден клієнт.

Код-орієнтир: crawl/functions/whatsapp_backfill.py →
backfill_next_whatsapp_target().


8. Waydroid — Android у контейнері

Що це: повноцінна система Android (LineageOS) у LXC-контейнері, що
використовує ядро Linux хоста (через binder/ashmem) — це не віртуальна
машина й не емуляція CPU. Екран виводиться через Wayland.

Навіщо нам: деякі акаунти вимагають реєстрації/входу через офіційний
застосунок
. У Waydroid ставимо справжній Telegram APK, входимо за номером
(SMS/OTP як на телефоні), витягаємо .session — далі збір іде headless через
Telethon, без Android.

Обмеження, які зустріли: пристрій крешиться, доки на хості не зроблено
modprobe binder_linux; шлях через noVNC/wayvnc виявився глухим кутом.


9. Проксі-вихід і релей

  • Вихід із IP дата-центру — сам по собі сигнал для анти-абʼюзу.
  • Chromium (WhatsApp/OpenWA) не вміє авторизовувати SOCKS5 → потрібен
    gost-relay без пароля в мережі, який фронтить авторизований upstream
    (IPVanish).
  • Проксі сесії WhatsApp незмінний після створення (зміна виходу =
    перезвʼязка акаунта).
  • Без python-socks Telethon тихо пішов би напряму — «витік IP», що
    виглядає як успіх (найгірший тип збою).

10. Обмеження, які ми зустріли (зведення)

ОбмеженняСутьПомʼякшення
Флуд-ліміти (Telegram)бан за обсяг resolve, не частотукеш entity + денний бюджет
Бани / CAPTCHA (Discord)self-bot проти ToS; 401/429/CAPTCHAкулдаун, інвалідація, облік подій
Обмеження WhatsAppTOS_BLOCK, розрив сесії; межа E2Erisk-панель; backfill лише після вступу
Ротація акаунтіводин токен не має «світитися»пули + вибір LRU
Проксі-вихідDC-IP = сигнал; SOCKS-авторизаціяgost-relay; стеження за витоком IP
Акаунти = витратний матеріалнеофіційні клієнти ризикованіне зберігаємо пароль — лише токен/сесію

11. Ключові числа (прод на момент лекції)

ПлатформаАкаунтиЦіліРядків результатівІнше
Telegram61 4525 098 538entity-кеш: 4 503; бюджет 60/день
Discord45 серв.25 969115 каналів; 7 зв. членства; 919 подій
WhatsApp25328збір пасивний (вебхук)

Discord за серверами: Urbexology — 13 873 · Bellingcat — 5 614 ·
AfD Community — 3 796 · Vegan Dreamland — 2 547 · Nour Community — 139.


12. Код-орієнтири (де що лежить)

КонцептФайл
Кеш + бюджет resolve (Telegram)crawl/functions/resolve.py
Ротація / здоровʼя пулу (Discord)auth/discord_account_pool.py
Цикл збору Discordcrawl/functions/discord_crawl.py
Синхронізація членства (Discord)crawl/functions/discord_membership.py
Backfill історії (WhatsApp)crawl/functions/whatsapp_backfill.py
Міст до WhatsApp (OpenWA)auth/whatsapp_bridge_client.py
Панель ризику акаунтівauth/account_risk.py
Канонічні рядки результатівdatabase/discord_rows.py, database/result_rows.py
Доступ до БД (ensure_*, запити)database/functions.py
Дашборд / маршрутиui/app.py, ui/static/*

13. Інструменти, згадані в лекції

  • Telethon — Telegram MTProto-клієнт (Python).
  • whatsapp-web.js / OpenWA — міст до WhatsApp web-протоколу (Node).
  • Waydroid — Android у контейнері на ядрі хоста.
  • gost — легкий проксі/relay (Go).
  • FastAPI — дашборд; MySQL — сховище; Docker / Portainer — деплой.

14. Домашнє завдання

Короткий зміст — повний текст у файлі
Домашнє завдання — OSINT-скрейпер.md:

Напишіть Python-проєкт, що збирає дані з однієї соцмережі з лекції
(Telegram / Discord / WhatsApp) або схожої (Reddit, Mastodon, публічний
Telegram-канал, YouTube-коментарі, RSS). Вимоги: інкрементність, канонічна
модель author·url·date·text, повага до лімітів (backoff), стійкість + dedup,
конфіг через .env. Здати: git-репо + README, ≥ 200 записів, звіт про
зустрінуті обмеження.


15. Файли цього заняття

  • Лекція 5 — OSINT-флот (кейс проєкту).pptx — презентація (33 слайди).
  • Домашнє завдання — OSINT-скрейпер.md — домашнє завдання.
  • Заняття 5 — Супровідні матеріали.md — цей документ.