jsonscraper

製品ローンチへの反応をTikTokで週次レポートにまとめる方法

キーワード検索で公開動画と指標を収集し、製品チームが繰り返し活用できるシグナルに変えます。

編集方針 誤りを報告する

アプリや新機能をリリースすると、フィードバックは短い動画の中にあっという間に散らばります。マーケターが手作業でいくつかの動画を見つけてチャットにリンクを送り、後からアナリストが、どの投稿を集計済みなのか、再生回数がどう変化したのかを把握できなくなることもあります。実用的な解決策は、一定の検索語で検索結果を定期的に収集し、元のレスポンスを保存したうえで、確認できたフィールドに基づいてレポートを作成することです。

記事:製品ローンチへの反応をTikTokで週次レポートにまとめる方法
概要:製品ローンチに関する公開TikTok動画を収集する実践ガイド。TikTok Scraper APIへのリクエスト、2種類のレスポンスの処理、重複排除を行い、実在しない指標を作らずに週次レポートを作成します。
画像の役割:カバー — 中心となるアイデア
セクション:
ビジュアルの内容:印刷されたダッシュボード風の週次レポートと、一般的な短尺動画フィードを表示したスマートフォン。動画の説明を示す注釈付きカード
© jsonscraper · AI生成イラスト

このガイドでは、具体的なケースを想定して収集を設定します。新機能をリリースしたチームが、製品名、主要機能、または典型的なユーザーの課題を説明文に含む公開TikTok動画を毎週追跡するケースです。これは検索で見つかったサンプルのモニタリングです。APIが返すのはクエリとパラメーターに基づく検索結果であり、ローンチに関するすべての投稿が網羅される保証はありません。

まず、チームが必要とするシグナルを決める

再生回数が多いことだけでは、次に何をすべきかを判断するのは困難です。チームにとって有用なのは、繰り返し出てくる質問、人々が実演している使い方、目立った公開反応を得ている動画を把握することです。そこで、最初にいくつかの検索語を決め、レポートに含めるフィールドを選びます。

たとえば、投稿計画ツールのローンチなら、「製品名」「コンテンツプランナー」「TikTokの予約投稿方法」といった検索語を試せます。同じテーマを人々がさまざまな表現で説明する可能性を反映したフレーズを選びましょう。後から同じ条件で収集結果を比較できるよう、モニタリングの開始日と地域とともに記録してください。

最小限のテーブルには、収集時刻、検索語、動画ID、リンク、説明文、投稿者名、投稿者ID、取得可能な再生回数・いいね数・コメント数を含められます。TikTok Scraper APIの検索結果では、aweme_id、desc、share_url、投稿者情報、統計情報の一部などがフィールドとして記載されています。個々のオブジェクトで実際にフィールドを確認してください。指標によっては欠けていることがあります。

ドキュメントに記載された検索機能に接続する

動画を検索するには、ベースURL https://tiktok.evelode.com のGETルート /searchVideo を使います。ドキュメントには、必須パラメーターのkeywordと、任意のcount、cursor、date_posted、sort_by、region、cache_timeoutが記載されています。日付フィルターの有効な値にはthis-week、並べ替えの値にはrelevance、most-liked、date-postedがあります。用途とパラメーター名は、TikTok APIのルート一覧で確認してください。

ライセンスキーはクエリパラメーターlicense_keyとして渡します。実行するスクリプトでは環境変数JSONSCRAPER_TIKTOK_LICENSE_KEYから読み込み、ソースコードに秘密情報を書き込んだり、ログに出力したりしないでください。この例はPython 3.8以降を対象としており、requestsパッケージを使います。

import os
import requests

BASE_URL = "https://tiktok.evelode.com"
API_KEY = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]


def search_videos(keyword, cursor=None):
    params = {
        "license_key": API_KEY,
        "keyword": keyword,
        "count": 20,
        "date_posted": "this-week",
        "sort_by": "date-posted",
        "region": "US",
    }
    if cursor is not None:
        params["cursor"] = cursor

    response = requests.get(
        f"{BASE_URL}/searchVideo",
        params=params,
        timeout=30,
    )
    response.raise_for_status()
    payload = response.json()

    if payload.get("status") != "ok":
        raise RuntimeError("TikTok APIがok以外のステータスを返しました")

    return payload["tiktok"]


result = search_videos("content planning app")
print("見つかったオブジェクト数:", len(result.get("aweme_list", [])))

このスクリプトはHTTPエラーとレスポンスの外側のステータスを確認します。HTTPリクエストが成功しても、検索結果に動画があるとは限りません。該当する投稿がない場合、リストが空になることがあります。初回の実行では、実際のオブジェクトと正規化したフィールド一覧を照合できるよう、レスポンス全体を安全なストレージに保存するとよいでしょう。

検索レスポンスの2種類の構造に対応する

検索結果には、構造上の重要な特徴があります。動画はtiktok.aweme_listに直接格納される場合と、tiktok.search_item_list[].aweme_infoの中に含まれる場合があります。最初のリストしか読み取らない処理では、2つ目の形式に含まれる結果を見落とす可能性があります。

次のように、両方の構造に対応し、動画オブジェクトが入れ子になっていない要素を安全にスキップする正規化関数を追加しましょう。

def extract_awemes(tiktok):
    items = list(tiktok.get("aweme_list") or [])

    for item in tiktok.get("search_item_list") or []:
        aweme = item.get("aweme_info")
        if aweme:
            items.append(aweme)

    return items


def normalize(aweme, keyword, collected_at):
    author = aweme.get("author") or {}
    stats = aweme.get("statistics") or {}

    return {
        "collected_at": collected_at,
        "keyword": keyword,
        "video_id": aweme.get("aweme_id"),
        "posted_at": aweme.get("create_time"),
        "description": aweme.get("desc"),
        "share_url": aweme.get("share_url"),
        "author_id": author.get("uid"),
        "author_name": author.get("nickname"),
        "views": stats.get("play_count"),
        "likes": stats.get("digg_count"),
        "comments": stats.get("comment_count"),
        "shares": stats.get("share_count"),
    }

値がない場合はNoneのままにします。ゼロに置き換えないでください。ゼロは測定された値を示しますが、Noneならフィールドがレスポンスに含まれていなかったことがわかります。この違いは平均値や割合、チーム向けの結論に影響します。

現在のスナップショットだけでなく履歴を保存する

変化を追跡するには、観測記録を個別に保存します。動画IDは投稿の重複排除に使えますが、履歴の削除には使いません。次回の収集で同じ動画が再び見つかった場合、それは新しい観測点になります。たとえば、観測テーブルの一意キーをvideo_idとcollected_atから作り、確認しやすいようリンクと説明文もレコードに保存できます。

プロトタイプには、次のような最小構成のSQLiteスキーマが便利です。

import sqlite3

conn = sqlite3.connect("tiktok_observations.sqlite3")
conn.execute("""
CREATE TABLE IF NOT EXISTS observations (
    video_id TEXT NOT NULL,
    collected_at TEXT NOT NULL,
    keyword TEXT NOT NULL,
    posted_at INTEGER,
    description TEXT,
    share_url TEXT,
    author_id TEXT,
    author_name TEXT,
    views INTEGER,
    likes INTEGER,
    comments INTEGER,
    shares INTEGER,
    PRIMARY KEY (video_id, collected_at, keyword)
)
""")
conn.commit()

実運用では、収集時刻をUTCに正規化し、元のJSONを別に保存して、スキーマのバージョン列も追加してください。新しいオブジェクトの構造が従来と異なるときに、元のレスポンスがあれば変換処理を再検証できます。複数の検索語で同じ投稿が見つかった場合は、一致した検索語を別の関連テーブルに保存するか、レポート作成時にまとめましょう。

ページネーション:レスポンスのカーソルを使って続行する

cursorパラメーターは検索の続きを取得するためのものです。前のレスポンスから値を取得し、変換せずに返送します。has_moreが続きがないことを示した場合、または設定した上限に達した場合は処理を終了します。カーソルは不透明な値として扱い、自分で計算したりページ番号に置き換えたりしないでください。

def collect_pages(keyword, max_pages=3):
    cursor = None
    collected = []

    for _ in range(max_pages):
        page = search_videos(keyword, cursor)
        collected.extend(extract_awemes(page))

        if not page.get("has_more"):
            break
        cursor = page.get("cursor")
        if cursor is None:
            break

    return collected

ページ数を制限すれば、定期処理のリクエスト量を予測しやすくなります。レポートのサンプル数を把握できるよう、実行ログにはページ数とhas_moreの値を記録しましょう。ページネーションを使っても、結果はAPIから受け取ったレスポンスと収集上限の範囲を示すものです。プラットフォーム上のすべての投稿を推定するものではありません。

再現可能なレポートを作成する

チームがより頻繁なシグナルを必要とする場合を除き、収集は週1回のスケジュールで実行します。実行ごとに、検索語の一覧、パラメーター、時刻、取得したオブジェクト数、一意なIDの数を記録してください。今回初めて見つかった投稿と、過去に見つかっている投稿は別々に集計します。

レポートには、次の4種類のシンプルな表示が役立ちます。

  • 新着動画:リンク、説明文、投稿日、動画が見つかった検索語。
  • 繰り返し現れるテーマ:「設定のエラー」「機能のリクエスト」「利用シナリオの紹介」など、手動で定義したカテゴリに説明文を分類。
  • 公開されている反応:取得可能な再生回数、いいね数、コメント数、シェア数を観測時刻とともに表示。
  • 確認すべきシグナル:新しい言い回し、よくある質問、担当者が詳しく見るべき動画。

レスポンス内の値の意味と鮮度を確認せずに、2つのスナップショット間の差を「新たに獲得したいいね」と呼ばないでください。「最後に取得したレスポンス内の指標の値」「保存済みスナップショット間の差」と表現するのが適切です。これにより、チームは何を計算したのかを把握でき、判断前に元の投稿を確認できます。

AIは収集の代わりではなく分類に活用する

正規化した後、動画の説明文をモデルに渡し、事前に定義したカテゴリに分類できます。必要なテキストフィールドだけを送信し、カテゴリ、簡潔な根拠、確信度、ラベルの根拠となった説明文の抜粋を構造化データとして返すように指示します。担当アナリストが判断の難しいケースを確認できるよう、ラベルの近くに元の投稿を保存してください。

実運用の流れはシンプルです。スケジューラーが収集を開始し、Pythonがレスポンスを検証してJSONを保存します。別の処理が新しいレコードを正規化し、分類器は新しい説明文だけを処理します。最後にデータベースからレポートを作成し、チームが選んだチャネルに送信します。TikTok Scraper APIが提供するのは検索データです。分類とレポート配信はPython、n8n、Makeなどで実装できる統合処理です。

ノイズを減らすには、モデルに送信する前にカテゴリの語彙を決め、手作業でラベル付けしたサンプルを定期的に点検してください。短い説明文や曖昧な説明文には、無理にカテゴリを選ばせるのではなく、「文脈不足」というステータスが役立ちます。AIラベルは確認待ちの投稿を整理するのに役立ちますが、ユーザーの課題に関する結論は、投稿を読み、複数の観測結果を比較して裏付けてください。

エラー、再試行、キーの安全な取り扱い

ネットワークリクエストは、タイムアウト、一時的なエラー、JSONとして解析できないレスポンスによって失敗することがあります。処理をリクエスト、HTTPコードの確認、JSON解析、外部ステータスの確認、正規化、保存の各段階に分けてください。一時的な障害には、待ち時間を段階的に延ばしながら回数を制限して再試行します。恒久的なエラーは後で調査できるよう記録し、実行を成功扱いにしないでください。

キーは実行環境のシークレットマネージャーまたは環境変数に保管してください。APIではlicense_keyをクエリ文字列で受け取るため、完全なURLやリクエストパラメーターのログ出力は避けましょう。そこに秘密情報が含まれてしまいます。診断用にはルート、レスポンスコード、所要時間、検索語、ジョブIDを記録し、ログからキーを除外してください。

スケジュールと収集量は、用途とプラットフォームの利用条件に応じて設定してください。公開データの収集は分析に本当に必要な範囲にとどめ、説明文、リンク、投稿者IDの保存についてはチーム内のルールに明記しましょう。APIのレスポンスや指標は不完全な場合や、観測ごとに変化する場合があります。そのため、レポートには収集時刻と各行の出所を記録してください。

結果:手作業で集めたリンクから、検証可能な履歴へ

設定が完了すると、チームは新たに見つかった動画の定期更新リスト、監査用の元レスポンス、取得可能な公開指標のテーブル、繰り返し現れるテーマの概要を得られます。これにより、新機能に関する質問をより早く把握し、ユーザーの利用例を見つけ、手動で分析する投稿を選びやすくなります。スナップショットの比較で、すでに見つかった動画の保存済み指標がどう変化したかを確認でき、検索ログからはどのようにサンプルが作成されたかをたどれます。

まずは検索語を1つ、ページ数を少なくして始め、実際のレスポンス構造を確認します。その後、検索語と実行スケジュールを追加してください。プロトタイプを本番環境に移す前に、重複排除、データの保存、エラー処理のルールを決めましょう。最新のルートとパラメーターはAPIの公式ドキュメントで確認できます。機能の説明とテスト開始方法はTikTok Scraper APIのページにあります。

People

No people listed for this article yet.

Keep reading公開指標で競合のTikTokクリエイティブを比較するPythonパイプライン
Read the next article

読んだ内容を実用的な連携へ

jsonscraperのソーシャルデータAPIを調べ、リクエストを試し、次のワークフローを構築しましょう。

APIを探す