jsonscraper

Как находить ранние сигналы TikTok-трендов: автоматический мониторинг поисковой выдачи

Собирайте повторяемые снимки выдачи по ключевым словам, сравнивайте метрики видео и превращайте изменения в проверяемый сигнал для контент-команды.

Редакционная политика Сообщить об ошибке

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

Article: Как находить ранние сигналы TikTok-трендов: автоматический мониторинг поисковой выдачи
Summary: Ручной поиск в TikTok плохо подходит для регулярного анализа: результаты быстро меняются, а отдельные ролики легко принять за тренд. Показываем, как построить ежедневный мониторинг поисковых запросов через TikTok Scraper API jsonscraper, сохранить исходные ответы, нормализовать данные и выделять темы для дальнейшей проверки.
Image role: cover — the central idea
Section: 
Visual subject: A phy
© jsonscraper · AI-generated illustration

Ниже — схема такого мониторинга на Python с TikTok Scraper API jsonscraper. Она подходит, например, агентству, которое отслеживает несколько тематических запросов для календаря публикаций, или бренду, которому важно увидеть, какие публичные ролики по теме получают заметные просмотры и реакции. API возвращает результаты поиска TikTok, включая описание ролика, автора, дату публикации, ссылку и доступные счётчики. Скрипт складывает каждый ответ в архив и формирует CSV-снимок для анализа.

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

Почему ручной поиск превращается в слабый мониторинг

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

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

Эти значения нужно трактовать как публичные метрики роликов, замеченных в ответе API, а не как полный охват TikTok или исчерпывающий рейтинг популярности. Результаты поиска могут меняться, отдельные поля могут отсутствовать, а показатели зависят от момента сбора. Поэтому цель пайплайна — сформировать воспроизводимую рабочую выборку и заметить кандидатов на проверку, а не объявить тему универсальным трендом по одному числу.

Схема решения: поиск, архив, сравнение

Пайплайн состоит из пяти частей: конфигурации ключевых слов, запроса к API, неизменённого архива JSON, нормализованного слоя записей и отчёта по изменениям. Такой разрез позволяет отдельно проверить работу каждого шага. Если схема ответа меняется или отдельные поля отсутствуют, исходный JSON остаётся доступен для повторной обработки.

  1. Определите набор запросов. Используйте конкретные фразы, связанные с продуктом, отраслью или задачей аудитории. Например, бренд кухонной техники может следить за «meal prep», «air fryer recipes» и названием конкретной категории продукта. Сохраняйте список запросов в конфигурационном файле, а не зашивайте в логику обработки.
  2. Задайте правила сбора. Выберите расписание и небольшой объём результатов для пилота. Запишите дату, регион и параметры поиска. Для сравнения по времени важнее повторять настройки, чем пытаться собрать максимально широкий ответ за один запуск.
  3. Храните исходный ответ. Записывайте JSON вместе с временем запуска и поисковым словом. Архив помогает восстановить исходную запись и исправить нормализацию без повторного API-вызова.
  4. Нормализуйте подтверждённые поля. Извлекайте только поля, которые присутствуют в ответе: ID, подпись, время публикации, автора, ссылку и доступные значения статистики. Отсутствующее значение оставляйте пустым, не заменяя нулём.
  5. Сравнивайте снимки. Сопоставляйте ролики по ID и храните каждое наблюдение отдельно. После этого можно получать новые для архива публикации и разницу между наблюдаемыми значениями метрик.

Для первоначального теста выберите два-три запроса и небольшое число результатов. Проверьте, насколько описания и авторы соответствуют вашей задаче, какие поля фактически возвращаются и насколько повторяется выборка при одинаковых условиях. Только после этого имеет смысл расширять список терминов и переводить запуск на расписание.

Что именно позволяет запросить TikTok Scraper API

В официальной документации jsonscraper маршрут GET /searchVideo предназначен для поиска видео по ключевому слову. Обязательный параметр — keyword. Среди документированных необязательных параметров — count, cursor, date_posted, sort_by, region и cache_timeout. Документация описывает для date_posted значения вроде this-week и this-month, а для sort_by — relevance, most-liked и date-posted. Точные имена и назначение параметров приведены в справочнике маршрутов TikTok API.

Базовый адрес сервиса — https://tiktok.evelode.com; ключ передаётся как query-параметр license_key. Для примера ниже ключ хранится в переменной окружения JSONSCRAPER_TIKTOK_LICENSE_KEY. Это позволяет не помещать секрет непосредственно в исходный код и не печатать его в журнале выполнения.

Ответ нужно разбирать с учётом вложенной структуры. Сначала проверьте внешний status, затем переходите к объекту tiktok. Для поиска возможны две формы списка: ролики могут находиться непосредственно в tiktok.aweme_list, а также в элементах tiktok.search_item_list внутри aweme_info. При этом aweme_list в ответе поиска может оказаться пустым, хотя ролики есть в search_item_list. Скрипт ниже поддерживает обе формы.

В объекте ролика документация и проверенный пример ответа показывают такие поля, как aweme_id, desc, create_time, share_url, сведения об авторе и объект statistics. Статистика может включать счётчики просмотров, лайков, комментариев и репостов. Конкретный набор и значение полей нужно проверять в каждом ответе: код оставляет отсутствующие поля пустыми. Пример маршрута и его документированные параметры доступны в описании TikTok Scraper API.

Рабочий пример на Python

Пример рассчитан на Python 3.8 и новее и использует пакет requests. Установите его командой python -m pip install requests. Сохраните код в файл collect_tiktok.py, задайте ключ в окружении и запускайте скрипт с поисковым словом. Скрипт создаёт каталог data, записывает исходный JSON и добавляет нормализованные наблюдения в CSV.

import csv
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from urllib.parse import urlparse

import requests

BASE_URL = "https://tiktok.evelode.com"
ARCHIVE = Path("data/raw")
OUT_CSV = Path("data/observations.csv")


def get_videos(tiktok):
    """Собрать ролики из подтверждённых вариантов ответа searchVideo."""
    videos = []

    aweme_list = tiktok.get("aweme_list") or []
    if isinstance(aweme_list, list):
        videos.extend(item for item in aweme_list if isinstance(item, dict))

    search_items = tiktok.get("search_item_list") or []
    if isinstance(search_items, list):
        for item in search_items:
            if not isinstance(item, dict):
                continue
            aweme_info = item.get("aweme_info")
            if isinstance(aweme_info, dict):
                videos.append(aweme_info)

    # Убираем дубликаты, сохраняя порядок и записи без ID.
    result = []
    seen = set()
    for video in videos:
        video_id = video.get("aweme_id")
        if video_id and video_id in seen:
            continue
        if video_id:
            seen.add(video_id)
        result.append(video)
    return result


def fetch(keyword, count=20, region="US"):
    license_key = os.environ.get("JSONSCRAPER_TIKTOK_LICENSE_KEY")
    if not license_key:
        raise RuntimeError("Set JSONSCRAPER_TIKTOK_LICENSE_KEY in the environment")

    params = {
        "license_key": license_key,
        "keyword": keyword,
        "count": count,
        "region": region,
        "sort_by": "relevance",
    }
    response = requests.get(
        f"{BASE_URL}/searchVideo", params=params, timeout=60
    )
    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")
    if not isinstance(tiktok, dict):
        raise RuntimeError("Response does not contain a TikTok result object")
    return payload, tiktok


def write_rows(keyword, videos, collected_at):
    OUT_CSV.parent.mkdir(parents=True, exist_ok=True)
    fields = [
        "collected_at", "keyword", "aweme_id", "create_time",
        "author_id", "author_name", "author_username", "description",
        "share_url", "play_count", "digg_count", "comment_count",
        "share_count", "collect_count",
    ]
    write_header = not OUT_CSV.exists()

    with OUT_CSV.open("a", newline="", encoding="utf-8") as file:
        writer = csv.DictWriter(file, fieldnames=fields)
        if write_header:
            writer.writeheader()

        for video in videos:
            author = video.get("author") or {}
            stats = video.get("statistics") or {}
            writer.writerow({
                "collected_at": collected_at,
                "keyword": keyword,
                "aweme_id": video.get("aweme_id"),
                "create_time": video.get("create_time"),
                "author_id": author.get("uid"),
                "author_name": author.get("nickname"),
                "author_username": author.get("unique_id"),
                "description": video.get("desc"),
                "share_url": video.get("share_url"),
                "play_count": stats.get("play_count"),
                "digg_count": stats.get("digg_count"),
                "comment_count": stats.get("comment_count"),
                "share_count": stats.get("share_count"),
                "collect_count": stats.get("collect_count"),
            })


def main():
    if len(sys.argv) 

Передайте ключ через окружение. В shell Bash команда для текущего сеанса выглядит так:

export JSONSCRAPER_TIKTOK_LICENSE_KEY="ваш_ключ"
python collect_tiktok.py "meal prep"

В Windows PowerShell переменную можно задать для текущего процесса командой $env:JSONSCRAPER_TIKTOK_LICENSE_KEY="ваш_ключ", а затем запустить тот же Python-файл. Не добавляйте ключ в репозиторий, CSV, архив ответа или сообщения об ошибках. Поскольку API принимает ключ в query-параметре, учитывайте, что полный URL запроса может попадать в журналы HTTP-клиента и инфраструктуры; настройте логирование так, чтобы секреты исключались.

Как читать код и проверять результат

Функция fetch передаёт документированные параметры и проверяет код HTTP, внешний статус и наличие объекта tiktok. Она не считает любое корректное тело ответа удачным результатом: если формат неожиданен, выполнение останавливается с понятной ошибкой. Так легче отличить пустую выдачу от проблемы доступа или изменившейся структуры.

Функция get_videos объединяет элементы прямого списка aweme_list и записи, вложенные в search_item_list[].aweme_info. Затем она убирает повторы по aweme_id, поскольку ролик может появиться в обеих коллекциях. Если ID отсутствует, запись сохраняется; это позволяет исследовать исходный результат, не подставляя придуманное значение.

Нормализация использует безопасное получение вложенных объектов. Поля автора или статистики могут отсутствовать, поэтому перед чтением код подставляет пустой объект. При этом CSV оставляет соответствующие ячейки пустыми. Это важное различие: пустая ячейка означает, что значение не пришло в наблюдении, а ноль — числовое значение, которое API действительно возвратил.

Архив получает отдельный JSON-файл на каждый запрос. Имя содержит время UTC и очищенную версию поискового слова. CSV хранит плоские записи для аналитики, а исходный JSON остаётся эталонным материалом для разбора новых полей или повторной обработки. Такой двойной формат удобен и для локального прототипа, и для последующей миграции в базу данных или объектное хранилище.

Для проверки первого запуска откройте JSON и убедитесь, что status равен ok, внутри есть объект tiktok, а одна или обе поддерживаемые коллекции содержат элементы. Затем сопоставьте несколько значений CSV с исходным объектом. В частности, проверьте, что счётчики не превращаются в строки с ошибками, даты публикации сохраняются как исходное значение, а ссылки принадлежат тем же роликам, что и ID.

Если корректный ответ не содержит роликов, сохраните этот факт как пустой результат запуска, а не как сбой кода. Если внешний статус или HTTP-ответ указывает на ошибку, не добавляйте такую запись в аналитические наблюдения: сначала устраните причину и повторите запуск. Для производственного процесса стоит также записывать HTTP-код, поисковое слово, время и краткое сообщение об ошибке, исключая ключ и полный URL с секретом.

Пагинация и повторяемость сбора

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

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

Параметр date_posted позволяет ограничить поиск одним из перечисленных в документации периодов; sort_by позволяет выбрать сортировку по релевантности, дате публикации или лайкам. При анализе динамики фиксируйте эти настройки рядом с запуском. Сравнение запросов с разными периодами или сортировками может отражать изменение условий поиска, а не изменение самой темы.

Параметр cache_timeout управляет кэшированием ответа. Документация описывает стандартное окно кэша в 3600 секунд и значение 0 для отключения кэширования. Для планового мониторинга выберите настройки осознанно и сохраните их в конфигурации. Если серия запросов запускается чаще часа и требуется различать ответы в пределах этого окна, отдельно проверьте поведение кэширования, прежде чем трактовать повторяющиеся результаты как отсутствие изменений.

Сравнение ежедневных наблюдений

CSV уже содержит основу для простого отчёта. Группируйте строки по поисковому слову и aweme_id, сортируйте по collected_at и сравнивайте только пары наблюдений, где оба значения метрики существуют. Например, разницу просмотров можно считать как последнее наблюдаемое значение минус предыдущее. Сохраняйте обе исходные точки: абсолютная разница и время между наблюдениями нужны для корректного понимания результата.

Не называйте эту разницу скоростью просмотров без оговорённого временного интервала. Если один запуск произошёл утром, а следующий через несколько дней, значение представляет накопленное изменение за этот промежуток. Для сопоставимого темпа можно делить разницу на фактическую длительность между наблюдениями, но результат остаётся средним темпом между двумя снимками, а не непрерывной телеметрией.

Отдельно считайте два вида сигналов. Первый — новые ID, появившиеся в выдаче при текущем запросе. Второй — изменение статистики уже наблюдавшихся видео. Новый ролик может быть кандидатом для проверки независимо от его текущего числа просмотров, а рост у старого видео помогает заметить, что публикация продолжает набирать реакции. Эти сигналы отвечают на разные вопросы и полезны в разных сценариях редакционного планирования.

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

Для первого отчёта достаточно таблицы с колонками: термин, ID, дата публикации, автор, описание, ссылка, текущие просмотры, просмотры в прошлом снимке, разница и время между снимками. Добавьте флаг «новое для архива» и поле для редакционной оценки. Сотрудник может отмечать соответствие бренду, пригодность формата и потенциальный риск копирования чужой идеи — API сам по себе этих оценок не делает.

Как не перепутать популярность ролика и полезность темы

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

При сравнении нескольких видео можно вычислить отношение взаимодействий к просмотрам, если оба счётчика присутствуют. Например, сумма лайков, комментариев и репостов, делённая на просмотры, даёт простой показатель наблюдаемой доли реакций. Зафиксируйте формулу и не смешивайте ролики с пропущенными значениями: иначе результат будет несопоставим. Этот коэффициент описывает только выбранные публичные счётчики и выбранные видео.

Не складывайте метрики нескольких снимков как будто это независимые события. Если один и тот же ролик попал в пять ежедневных ответов, его просмотры в этих строках — последовательные состояния одного счётчика, а не пять разных аудиторий. Для суммы по уникальным публикациям используйте одну согласованную точку наблюдения на ролик, например последний снимок за отчётный период, и сохраните правило выбора.

Ещё один полезный срез — повторяющиеся слова в описаниях. Простой текстовый анализ может группировать публикации по заранее заданным словарям: «рецепт», «обзор», «до/после», «ошибка», «совет». Классификатор или языковая модель могут предлагать категории и краткие резюме, однако в таблице стоит хранить оригинальное описание и URL, чтобы редактор мог перепроверить интерпретацию по самому ролику.

Автоматизация по расписанию

После проверки ручного запуска перенесите сбор в планировщик: cron на собственном сервере, GitHub Actions или рабочий процесс n8n/Make. Интеграция должна запускать тот же проверенный скрипт, передавать ключ из хранилища секретов, архивировать JSON и отправлять уведомление только при успешном завершении. Конкретная реализация планировщика зависит от инфраструктуры; API-вызов и формат обработки остаются прежними.

Пример расписания cron для ежедневного запуска в 08:15 по времени машины:

15 8 * * * cd /srv/tiktok-monitor && /usr/bin/python3 collect_tiktok.py "meal prep" >> logs/collector.log 2>&1

Перед использованием такой строки настройте переменную окружения в службе или оболочке, под которой работает cron, и задайте корректный часовой пояс хоста. Для нескольких ключевых слов лучше хранить список в файле, а скрипту передавать каждый запрос отдельным запуском. Так ошибка одного запроса не обязана отменять весь набор, а архивы легче сопоставлять.

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

Если результаты должны попадать в Google Sheets, базу данных или внутреннюю панель, добавьте это после надёжного архивирования. Сначала запишите исходный ответ, затем делайте загрузку нормализованных строк; если выгрузка не удалась, повторите загрузку из архива, не обязательно повторяя сбор данных. Идентификатор ролика и время сбора помогают организовать повторяемую вставку и отличить новый снимок от старого.

Добавление ИИ: полезная роль — сортировка, а не подмена источника

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

Храните результат модели в отдельных колонках, например ai_topic, summary и review_status. Не перезаписывайте исходное описание и значения API. При изменении инструкции или модели повторная обработка должна быть возможна на сохранённых записях; для этого полезно хранить версию промпта и дату классификации.

Практичная задача для модели — предложить редактору кластеры: «короткие рецепты», «сравнение устройств», «ошибки новичков». Затем аналитик проверяет несколько примеров в каждом кластере по ссылкам и корректирует словарь. Такой human-in-the-loop процесс превращает ИИ в средство навигации по корпусу, оставляя проверяемые исходные наблюдения доступными.

Не поручайте модели самостоятельно объявлять причинность между форматом и охватом по небольшой поисковой выборке. Для такого вывода нужны заранее определённая методика, сравнимые публикации и дополнительные данные. В практической редакционной работе достаточно ранжирования кандидатов для просмотра, гипотез о повторяющихся сюжетах и списка ссылок для ручного разбора.

Качество выборки и границы вывода

Пайплайн сохраняет ответы, полученные по заданным запросам и параметрам. Он помогает сравнивать эти наблюдения, но охват поиска ограничен конкретным запросом, моментом сбора, настройками и ответом сервиса. Поэтому формулируйте выводы точно: «среди полученных результатов по запросу X в снимках этой недели чаще встречалась тема Y», а не «TikTok сейчас целиком обсуждает Y».

Сравнивайте только одинаково настроенные серии: один регион, одинаковые параметры сортировки, период публикации и число запрошенных результатов. Если вы меняете запрос или фильтр, отметьте это как новую серию. Для анализа сезонности или кампании полезно хранить версию конфигурации, иначе изменение входа будет выглядеть как изменение контента.

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

Если проект связан с конкурентами или авторами, ограничьте сбор задачей и минимально необходимыми данными. Не собирайте чувствительную информацию и не используйте публичные показатели как оценку личности автора. Для отчёта маркетинговой команде обычно достаточно ссылки, описания, имени профиля, времени публикации и агрегированных метрик. Перед автоматизацией проверьте применимые условия платформы, требования вашей организации и правила хранения данных.

Практический чек-лист перед запуском

  • Сформулируйте бизнес-вопрос: какие темы, форматы или публикации вы хотите замечать.
  • Начните с нескольких устойчивых поисковых фраз и зафиксируйте их написание.
  • Проверьте маршрут /searchVideo, обязательный keyword и остальные параметры по документации.
  • Храните ключ в переменной окружения и исключите его из вывода, логов и репозитория.
  • Проверяйте внешний статус ответа и наличие объекта tiktok.
  • Обрабатывайте как aweme_list, так и search_item_list[].aweme_info.
  • Сохраняйте сырой JSON до нормализации.
  • Оставляйте отсутствующие поля пустыми и не подменяйте их нулями.
  • Сопоставляйте публикации по aweme_id, а курсор передавайте без преобразования.
  • Фиксируйте дату сбора и параметры поиска для каждого снимка.
  • Проверяйте несколько роликов вручную перед выводами и передачей результатов модели.

Что получится на выходе

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

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

Начать можно с одного запроса, ежедневного локального запуска и CSV-файла. Когда проверка покажет, что выборка соответствует задаче, добавьте расписание, базу данных или классификацию описаний. Документированные параметры и назначение маршрутов можно сверять в документации TikTok API, а сведения о доступе и продукте — на странице TikTok Scraper API jsonscraper.

Персоны

Для этой статьи персоны пока не указаны.

Читайте дальшеМониторинг TikTok-хэштегов на Python: рабочий запрос к API
Читать следующую статью

Превратите прочитанное в рабочую интеграцию

Изучайте API социальных данных jsonscraper, тестируйте запросы и создавайте новые процессы.

Смотреть API