Модульный инструмент social listening / OSINT для внутреннего аудита: собирает из TikTok описания видео и комментарии, минимизирует персональные данные и складывает в data platform (JSONL / Postgres). Заточен под поиск жалоб клиентов, схем обхода контролей и возможных утечек по упоминаниям бренда.
Сбор отделён от классификации и от хранилища. Источник данных (yt-dlp, прямой парс HTML, TikTokApi, импорт выгрузки или платный API) — это один сменный адаптер; вся обвязка (PII-минимизация, дедуп, классификация, выгрузка) общая. Когда TikTok что-то меняет — чините один коллектор, остальное не трогаете.
- Статус: что собирается, а что нет
- Важно про TikTokApi (комментарии/поиск)
- Установка
- Быстрый старт
- Конфигурация (env)
- Формат вывода
- Архитектура
- Расширение: свой источник (адаптер)
- PII и 152-ФЗ
- Тесты и диагностика
- Правовая оговорка
- Структура проекта
| Возможность | Статус | Канал |
|---|---|---|
Дискавери по аккаунту @user (вся лента) |
✅ работает с любого IP | yt-dlp |
| Дискавери по ссылке на видео / id | ✅ работает с любого IP | yt-dlp |
| Описания + метаданные (лайки, просмотры, дата, музыка) | ✅ работает с любого IP | yt-dlp / прямой парс HTML |
| Импорт выгрузки JSON/CSV | ✅ работает всегда | manual |
Дискавери по #хэштегу / ключевику |
TikTokApi (подписанный API) | |
| Комментарии | TikTokApi (браузер) | |
| Классификация (жалоба/лазейка/утечка) | 🔲 заглушка | classify.py |
Почему так. Описания и метаданные TikTok отдаёт прямо в HTML страницы видео (виден с любого IP). Комментарии и поиск — это подписанные XHR-эндпоинты, которые TikTok гейтит сильнее. См. следующий раздел.
Сбор комментариев и поиск по хэштегам/ключевикам идут через библиотеку
TikTokApi (Playwright-браузер, который
сам подписывает запросы). На практике эти эндпоинты нестабильны:
- Проверено на TikTokApi 7.3.3 (последняя на момент сборки) с валидным
ms_tokenзалогиненного аккаунта, с резидентного IP: рабочим оказался толькоtrending, аuser/hashtag/search/commentsвозвращали пустой ответ (EmptyResponseException) детерминированно — то есть это не репутация IP, а расхождение подписи библиотеки с текущими требованиями TikTok. - Это не чинится обновлением версии, прокси или токеном со стороны этого кода.
Вывод для боевого использования: для надёжного сбора комментариев/хэштегов в проде используйте платный TikTok-API (Apify TikTok Scrapers, EnsembleData, TikAPI, ScrapTik и т.п.) — они держат рабочий signer + пул прокси. Подключается это одним адаптером (см. Расширение); pipeline не меняется.
Встроенный путь TikTokApi оставлен как опциональный: он заработает, если у вас
сложится связка «доверенный IP + рабочая на тот момент версия библиотеки + валидный
ms_token». Чтобы проверить своё окружение — см. Диагностика.
Код при блокировке не падает: описания всё равно собираются, а блок комментариев
пишется в stats.errors с инструкцией; повторный блок отключает комментарии на прогон,
чтобы не долбить заблокированный IP.
git clone <your-repo-url> tiktok-audit-monitor
cd tiktok-audit-monitor
python3 -m venv .venv && source .venv/bin/activate
pip install -e . # ядро: описания, метаданные, manual-импорт
# Опционально — комментарии и keyword/hashtag-поиск (тяжёлые зависимости):
pip install -e ".[comments]"
python -m playwright install webkitТребуется Python ≥ 3.11.
После pip install -e . доступна команда tiktok-audit-monitor
(или python -m tiktok_audit_monitor.cli).
# 1) Что резолвится по запросу (без скачивания контента)
tiktok-audit-monitor discover --query "@tiktok" --limit 5
# 2) Описания из ленты аккаунта (работает с любого IP)
tiktok-audit-monitor collect --query "@some_account" --videos 20 --no-comments
# 3) Описания по конкретной ссылке, движок прямого HTML-парса (без yt-dlp)
tiktok-audit-monitor collect --query "https://www.tiktok.com/@user/video/123" \
--engine html --no-comments
# 4) Описания + комментарии по ключевику (нужны TT_PROXY / TT_MS_TOKEN, см. выше)
TT_PROXY="http://user:pass@host:port" TT_MS_TOKEN="..." \
tiktok-audit-monitor collect --query "сбербанк лимит" --videos 10 --comments 50
# 5) Прогон выгрузки через pipeline (без живого скрейпинга — воспроизводимо)
tiktok-audit-monitor manual --input export.json
# 6) Только упоминания бренда
tiktok-audit-monitor collect --query "@some_account" --videos 50 --brand-filterВыход: data/collected.jsonl (минимизированные записи сбора) и
data/incidents.jsonl (пока все unclassified). Флаг --postgres-dsn дублирует в БД.
| Переменная | Назначение | Дефолт |
|---|---|---|
TT_PROXY |
egress-прокси (для комментариев/поиска нужен резидентный/мобильный) | — |
TT_MS_TOKEN |
session-токен TikTok (для TikTokApi-путей) | — |
TT_BROWSER |
webkit / chromium |
webkit |
TT_HEADLESS |
0 повышает шанс пройти анти-бот |
1 |
TT_MIN_INTERVAL / TT_JITTER |
паузы между запросами (вежливость), сек | 2.0 / 1.0 |
TT_MAX_RETRIES / TT_BACKOFF_BASE |
ретраи и бэкофф | 4 / 2.0 |
TT_SOCKET_TIMEOUT |
таймаут сети, сек | 30 |
TT_AUDIT_SALT |
соль для хэша автора. Не задана → генерится в data/.salt (с предупреждением), чтобы хэши не были обратимы по известной константе |
авто |
TT_SALT_FILE |
путь к файлу соли (независим от TT_RAW_DIR) |
data/.salt |
TT_STORE_TEXT |
хранить замаскированный текст | 1 |
TT_RAW_STORE |
писать аудит-трейл сырых ответов (содержит ПДн!) | 0 (выкл) |
TT_RAW_DIR |
каталог сырого аудит-трейла | data/raw |
TT_COLLECTED / TT_INCIDENTS |
пути выгрузки | data/collected.jsonl / data/incidents.jsonl |
Скорость регулируется паузами: TT_MIN_INTERVAL=1 ускоряет в 2–3 раза, но
повышает риск бана. При дефолте описания идут ~10 роликов/мин; комментарии ~10–15/мин
плюс разовый старт браузерной сессии (5–15 с).
collected.jsonl — по записи на строку (CollectedItem):
{
"item_id": "a1b2c3…",
"kind": "caption", // caption | comment | reply
"video_id": "7649091368656194847",
"source_url": "https://www.tiktok.com/@user/video/7649091368656194847",
"author_hash": "9bdfc9a04c0d2cc3", // салт-хэш, не реальный ник
"text": "…замаскированный текст…", // телефоны/карты/email/контакты → [PHONE] и т.п.
"like_count": 4026,
"created_at": "2026-05-01T10:00:00Z",
"collected_at": "2026-06-11T08:00:00Z",
"collector": "ytdlp"
}incidents.jsonl — Incident с category/severity (сейчас null, т.к.
классификатор — заглушка) и item_id-ссылкой на запись сбора.
Маскируются: телефоны (в т.ч. без кода страны и 10-значные счета РФ), номера карт,
email, мессенджер-контакты (telegram/viber/whatsapp/…), @-хендлы. Автор хэшируется
с солью. Сырой текст в выгрузку не попадает (только при TT_STORE_TEXT=1, и то
замаскированный).
config.py Settings (из env) + бренд-триггеры; resolve_salt()
models.py VideoRef → RawItem (transient, c PII) → CollectedItem / Incident (persisted)
pii.py хэш автора + маскировка телефон/карта/email/контакт; excerpt по span'ам токенов
classify.py ЗАГЛУШКА (passthrough) — заменяется на правила/LLM, контракт не меняется
discovery.py query → [VideoRef]; роутинг yt-dlp (user/video) vs TikTokApi-search (tag/keyword)
pipeline.py оркестрация: discovery → collect → PII-min → (classify) → records; latch'и блокировок
sink.py JsonlSink (идемпотентный дедуп) + Postgres upsert
cli.py подкоманды discover / collect / manual
core/
http_client.py httpx + rate limit + ретраи/бэкофф + прокси + ротация UA
rate_limiter.py min-interval + jitter (детерминируемый — инъекция часов в тестах)
rawstore.py опциональный аудит-трейл сырых ответов (ПДн → ограничьте доступ)
proxy.py URL-строка прокси → Playwright ProxySettings {"server": …}
errors.py типизированные исключения (BlockedByAntiBot, DependencyMissing, …)
collectors/
ytdlp.py дискавери (user/video) + описания/метаданные [работает с любого IP]
html.py прямой парс __UNIVERSAL_DATA_FOR_REHYDRATION__ [работает с любого IP]
comments.py комментарии через TikTokApi (прокси/ms_token) [см. раздел про TikTokApi]
search.py keyword/hashtag-дискавери через TikTokApi [см. раздел про TikTokApi]
manual.py импорт JSON/CSV [работает всегда]
Каждый коллектор реализует крошечный протокол (DiscoveryCollector /
ContentCollector в collectors/base.py) — движки взаимозаменяемы.
Чтобы подключить платный TikTok-API (или любой другой источник), не трогая
pipeline, добавьте content-коллектор, возвращающий RawItem:
# collectors/myprovider.py
from ..models import RawItem, VideoRef
class MyProviderCollector:
name = "myprovider"
def __init__(self, settings, api_key: str):
self.settings = settings
self.api_key = api_key
def collect(self, ref: VideoRef, *, comment_limit: int = 50):
# 1) дёрнуть API провайдера по ref.video_id / ref.url
# 2) вернуть RawItem'ы (kind="caption"/"comment"), сырой текст и автор —
# PII-минимизация и дедуп произойдут дальше в pipeline автоматически
for c in provider_fetch_comments(self.api_key, ref.video_id, comment_limit):
yield RawItem(kind="comment", text=c["text"], url=ref.url,
video_id=ref.video_id, author=c["author"],
like_count=c.get("likes"), collector=self.name)Дальше — подменить выбор коллектора в pipeline.Pipeline._caption_collector_for /
_comments_collector_for (или прокинуть фабрику). Вся остальная цепочка (маскировка,
дедуп по item_id, выгрузка, классификация) работает как есть.
- В хранилище попадают минимизированные записи: автор → салт-хэш, контактные данные в тексте замаскированы, сырой текст не сохраняется (или только замаскированный).
- Сырой аудит-трейл (
TT_RAW_STORE=1, каталогdata/raw) содержит ПДн — включайте только при необходимости, ограничьте доступ и срок хранения по политике 152-ФЗ. TT_AUDIT_SALTобязательно задайте явно в проде (иначе генерится случайная локальная соль; известная константа-заглушка никогда не используется для боевых хэшей).- Оформляйте обработку как цель предотвращения мошенничества; держите низкий объём запросов.
Юнит-тесты (stdlib, без pytest) — офлайн-логика сбора: роутинг запросов, маскировка ПДн, дедуп, нормализация комментария, парс HTML-рехидрации, классификация исключений, прокси-формат, rate limiter, сквозной manual-прогон:
python -m tiktok_audit_monitor.tests.run_testsДиагностика окружения (diag_tiktok.py) — проверяет, какие TikTokApi-эндпоинты
открыты с вашего IP+токена (откроется окно webkit):
python diag_tiktok.py "<ваш ms_token>"Если trending OK, а comments/hashtag EMPTY — вы упёрлись в ограничение TikTokApi
(см. раздел про TikTokApi); переходите на
платный источник через адаптер.
Неофициальный сбор данных нарушает Terms of Service TikTok и затрагивает обработку
персональных данных третьих лиц. Используйте инструмент как внутренний аудиторский:
низкий объём запросов, цель — предотвращение мошенничества, минимизация и ограниченное
хранение данных. manual-источник переносит вопрос легальности сбора на тот процесс,
которым получена выгрузка. Ответственность за законность использования — на операторе.
tiktok-audit-monitor/
├── README.md
├── LICENSE
├── pyproject.toml
├── requirements.txt
├── diag_tiktok.py # диагностика TikTokApi-эндпоинтов
└── tiktok_audit_monitor/ # пакет
├── cli.py, config.py, models.py, pii.py, classify.py
├── discovery.py, pipeline.py, sink.py
├── collectors/ # ytdlp, html, comments, search, manual
├── core/ # http_client, rate_limiter, rawstore, proxy, errors
├── fixtures/ # данные для офлайн-тестов
├── sample_export.json # пример входа для `manual`
└── tests/run_tests.py