jsonscraper
Ринки

Як оцінити якість лідів у TikTok за публічними відео: покроковий пайплайн на Python

Зберіть вибірку за ключовими словами, визначте потенційні сигнали попиту й передайте дані для перевірки аналітику або класифікатору на основі ШІ

Редакційна політика Повідомити про помилку

Команда продажів отримує те саме запитання з різних каналів: які завдання потенційні клієнти вже намагаються розв’язати? Ручний пошук у TikTok дає безліч роликів, але його складно повторити за тиждень, порівняти результати й пояснити, чому конкретне відео потрапило до звіту. Для невеликого дослідження можна перетворити публічну видачу за кількома точними запитами на відтворюваний потік даних: зберегти вихідну відповідь, виділити поля відео й автора, прибрати дублікати та окремо оцінити ознаки наміру придбати або вибрати продукт.

Стаття: Як оцінити якість лідів у TikTok за публічними відео: покроковий пайплайн на Python
Короткий опис: Практичний сценарій для маркетолога й розробника: знаходьте публічні відео TikTok за запитами аудиторії через TikTok Scraper API, зберігайте вихідні відповіді, усувайте дублікати роликів і ранжуйте їх за чіткими правилами. У статті наведено скрипт Python, який обробляє два варіанти структури відповіді та безпечно передає ключ API.
Роль зображення: обкладинка — основна ідея
Розділ: 
Візуальний об’єкт: Крупний план, редакційна ілюстрація
© jsonscraper · Ілюстрація, створена ШІ

Нижче — робоча схема на Python із TikTok Scraper API від jsonscraper. Вона підійде, наприклад, сервісу для монтажу відео, який хоче зрозуміти, як автори описують труднощі із субтитрами, шаблонами та експортом. Скрипт збирає повернуті результати пошуку, а аналітик перевіряє класифікацію й вирішує, які формулювання варто використати в дослідженні аудиторії. Це спосіб організувати спостереження за публічним контентом, а не автоматично підрахувати всіх користувачів із наміром купити.

Проблема: запити аудиторії є, але дослідження складно відтворити

Під час ручного дослідження легко втратити контекст. Один співробітник шукає «як додати субтитри», інший — «автоматичні субтитри для Reels», а третій зберігає лише ролики, що сподобалися. У підсумковій таблиці змішуються різні запити, дати, метрики й критерії відбору. Коли керівник просить повторити аналіз або порівняти два тижні, доводиться відновлювати не лише результати, а й сам процес пошуку.

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

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

Схема рішення: пошук, фіксація, очищення, оцінювання

Пайплайн складається з чотирьох етапів. Спочатку команда формує невеликий словник пошукових запитів, кожен із яких відповідає конкретному завданню аудиторії. Потім скрипт надсилає запити на пошук відео й зберігає повну відповідь JSON. На третьому етапі різні структури відповіді нормалізуються в один рядок на відео, а повтори усуваються за ідентифікатором. Нарешті, правила або окремий класифікатор на основі ШІ визначають пріоритет для ручної перевірки, зберігаючи причину оцінювання.

Розділення цих етапів важливе для відтворюваності. Сирі відповіді допомагають з’ясувати причини змін у полях або помилок нормалізації. Нормалізована таблиця зручна для фільтрації та візуалізації. Окрема таблиця оцінок дає змогу змінювати правила без повторного запиту до API, якщо збережені дані придатні для такої повторної обробки й відповідають строку зберігання команди.

Для прикладу можна взяти запити «помилки автоматичних субтитрів», «як швидко додати субтитри» й «монтаж коротких відео для бізнесу». Це лише приклади словника: формулювання потрібно адаптувати до мови аудиторії та продукту. Запити слід зберігати разом із результатом, адже пошук за різними словами формує різні вибірки.

Що надає TikTok Scraper API

В опублікованій документації jsonscraper для пошуку відео зазначено GET-маршрут /searchVideo за базовою адресою https://tiktok.evelode.com. Обов’язковий параметр — keyword; серед задокументованих додаткових параметрів є count, cursor, region, date_posted, sort_by і cache_timeout. Наприклад, для sort_by передбачено задокументовані значення most-liked, relevance і date-posted, а для date_posted — такі значення, як this-week або all-time. Точний список параметрів і призначення маршруту наведено в довіднику кінцевих точок TikTok API.

Ключ передається як параметр запиту license_key. У наведеному нижче прикладі він зчитується зі змінної середовища JSONSCRAPER_TIKTOK_LICENSE_KEY, щоб не зберігати секрет у коді й не виводити його в журнал. Для автентифікації та вибору параметрів користуйтеся чинними умовами доступу; сторінка TikTok Scraper API містить опис продукту й посилання на демонстрацію та документацію.

Відповідь пошуку потрібно обробляти з огляду на її структуру, а не припускати наявність єдиного масиву. У перевіреному прикладі API повертав статус верхнього рівня й об’єкт tiktok; ролики можуть міститися в tiktok.aweme_list, а в результатах пошуку також трапляється tiktok.search_item_list[].aweme_info. Перевіряйте обидві форми. У знайдених об’єктах, якщо відповідне поле наявне, доступні ідентифікатор ролика, опис, посилання, час публікації, відомості про автора та статистика, наприклад перегляди, вподобання, коментарі й поширення. Метрики та поля слід вважати необов’язковими: код не повинен підставляти вигадані нулі, якщо значення відсутнє.

Для пагінації пошуку використовується cursor. Якщо скрипт продовжує отримувати результати, він має передати отримане значення як непрозорий токен наступного запиту, а не обчислювати його самостійно. Для початкового прототипу доцільно обмежити збір однією сторінкою на запит: це спрощує перевірку й забезпечує передбачуване навантаження. Згодом можна додати пагінацію з лімітом кількості сторінок і захистом від повторення курсора.

Підготовка середовища

У прикладі використовується Python 3.8 або новіша версія та стандартна бібліотека. Вкажіть ключ у змінній середовища, наприклад в оболонці macOS або Linux:

export JSONSCRAPER_TIKTOK_LICENSE_KEY="ваш_ключ"
python tiktok_demand.py

У Windows PowerShell змінну можна задати так:

$env:JSONSCRAPER_TIKTOK_LICENSE_KEY="ваш_ключ"
python .\tiktok_demand.py

Скрипт виконує окремий запит для кожного ключового слова. Він перевіряє HTTP-помилки, відповідь JSON і зовнішній статус, а потім витягує об’єкти з обох підтверджених варіантів масиву. Сирі відповіді записуються у файл JSONL по одному рядку: кожен запис містить запит, час спостереження та вихідну відповідь. Друга частина формує CSV з уніфікованими полями. Файл із ключем у коді відсутній, а вміст секрету не виводиться.

Приклад: збирання та нормалізація результатів пошуку

import csv
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path
from urllib.error import HTTPError, URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen

BASE_URL = "https://tiktok.evelode.com/searchVideo"
QUERIES = [
    "помилки автоматичних субтитрів",
    "як швидко додати субтитри",
    "монтаж коротких відео для бізнесу",
]


def extract_videos(payload):
    """Підтримує обидві структури відповіді пошуку, які спостерігалися."""
    tiktok = payload.get("tiktok") or {}
    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
            video = item.get("aweme_info")
            if isinstance(video, dict):
                videos.append(video)

    return videos


def fetch(query, license_key):
    params = {
        "keyword": query,
        "count": 20,
        "sort_by": "relevance",
        "date_posted": "this-month",
        "region": "US",
        "license_key": license_key,
    }
    url = BASE_URL + "?" + urlencode(params)
    request = Request(url, headers={"Accept": "application/json"})

    try:
        with urlopen(request, timeout=45) as response:
            payload = json.loads(response.read().decode("utf-8"))
    except HTTPError as exc:
        raise RuntimeError("API повернув HTTP-статус {}".format(exc.code)) from exc
    except (URLError, TimeoutError, json.JSONDecodeError) as exc:
        raise RuntimeError("Не вдалося виконати або обробити запит до API") from exc

    if payload.get("status") != "ok":
        raise RuntimeError("Статус відповіді API не дорівнював ok")
    return payload


def metric(statistics, key):
    value = statistics.get(key)
    return value if isinstance(value, (int, float)) else ""


def main():
    license_key = os.environ.get("JSONSCRAPER_TIKTOK_LICENSE_KEY")
    if not license_key:
        raise SystemExit("Задайте JSONSCRAPER_TIKTOK_LICENSE_KEY у змінній середовища")

    raw_path = Path("tiktok_raw.jsonl")
    csv_path = Path("tiktok_videos.csv")
    seen_ids = set()
    rows = []

    with raw_path.open("a", encoding="utf-8") as raw_file:
        for query in QUERIES:
            observed_at = datetime.now(timezone.utc).isoformat()
            payload = fetch(query, license_key)
            raw_file.write(json.dumps({
                "query": query,
                "observed_at": observed_at,
                "response": payload,
            }, ensure_ascii=False) + "\n")

            for video in extract_videos(payload):
                video_id = video.get("aweme_id")
                if not video_id or video_id in seen_ids:
                    continue
                seen_ids.add(video_id)

                author = video.get("author") or {}
                stats = video.get("statistics") or {}
                rows.append({
                    "query": query,
                    "observed_at": observed_at,
                    "video_id": video_id,
                    "created_at": video.get("create_time", ""),
                    "description": video.get("desc", ""),
                    "share_url": video.get("share_url", ""),
                    "author_username": author.get("unique_id", ""),
                    "author_nickname": author.get("nickname", ""),
                    "views": metric(stats, "play_count"),
                    "likes": metric(stats, "digg_count"),
                    "comments": metric(stats, "comment_count"),
                    "shares": metric(stats, "share_count"),
                })
            time.sleep(1)

    columns = [
        "query", "observed_at", "video_id", "created_at", "description",
        "share_url", "author_username", "author_nickname", "views",
        "likes", "comments", "shares",
    ]
    with csv_path.open("w", newline="", encoding="utf-8") as csv_file:
        writer = csv.DictWriter(csv_file, fieldnames=columns)
        writer.writeheader()
        writer.writerows(rows)

    print("Збережено {} унікальних отриманих відео у {}".format(len(rows), csv_path))


if __name__ == "__main__":
    main()

Значення count тут задано як запитуваний розмір вибірки для кожного запиту. Скрипт не припускає, що API зобов’язаний повернути саме стільки елементів: фактична кількість рядків залежить від відповіді. Пауза між запитами — це простий спосіб регулювати темп запуску, а не твердження про ліміт чи вимогу сервісу. Для запуску за промисловим розкладом додайте обмежені повторні спроби, моніторинг помилок і правила допустимої частоти запитів з огляду на умови вашого тарифного плану.

Як читати отриману таблицю

У CSV один рядок відповідає одному унікальному отриманому ролику, знайденому за одним із запитів. Поле query показує походження запису, observed_at — час знімка, а video_id слугує ключем дедуплікації. Опис і посилання допомагають аналітику перевірити контекст, а публічні лічильники — оцінити відгук на момент збору. Для довгострокового порівняння використовуйте окремі спостереження: не перезаписуйте історію метрик, якщо потрібно побачити їхні зміни.

Лічильники переглядів, уподобань, коментарів і поширень — це знімок публічної статистики, повернутий API на момент запиту. В окремих об’єктах вони можуть бути відсутні, тож порожнє значення в CSV означає, що у відповіді не було числового поля. Це не те саме, що нуль, і під час розрахунку агрегатів ці випадки потрібно обробляти окремо. Крім того, знайдені результати відображають вибірку видачі для конкретних слів, регіону, часового фільтра та параметрів запиту. Вони описують саме отримані ролики, а не весь контент чи аудиторію платформи.

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

Як підключити ШІ, не віддаючи йому роль судді

Коли буде зібрано вибірку, модель може допомогти позначити описи за заздалегідь визначеною схемою: проблема, згаданий інструмент, тон запитання й наявність сигналу вибору продукту. Передавайте моделі лише потрібні поля — наприклад, текст опису та ідентифікатор запису — і просіть повернути фіксований JSON із мітками та коротким обґрунтуванням. Зберігайте версію інструкції, модель і результат поруч із вихідним рядком, щоб можна було повторити розмітку або вибірково перевірити її вручну.

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

Щоб оцінити якість розмітки, візьміть випадкову підвибірку й вручну позначте ті самі категорії. Порівняйте узгодженість для кожної мітки й дослідіть помилки: наприклад, модель може сприйняти сарказм як скаргу, а освітню пораду — як особистий досвід. Часто корисніше виправити словник запитів та інструкцію, ніж одразу ускладнювати модель. Для звіту зберігайте вихідні тексти й посилання відповідно до прийнятої політики зберігання та доступу.

Автоматизація за розкладом і контроль якості

Після успішного ручного запуску скрипт можна запускати за розкладом у cron, планувальнику завдань хмарної платформи або оркестраторі на кшталт n8n. Практична послідовність кроків не змінюється: зчитати список запитів, викликати API, перевірити статус, зберегти сиру відповідь, нормалізувати ролики, записати нові знімки й сформувати звіт. Ключ слід передавати через механізм секретів середовища виконання, а не зберігати в таблиці, тексті workflow чи повідомленні про помилку.

В автоматизованому завданні корисні чотири перевірки. Перша — запит завершився успішно, а відповідь є JSON. Друга — зовнішній статус дорівнює очікуваному значенню. Третя — обробник розуміє обидва варіанти структури пошуку й коректно працює за відсутності полів. Четверта — кількість нових унікальних роликів і кількість помилок записуються в журнал. Якщо результатів раптово немає, у звіті слід показати нульову вибірку як стан запуску, а не подавати її як звичайний успішний звіт без пояснень.

Додавайте пагінацію після перевірки першої сторінки. Для маршруту пошуку в документації зазначено параметр cursor; зберігайте отриманий токен і передавайте його без змін у наступному запиті. Обмежте максимальну кількість сторінок для одного пошукового терміна й зупиняйте цикл, якщо немає нових елементів, наступного курсора або якщо курсор уже оброблявся. Так час виконання й обсяг збору залишатимуться контрольованими. Наявність курсора дає змогу продовжити отримання видачі, але не гарантує повноти результату щодо всіх публікацій.

Повторний запуск в один день може повертати ті самі ролики. Тому ключем дедуплікації має бути стабільний ідентифікатор відео, а історію знімків слід зберігати окремими записами з датою спостереження. Якщо потрібне зведене представлення, формуйте його на основі знімків: так можна відрізнити щойно знайдений ролик від того, що з’явився в кількох запитах або був отриманий повторно пізніше.

Метрики: що можна коректно порівнювати

Для операційного моніторингу корисні кількість унікальних знайдених роликів за запитом, частка роликів із заповненим описом, розподіл доступних реакцій і частота появи певних тем. Порівнюючи запити, фіксуйте однакові параметри й період запуску. Якщо в одному запуску використано this-week, а в іншому — this-month, різницю в обсягах може пояснювати часове вікно, тож без додаткового аналізу її не можна трактувати як зміну інтересу.

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

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

Типові помилки та способи їх уникнути

Вважати порожнє поле нульовим значенням

Якщо статистика чи дані автора відсутні, код вище залишає клітинку порожньою. Так зберігається різниця між невідомим значенням і виміряним нулем. Під час аналітики чітко визначте правила обробки пропусків і зазначайте кількість рядків, виключених із конкретного розрахунку.

Припускати, що пошук завжди повертає один масив

У відповідях пошуку трапляються aweme_list і вкладені елементи search_item_list[].aweme_info. Обробник перевіряє обидві форми та ігнорує елементи невідповідного типу. Якщо схема зміниться, збережені сирі відповіді допоможуть швидко виявити нове розташування даних, а тестові JSON-фікстури — перевірити виправлення до наступного запуску.

Повторно зараховувати той самий ролик як окремий сигнал

Один ролик може відповідати кільком пошуковим словам. У прикладі він потрапляє до підсумкового CSV лише один раз, а поле запиту вказує на перший збіг у поточному порядку. Якщо потрібно зберегти всі зв’язки «ролик — запит», використовуйте окрему таблицю зв’язків або список запитів для кожного ідентифікатора, а не видаляйте походження запису.

Порівнювати неспівставні вибірки

На вибірку впливають слово, регіон, часовий фільтр, сортування та дата запуску. Зберігайте параметри разом із відповіддю та змінюйте по одному чиннику, якщо дослідження порівнює варіанти. Так можна зрозуміти, чи пов’язана зміна результату з поведінкою видачі, чи зі зміною параметрів експерименту.

Видавати кореляцію за намір купити

Опис відео й публічні лічильники дають змогу побачити ознаки змісту та реакції аудиторії. Самі по собі вони не показують, хто готовий купити, чи бачила людина рекламу та якою є конверсія. Використовуйте їх для формування гіпотез, перевірки тем і підготовки контенту. Ефективність продажів оцінюйте за власними даними кампаній, узгодженими з цим дослідженням за часом і аудиторією.

Як розширити пайплайн

Коли базова версія стабільно працюватиме, можна додати файл конфігурації зі списком запитів і параметрами запуску, щоб змінювати словник без редагування Python. Наступний крок — таблиця відповідностей між запитами й тематичними кластерами, наприклад «якість розпізнавання», «швидкість монтажу» та «експорт». Ці категорії має визначити команда й перевірити на прикладах; API повертає результати пошуку, а схему інтерпретації визначає дослідник.

Замість CSV для зберігання підійде реляційна база даних: таблиця запусків, таблиця роликів і таблиця знімків метрик. Унікальний індекс за ідентифікатором ролика захищає каталог від дублікатів, а знімки дають змогу відстежувати зміни доступних лічильників. Зберігайте дату спостереження в UTC і версію нормалізатора. Якщо логіку витягування буде змінено, архівний JSONL можна обробити повторно й порівняти результати.

У n8n збір можна запускати за розкладом, а код нормалізації виконувати в окремому сервісі Python або вузлі, якщо вибране середовище підтримує потрібні операції. На першому етапі модель не обов’язкова: спершу досягніть стабільного збору, потім виміряйте, скільки часу займає ручна класифікація та які категорії повторюються. ШІ виправданий тоді, коли скорочує конкретну повторювану роботу, а його мітки можна перевіряти.

Якщо робоче запитання стосується не пошуку за формулюваннями, а регулярного спостереження за певним обліковим записом, в офіційному довіднику є окремий маршрут /getUserFeed із параметрами query, max_cursor і count. Для хештега передбачено /getHashtagFeed із параметром cursor. Це різні сценарії збору: вибирати кінцеву точку слід, виходячи з дослідницького запитання, а не підміняти один тип вибірки іншим.

Результат: відтворювана вибірка замість набору закладок

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

Практичний результат для команди — прозоріше рішення про те, які проблеми варто перевірити в інтерв’ю, на цільовій сторінці чи в рекламному повідомленні. Якщо дослідження потребує іншого типу даних, змініть запити або скористайтеся відповідним задокументованим маршрутом. Перед адаптацією пайплайна перевірте параметри в документації TikTok API; інформацію про продукт і доступ до демонстрації наведено на сторінці TikTok Scraper API.

Такий підхід розв’язує початкове завдання: перетворює пошук у TikTok на відтворюваний дослідницький процес. Скрипт збирає конкретні повернуті ролики, зберігає їхнє походження та знімки, а людина або класифікатор, результати якого можна перевірити, перетворює зміст на гіпотези про попит. Команда отримує основу для наступного рішення, зберігаючи межу між публічними ознаками контенту й підтвердженими результатами продажів.

Люди

Для цієї статті ще немає людей.

Продовжуйте читатиЯк архівувати результати пошуку TikTok за допомогою Python
Читайте наступну статтю

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

Досліджуйте API соціальних даних jsonscraper, тестуйте запити й створюйте нові процеси.

Переглянути API