Когда команда ищет тему для следующей кампании, ручной просмотр десятков профилей быстро превращается в набор заметок без единой методики. Один аналитик записывает просмотры, другой — подписи к видео, а публикации с похожими формулировками оказываются в разных таблицах. Через неделю трудно понять, что повторяется чаще: тема, формат подачи или просто удачный ролик.

Практичный подход — вести небольшой список публичных аккаунтов, регулярно получать сведения об их видео в структурированном виде и сохранять каждый сбор как отдельный снимок. Затем можно сравнивать публикации и доступные метрики во времени, а языковую модель использовать для предварительной группировки подписей. Ниже — схема такого исследовательского пайплайна на Python с TikTok Scraper API от jsonscraper.
Сформулируйте вопрос до сбора данных
Представим маркетинговую команду небольшого бренда спортивного питания. Ей нужно выяснить, какие темы регулярно появляются у выбранных публичных TikTok-креаторов и какие видео стоит посмотреть вручную. Задача — сравнить публикации заранее выбранных аккаунтов за период наблюдения, а не построить универсальный рейтинг популярности TikTok.
Это задаёт границы анализа. Сбор ленты выбранных профилей помогает изучать содержание и частоту публикаций этих аккаунтов. Доступные публичные счётчики можно фиксировать на момент запроса. Для оценки результата собственной рекламы понадобятся отдельные данные — например, расходы и конверсии из рекламной системы или веб-аналитики.
До подключения API запишите протокол исследования: список аккаунтов, дату начала, периодичность сбора, поля анализа и критерии включения публикаций. Фиксируйте время каждого запроса. Тогда можно отличить изменение метрики у одного видео от различия между двумя наборами наблюдений.
Что собирать и что считать
Для небольшого проекта нужны три слоя данных. Первый — идентификатор аккаунта и время запуска сбора. Второй — исходный ответ API, сохранённый для последующей проверки. Третий — нормализованные поля для запросов и отчётов: ID видео, подпись, время публикации и доступные счётчики взаимодействий.
Имена полей и вложенность ответа нужно установить по образцу конкретного маршрута. Не закладывайте заранее предположение, что список всегда называется videos или счётчик просмотров — views. Сначала выполните документированный запрос и изучите его фактический JSON, затем настройте преобразование в собственную схему.
Полезные показатели — число новых публикаций за интервал, распределение публикаций по темам и изменение публичных счётчиков между снимками одного видео. Для последнего сравнивайте записи с совпадающим ID видео. Так динамика уже опубликованного ролика остаётся отделена от показателей новых публикаций.
Подключение TikTok Scraper API
В описании TikTok Scraper API указан базовый адрес https://tiktok.evelode.com, а справочник маршрутов подтверждает GET /getUserFeed и параметры query, max_cursor, count, region, with_pinned_posts, sort_type и cache_timeout. Для первого запроса достаточно указать профиль в query и, например, число элементов через count. Ключ license_key передаётся в query string; его настройку также описывает справочник API. В коллекции Postman можно сверить endpoint и проверить ответ перед интеграцией.
Храните ключ в переменной окружения. Не добавляйте его в исходный код, репозиторий, таблицу или клиентское приложение. Выполните запрос, сохраните успешный пример JSON с датой и названием маршрута и используйте его как основу для адаптера нормализации и тестов.
Рабочий минимальный запрос на Python
Справочник указывает, что ответ пользовательской ленты содержит внешний статус и объект tiktok, где список публикаций расположен в aweme_list. В записях могут присутствовать ID, подпись, время публикации, автор и статистика. Конкретные поля и значения следует проверять по полученному ответу: отдельные данные могут отсутствовать.
import json
import os
from datetime import datetime, timezone
from pathlib import Path
import requests
API_KEY = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
ENDPOINT_URL = "https://tiktok.evelode.com/getUserFeed"
def fetch_user_feed(handle: str, count: int = 20) -> dict:
response = requests.get(
ENDPOINT_URL,
params={
"license_key": API_KEY,
"query": handle,
"count": count,
"region": "US",
},
timeout=45,
)
response.raise_for_status()
payload = response.json()
if not isinstance(payload, dict):
raise ValueError("Ожидался объект JSON")
if payload.get("status") != "ok":
raise RuntimeError(f"API вернул статус: {payload.get('status')!r}")
tiktok = payload.get("tiktok")
if not isinstance(tiktok, dict):
raise ValueError("В ответе отсутствует объект tiktok")
return payload
def save_raw(payload: dict, account: str, output_dir: str = "data/raw") -> Path:
collected_at = datetime.now(timezone.utc).isoformat()
safe_account = "".join(c for c in account if c.isalnum() or c in "-_@")
path = Path(output_dir) / f"{safe_account}_{collected_at.replace(':', '-')}.json"
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(
json.dumps(
{"collected_at": collected_at, "account": account, "payload": payload},
ensure_ascii=False,
indent=2,
),
encoding="utf-8",
)
return path
def normalize_items(payload: dict, account: str, collected_at: str) -> list:
items = payload["tiktok"].get("aweme_list", [])
if not isinstance(items, list):
raise ValueError("Поле tiktok.aweme_list не является списком")
observations = []
for item in items:
if not isinstance(item, dict):
continue
stats = item.get("statistics")
stats = stats if isinstance(stats, dict) else {}
author = item.get("author")
author = author if isinstance(author, dict) else {}
observations.append({
"account_handle": account,
"collected_at": collected_at,
"video_id": item.get("aweme_id"),
"caption": item.get("desc"),
"published_at_epoch": item.get("create_time"),
"author_handle": author.get("unique_id"),
"views": stats.get("play_count"),
"likes": stats.get("digg_count"),
"comments": stats.get("comment_count"),
"shares": stats.get("share_count"),
})
return observations
if __name__ == "__main__":
account = "creator_handle"
payload = fetch_user_feed(account, count=20)
collected_at = datetime.now(timezone.utc).isoformat()
raw_path = save_raw(payload, account)
observations = normalize_items(payload, account, collected_at)
print(f"Сохранено: {raw_path}; записей: {len(observations)}")
Перед запуском задайте JSONSCRAPER_TIKTOK_LICENSE_KEY в окружении и установите библиотеку requests. Код проверяет HTTP-ответ, внешний статус и наличие объекта tiktok, после чего читает aweme_list. Он сохраняет сырой JSON и извлекает подтверждённые справочником поля, оставляя отсутствующие значения пустыми. Полученная лента — это возвращённый API набор результатов, поэтому отчёт следует связывать с временем запроса и выбранным профилем.
Храните снимки и сравнивайте публикации
Для малого проекта подойдут SQLite или PostgreSQL. Сырой ответ храните отдельно от нормализованных записей. Для таблицы наблюдений можно использовать такую схему:
CREATE TABLE IF NOT EXISTS video_observations (
account_handle TEXT NOT NULL,
video_id TEXT NOT NULL,
collected_at TEXT NOT NULL,
published_at_epoch INTEGER,
caption TEXT,
views INTEGER,
likes INTEGER,
comments INTEGER,
shares INTEGER,
raw_file TEXT,
PRIMARY KEY (account_handle, video_id, collected_at)
);
Каждый запуск добавляет новый снимок, а не перезаписывает прошлый. При сравнении счётчиков вычисляйте разницу только там, где есть оба значения для одного видео. Интервал между запросами и время наблюдения включайте в отчёт: они объясняют, за какой период накопилось изменение.
Для тематической группировки начните с небольшого словаря категорий, затем при необходимости добавьте классификатор или языковую модель. Передавайте модели очищенные подписи, ID публикаций и заранее заданные категории. Структурированный результат с категорией и коротким обоснованием легче сравнивать между запусками, чем свободный обзор.
Добавьте языковую модель с проверяемой разметкой
Модель может предварительно распределять подписи по темам вроде «рецепты», «тренировки», «обзоры продуктов» и «личные истории». Для начала вручную разметьте несколько десятков публикаций. Сравните автоматические метки с этими примерами, уточните определения категорий и повторите оценку после изменения промпта или модели.
Число новых публикаций, медиану счётчиков и разницу между снимками надёжнее рассчитывать обычным кодом. Модель используйте для классификации текста и подготовки кратких пояснений. Исходные подписи и числовые наблюдения оставляйте доступными для проверки.
Сохраняйте вместе с меткой ID публикации, версию промпта, дату обработки и использованную модель. При ошибочной классификации аналитик сможет найти подпись и поправить правило. Первоначальную метку и ручную корректировку полезно хранить отдельно.
Автоматизируйте запуск
После проверки ручного прогона перенесите скрипт в cron, GitHub Actions, n8n или Make. Планировщик запускает сбор по расписанию, передаёт список аккаунтов, регистрирует результат и направляет отчёт в выбранное хранилище. Ключ храните в секретах среды исполнения. Сначала проверьте процесс на одном аккаунте, затем расширяйте список.
Разделите автоматизацию на этапы: очередь аккаунтов, вызов API, сохранение сырого ответа, нормализация, запись снимка и подготовка отчёта. Ошибка одного аккаунта не должна стирать результаты остальных. Повторный запуск можно сделать идемпотентным с помощью ID запуска и ограничений уникальности в базе.
Журналируйте время, аккаунт, маршрут, HTTP-статус, длительность, число обработанных элементов и описание ошибки. Не записывайте API-ключ в журнал. Параметр cache_timeout указан для /getUserFeed; его можно добавить в запрос, если нужен заданный срок кэширования. В API-справочнике значение по умолчанию описано как 3600 секунд.
Проверьте качество перед публикацией отчёта
Сверьте несколько нормализованных записей с исходным JSON. Проверьте, что повторный сбор распознаёт то же видео по ID, даты разбираются ожидаемым образом, числовые поля имеют подходящий тип, а доля пропусков известна. Затем выполните повторный запуск и убедитесь, что база сохранила старые наблюдения и добавила новые.
Не смешивайте аккаунты и периоды сбора. Для сравнения тем используйте одинаковую длину периода или явно показывайте её в отчёте. Для динамики счётчиков фиксируйте промежуток между снимками, чтобы читатель понимал масштаб сравниваемых интервалов.
Сохраняйте исходный текст подписи и создавайте очищенную версию отдельно. Эмодзи, хэштеги, ссылки и языковые особенности могут влиять на классификацию; отдельные поля помогут проверить влияние очистки и пересчитать категории без нового обращения к API.
Какой результат даст пайплайн
После нескольких циклов команда получит таблицу публикаций и снимков, предварительную группировку подписей по темам и отчёт о новых видео за выбранный период. Это помогает отобрать ролики для экспертного просмотра, увидеть повторяющиеся темы у выбранных аккаунтов и проверить изменение публичных счётчиков между датами наблюдений.
На основе этих данных можно сформулировать гипотезы для редакционного календаря: сравнить способы подачи одного вопроса или выделить темы для тестирования в собственном контенте. Для оценки коммерческого эффекта сопоставьте наблюдения с внутренними данными кампаний.
Чтобы начать, выберите небольшой список публичных аккаунтов и проверьте GET /getUserFeed в коллекции запросов Postman. Переносите в код только параметры и пути к полям, подтверждённые документацией маршрута и его реальным ответом.
Ответственный сбор публичных данных
Ограничьте список аккаунтов целью исследования, собирайте необходимые поля и задайте срок хранения сырого ответа. Перед коммерческим использованием данных проверьте применимые условия платформы и требования к персональным данным в вашей юрисдикции. Контроль доступа и удаление устаревших снимков помогают удерживать процесс в рамках задачи.
Перед отправкой данных в ИИ-сервис удаляйте поля, которые модели не нужны. В отчёте указывайте ID публикации и дату наблюдения, чтобы сотрудник мог перейти к записи и проверить основание вывода.
Краткий чек-лист запуска
- Определите нишу, список аккаунтов, период и вопросы анализа.
- Проверьте параметры
GET /getUserFeedв справочнике и фактический ответ в Postman. - Сохраните пример JSON и настройте нормализатор на подтверждённые поля.
- Записывайте сырой ответ и отдельные снимки с временем сбора.
- Считайте числовые показатели кодом; используйте ИИ для предварительной группировки текста.
- Добавьте расписание, журналирование, обработку повторов и срок хранения.
Так мониторинг становится воспроизводимым исследованием: каждый вывод связан с публикацией и временем наблюдения, а код опирается на фактическую схему выбранного маршрута.