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

Ниже — практический процесс для оценки публичной ленты TikTok-креатора. Он использует TikTok Scraper API jsonscraper и Python: получает публикации через документированный маршрут, сохраняет исходный JSON, приводит подтверждённые поля к таблице и считает долю роликов, подходящих под заданную тему. При желании описания можно передать текстовому классификатору как следующий, отдельно контролируемый этап.
Сначала определите, что значит «подходит»
Предположим, команда выбирает автора для кампании о домашнем приготовлении кофе. Число подписчиков и популярность отдельных роликов могут помочь описать охват, но сами по себе не отвечают на вопрос, насколько лента связана с кофе. Для первого фильтра нужны признаки содержания: упоминает ли описание ролика приготовление кофе, оборудование, рецепты или обзоры; сколько публикаций на эту тему попало в заданное окно наблюдения; какова доля тематических роликов среди собранных.
Перед сбором данных запишите критерии в короткий словарь: например, «эспрессо», «кофемолка», «латте», «заваривание». Добавьте исключения и неоднозначные слова. «Кофе» может встретиться в шутке, рекламной интеграции или случайном контексте, поэтому автоматическое совпадение по тексту — первичная разметка, а не окончательная оценка автора. Разделяйте как минимум три статуса: явное соответствие, возможное соответствие и нерелевантный ролик.
Выборка тоже должна быть определена заранее. Можно анализировать, например, последние 20 полученных публикаций при каждом еженедельном запуске. Это условие вашего мониторинга, а не обещание API вернуть ровно такой объём: доступность и состав результатов определяются ответом конкретного запроса. Записывайте время сбора, число полученных элементов и параметры запроса, чтобы сравнивать снимки без смешения разных правил.
Запрос к ленте автора
В документации jsonscraper маршрут GET /getUserFeed принимает обязательный параметр query — ник или URL профиля. Среди необязательных параметров указаны count, region, sort_type, with_pinned_posts и max_cursor. API-ключ передаётся как license_key в query string; держите его в переменной окружения, а не в исходном коде. Подробности маршрутов и параметров приведены в официальной документации TikTok API.
В ответе сначала проверьте внешний status, затем обращайтесь к объекту tiktok. Для ленты пользователя список публикаций находится в tiktok.aweme_list. В наблюдавшейся схеме присутствуют идентификатор ролика, текст описания, время публикации, автор, URL и объект статистики. Отдельные поля могут отсутствовать, поэтому обработчик должен сохранять пустые значения как пустые, а не подменять их придуманными числами.
Следующий минимальный пример рассчитан на Python 3.8+ и библиотеку requests. Сохраните ключ в JSONSCRAPER_TIKTOK_LICENSE_KEY. Код выполняет один запрос, проверяет HTTP-ответ и внешний статус API, записывает исходный JSON и выводит нормализованные строки.
import json
import os
from datetime import datetime, timezone
from pathlib import Path
import requests
API_KEY = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
PROFILE = "creator_username"
params = {
"license_key": API_KEY,
"query": PROFILE,
"count": 20,
"region": "US",
"sort_type": 0,
"with_pinned_posts": 0,
}
response = requests.get(
"https://tiktok.evelode.com/getUserFeed",
params=params,
timeout=30,
)
response.raise_for_status()
payload = response.json()
if payload.get("status") != "ok":
raise RuntimeError("TikTok API returned a non-ok status")
tiktok = payload.get("tiktok") or {}
items = tiktok.get("aweme_list") or []
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
Path("snapshots").mkdir(exist_ok=True)
Path(f"snapshots/{PROFILE}_{stamp}.json").write_text(
json.dumps(payload, ensure_ascii=False, indent=2),
encoding="utf-8",
)
rows = []
for item in items:
stats = item.get("statistics") or {}
author = item.get("author") or {}
rows.append({
"aweme_id": item.get("aweme_id"),
"created_at": item.get("create_time"),
"description": item.get("desc") or "",
"share_url": item.get("share_url"),
"creator": author.get("unique_id") or author.get("nickname"),
"play_count": stats.get("play_count"),
"digg_count": stats.get("digg_count"),
"comment_count": stats.get("comment_count"),
"share_count": stats.get("share_count"),
})
print(json.dumps(rows, ensure_ascii=False, indent=2))
Параметр sort_type для этого маршрута описан как 0 для недавней ленты и 1 для популярной. В примере выбран режим недавних публикаций, а закреплённые ролики исключены через with_pinned_posts=0, чтобы старый закреплённый пост не попадал в выборку новых публикаций. Если нужен иной режим, сохраните параметр в метаданных снимка и применяйте его одинаково во всех запусках.
Обработка ответа: от JSON к воспроизводимой таблице
Исходный ответ полезно сохранять до преобразований. Он позволяет перепроверить нормализацию, выяснить, почему строка оказалась пустой, и адаптировать обработчик, если в ответах изменится наличие необязательных полей. В рабочем хранилище рядом с JSON сохраните время сбора в UTC, профиль-запрос, параметры и версию вашего скрипта. Не кладите ключ API в архив или лог.
Для повторных запусков используйте aweme_id как идентификатор публикации, если поле присутствует. Дедупликация по этому ID не даст считать один ролик несколькими публикациями при повторном получении. При этом сохраняйте отдельные снимки статистики: значения просмотров и реакций относятся к моменту наблюдения, а не к неизменным характеристикам ролика. Если поле статистики отсутствует, оставьте его пустым и исключите такую запись из расчёта соответствующей метрики.
Время публикации в схеме обозначено как create_time. Для аналитической таблицы преобразуйте его в дату и храните как исходное значение плюс нормализованное UTC-время. Перед расчётом проверьте несколько реальных записей из полученного ответа, чтобы убедиться в ожидаемом типе и единицах. Такая проверка особенно важна при построении временных графиков: ошибка преобразования времени сдвигает публикации между днями и портит сравнение недель.
Минимальный тематический классификатор можно построить без модели: нормализовать текст, искать заданные ключевые фразы и помечать совпадения. Для более полезной разметки подготовьте набор вручную проверенных описаний и правила для пограничных случаев. Затем сравните простой словарный фильтр с разметкой человека: выясните, какие выражения дают ложные совпадения, и обновите словарь. Это создаёт понятный базовый уровень, с которым можно оценивать последующее применение ИИ.
import re
KEYWORDS = (
"кофе", "эспрессо", "кофемолка", "латте", "заваривание",
)
def normalize(text):
text = (text or "").casefold()
return re.sub(r"\s+", " ", text).strip()
def classify(description):
text = normalize(description)
matches = [word for word in KEYWORDS if word in text]
return {
"topic_match": bool(matches),
"matched_terms": matches,
}
for row in rows:
row.update(classify(row["description"]))
Ключевое слово в описании может быть полезным сигналом, но классификатору стоит возвращать объяснимую причину: список совпавших терминов, а не только метку «да/нет». Для языковых моделей используйте структурированный запрос: передайте описание ролика и фиксированные категории, попросите вернуть категорию, краткое основание и уровень уверенности. Сохраняйте исходный текст и ответ модели отдельно. Решения, влияющие на бюджет или выбор партнёра, проверяйте человеком по ссылкам на публикации.
Считайте показатели с понятным знаменателем
Для простого отчёта подойдут доля тематических роликов и частота публикаций. Доля равна числу роликов с подтверждённым тематическим соответствием, делённому на число роликов, которые удалось классифицировать. Всегда показывайте оба числа: например, «7 из 18 проверенных описаний». Это делает результат понятным и помогает заметить, когда процент построен на слишком малой выборке.
Частоту публикаций можно выразить числом полученных роликов за фиксированный период, например за последние 30 дней. Границы периода задавайте по времени сбора и опубликованным датам. При еженедельных снимках храните результат каждого запуска, а не только обновлённую итоговую строку: тогда видны изменения тематики и активности. Не интерпретируйте число собранных элементов как полный архив публикаций автора — анализируйте фактически полученную выборку и явно обозначайте её правило.
Статистику просмотров, лайков, комментариев и репостов удобно использовать как контекст для каждого ролика. Сравнивать абсолютные значения следует осторожно: более ранняя публикация могла дольше накапливать реакции. Для сравнения в пределах одного автора фиксируйте время каждого сбора и рассматривайте динамику одного и того же ролика между снимками. Не называйте разницу между двумя снимками «скоростью роста», если интервал и доступность измерений не зафиксированы.
Полезная итоговая запись для каждого профиля включает дату сбора, выбранные параметры, число полученных публикаций, число классифицированных описаний, число тематических совпадений, список URL примеров и краткую заметку о неоднозначных случаях. Такая таблица позволяет сотруднику проверить вывод, а другому аналитику — повторить методику на следующем профиле.
Пагинация и расписание
Если выборка требует следующей страницы, документация для ленты профиля использует max_cursor, полученный из предыдущего ответа. Передавайте его без преобразования: курсор является непрозрачным значением, которое нужно сохранить и вернуть API. В ответе также проверьте has_more, если планируете запрашивать продолжение. Ограничьте число страниц или общий бюджет запросов, чтобы сбор завершался предсказуемо.
cursor = None
all_items = []
max_pages = 3
for _ in range(max_pages):
page_params = dict(params)
if cursor is not None:
page_params["max_cursor"] = cursor
page_response = requests.get(
"https://tiktok.evelode.com/getUserFeed",
params=page_params,
timeout=30,
)
page_response.raise_for_status()
page_payload = page_response.json()
if page_payload.get("status") != "ok":
raise RuntimeError("TikTok API returned a non-ok status")
page = page_payload.get("tiktok") or {}
all_items.extend(page.get("aweme_list") or [])
if not page.get("has_more"):
break
cursor = page.get("max_cursor")
if cursor is None:
break
Периодичность запуска выбирайте под задачу: для первичной оценки достаточно ручного запуска; для списка авторов — недельное расписание может выявлять изменения без постоянного опроса. Запуск можно поместить в cron, CI-задачу или оркестратор. Схема проста: получить профили из таблицы, выполнить запросы с ограничением параллелизма, записать снимки, проверить долю успешных ответов и отправить сводку в рабочую таблицу. Повторяйте запрос после временной ошибки с ограниченными попытками и задержкой, а ошибки авторизованных запросов сохраняйте отдельно для проверки ключа и конфигурации.
Где уместен ИИ, а где нужна проверка
ИИ полезен для классификации описаний, содержащих сленг, несколько языков или формулировки без точного ключевого слова. Сначала задайте закрытый список категорий и попросите модель использовать только текст описания. Затем измерьте качество на небольшой вручную размеченной выборке: сравните категории модели с решениями редактора, отдельно разберите ошибки и неоднозначные случаи. В отчёт лучше включать долю совпадений модели с ручной разметкой и число проверенных примеров, чем неинтерпретируемый общий балл.
Не передавайте модели задачу «выбери лучшего автора» без критериев. Вместо этого разделите процесс на измеримые признаки: тематическая доля, регулярность, примеры релевантных роликов и диапазон публичных реакций. Модель может кратко суммировать эти поля и указать ссылки на основания; финальное решение остаётся у команды, которая учитывает формат кампании, аудиторию и договорённости с автором.
Если анализ касается рекламных интеграций, отдельно проверяйте раскрытие отношений автора с брендом по самим публикациям и применимым требованиям. Руководство Федеральной торговой комиссии США объясняет, что связь с брендом должна быть заметно раскрыта рядом с рекомендацией; при этом профильная биография или скрытая часть текста могут быть недостаточны для заметного уведомления аудитории. См. рекомендации FTC для авторов соцсетей. Мониторинг публичных данных помогает собрать материал для проверки, но оценка соблюдения правил требует контекста конкретного поста и кампании.
Что получится на выходе
После настройки пайплайна команда получает датированные снимки публичной ленты, таблицу публикаций с описаниями и доступными метриками, а также повторяемый расчёт тематической доли. На их основе можно быстрее отбирать профили для дальнейшей проверки, замечать смену тем и документировать причины оценки. Метод остаётся проверяемым: исходный JSON, параметры запроса, классификационные правила и ссылки на ролики позволяют проследить путь от данных до вывода.
Для первого теста запустите скрипт на одном профиле, сохраните сырой ответ и вручную проверьте несколько классификаций. Затем зафиксируйте словарь тем, правила выборки и формат отчёта. Когда результат станет воспроизводимым, добавьте расписание и очередь профилей. Описание маршрутов и параметров смотрите в документации API, а обзор продукта и доступные варианты интеграции — на странице TikTok Scraper API.
Практический чек-лист перед запуском
- Запишите тему кампании, словарь включений и примеры пограничных случаев.
- Зафиксируйте окно выборки, значение
count, сортировку и настройку закреплённых публикаций. - Храните исходный JSON, дату сбора и параметры отдельно от секретного ключа.
- Используйте
aweme_idдля дедупликации, если идентификатор присутствует. - Отличайте отсутствие значения от нуля и не усредняйте метрики без понятного основания.
- Показывайте размер выборки рядом с тематической долей и прикладывайте ссылки-примеры.
- Проверяйте ИИ-классификацию на ручной выборке до использования в решениях о кампании.
- Обновляйте оценку по расписанию и сравнивайте снимки, собранные по одинаковым правилам.