APIを使ってTikTok動画を検索すると、処理側が最初に想定する配列とは別の場所に動画が格納されている場合があります。jsonscraperの `\/searchVideo` に対する確認済みのレスポンスでは、`aweme_list` は空で、動画データを含む要素は `search_item_list[].aweme_info` にありました。コードが `aweme_list` だけを読み取ると、レスポンスに検索結果が含まれていても、動画を1件も保存できません。開発者にとっての具体的な信頼性向上策は、データの両方の形式を抽出し、データベースへの書き込みやレポートへの送信前に単一のリストへ正規化することです。
![JSON解析でTikTok検索結果を取りこぼさない方法
概要:TikTok検索の実践ガイド:エンドポイント `/searchVideo` は空の `aweme_list` を返すことがあり、見つかった動画は `search_item_list[].aweme_info` に入っている場合があります。IDで重複を除去しながら、両方の構造をPythonで正規化する方法を紹介します。
画像の役割:カバー — 中心的なアイデア
セクション:JSON解析でTikTok検索結果を取りこぼさない方法
ビジュアルの主題:TikTok APIのJSON正規化を表すエディトリアル写真:2つの異なるストリーム](/assets/uploads/journal/2026/11/3f9ca6f48040b3044b8190c9a7b7a847.png.hero.webp)
実際の例とエンドポイントの説明は、jsonscraperのAPI仕様とTikTokエンドポイントのドキュメントで確認できます。仕様に記載されたスキーマのスナップショットの日付は2026年10月25日です。これは特定のレスポンスの構造を示すものであり、それ以降のすべてのリクエストで各フィールドが必ず存在することを保証するものではありません。
パーサーが空のリストを返す理由
`GET https://tiktok.evelode.com/searchVideo` エンドポイントは、必須パラメーター `keyword` を使って動画を検索します。ドキュメントには `cursor`、`count`、`cache_timeout`、`date_posted`、`sort_by`、`region` も記載されています。観測されたレスポンスのスキーマでは、トップレベルのオブジェクトに `status` とネストされた `tiktok` オブジェクトが含まれます。その内部には `cursor`、`has_more`、`status_code`、`aweme_list`、`search_item_list` があります。
キーワードと `count=3` を指定したリクエストで確認した例では、`aweme_list` は空でした。一方、`search_item_list` には動画情報が `aweme_info` に格納された要素が含まれていました。これらのオブジェクトには、動画ID、キャプション、投稿URL、投稿者、再生数、いいね数、コメント数などの統計情報が含まれる場合があります。ここで説明したフィールドは観測されたスキーマに基づくものです。処理側では、値が欠けているケースにも対応してください。
重要なのは、HTTPリクエストの成功と、想定した1つのフィールドに空でない配列があることは別々に確認すべきだという点です。まず外側のステータスと `tiktok` の有無を確認し、次にドキュメントに記載された各場所から動画を収集します。分析用にはIDと元のレスポンスを保存してください。そうすれば、個々のレコードがどのように抽出・正規化されたかを追跡できます。
ストレージへの保存前にレスポンスを正規化する
APIと独自システムの境界には、ネストされた `tiktok` オブジェクトを受け取り、統一された要素を返す関数を設けると便利です。両方の配列を処理し、辞書ではない要素や空の要素を除外するとともに、`aweme_id` で同一動画の重複を取り除きます。プロバイダーがカウンターを返さなかった場合は、空のままにしてください。ゼロは測定された値を意味しますが、`None` はフィールドが存在しないことを表します。
以下はPython 3.8以降で動作する最小限の例です。リクエストを1回送信し、通信状態とトップレベルのステータスを確認してから、2種類の結果を正規化し、選択したフィールドを出力します。キーは環境変数から読み込み、ログには出力しません。
import os
import requests
BASE_URL = "https://tiktok.evelode.com"
def extract_videos(tiktok):
candidates = []
aweme_list = tiktok.get("aweme_list") or []
if isinstance(aweme_list, list):
candidates.extend(aweme_list)
search_items = tiktok.get("search_item_list") or []
if isinstance(search_items, list):
for item in search_items:
if isinstance(item, dict):
candidates.append(item.get("aweme_info"))
unique = {}
for video in candidates:
if not isinstance(video, dict):
continue
video_id = video.get("aweme_id")
if video_id:
unique[video_id] = video
return list(unique.values())
license_key = os.environ["JSONSCRAPER_TIKTOK_LICENSE_KEY"]
response = requests.get(
BASE_URL + "/searchVideo",
params={
"license_key": license_key,
"keyword": "python tutorial",
"count": 10,
"region": "US",
},
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")
if not isinstance(tiktok, dict):
raise RuntimeError("Response has no tiktok object")
for video in extract_videos(tiktok):
stats = video.get("statistics") or {}
author = video.get("author") or {}
print({
"aweme_id": video.get("aweme_id"),
"desc": video.get("desc"),
"share_url": video.get("share_url"),
"author": author.get("unique_id"),
"play_count": stats.get("play_count"),
"digg_count": stats.get("digg_count"),
"comment_count": stats.get("comment_count"),
})
`python -m pip install requests` を実行して依存関係をインストールし、実行環境に `JSONSCRAPER_TIKTOK_LICENSE_KEY` を設定して、たとえば `search_videos.py` という名前でファイルを保存します。リクエストパラメーターには、ドキュメントに記載された `keyword`、`count`、`region` を使い、`license_key` はクエリパラメーターとして渡します。このコードは、記録された例と同様に `status: "ok"` が返ることを想定しています。APIが別のステータスを返した場合は、想定外の構造が後続処理に渡される前に停止します。
例を繰り返し実行できる収集処理にする
一度だけエクスポートするなら、正規化した要素をJSON Linesまたはテーブルに保存すれば十分です。定常的に実行する処理では、取得時刻と検索語句を添えて元のレスポンスも保存しましょう。正規化した動画を格納する別テーブルでは、`aweme_id` をキーとして使えます。同じ結果が再び返された場合はレコードを更新し、2つの配列に同じIDがあっても重複レコードは作成されません。
![JSON解析でTikTok検索結果を取りこぼさない方法
概要:TikTok検索の実践ガイド:エンドポイント `/searchVideo` は空の `aweme_list` を返すことがあり、見つかった動画は `search_item_list[].aweme_info` に入っている場合があります。IDで重複を除去しながら、両方の構造をPythonで正規化する方法を紹介します。
画像の役割:補足図2 — 別の具体的な側面
セクション:例を繰り返し実行できる収集処理にする
ビジュアルの主題:TikTok検索レスポンスの仕様を示すロシア語の技術インフォグラフィック](/assets/uploads/journal/2026/11/39ced48bbcc7b623445dea615bee2279.png.hero.webp)
次のページを取得するには、ドキュメントに従って `cursor` パラメーターに前のレスポンスで受け取った値を渡します。カーソルは不透明なトークンとして扱い、変換せずに保存して返してください。`has_more` が続きなしを示す場合、またはAPIから有効なカーソルが提供されない場合は、ページネーションのループを終了します。誤ったロジックによる無限ループを防ぐため、1回の実行で処理するページ数にも上限を設けてください。確認済みの情報源が裏付けているのは、パラメーター名と、観測されたスキーマにおける `cursor` および `has_more` フィールドの存在です。結果の網羅性は保証されていません。
複数の検索語句を監視する場合は、語句を動画IDおよび収集時刻とともに保存します。これにより、検索ごとのデータを切り出し、実行ごとの検索結果を比較し、新しいIDを後続の分類キューに送ることができます。このようなシステムが記録するのは実際に取得した検索結果です。データセットの内容は、クエリ、地域、時刻、そしてAPIが実際に返した要素に左右されます。
リクエストの成功だけでなくデータ品質も確認する
正規化後は、パイプラインの単純な技術指標を記録すると便利です。たとえば、各配列から取得したレコード数、一意のID数、IDがない要素の割合、統計情報がない要素の割合を追跡します。これらは個々のレスポンスを処理する際の指標であり、動画の人気度を示す評価ではありません。たとえば `play_count` がない要素の割合が増えた場合、分析側ではゼロを代入せず、不明値を保持してフィールドの完全性を記録すべきです。
すべての動画が同じ統計情報を必ず持つことを前提に、後続の計算を組み立てないでください。生データを保存する際はJSON全体を保持し、分析用テーブルでは必要なフィールドだけを選択して `NULL` を許容します。レスポンス形式が変わった場合でも、元データのアーカイブがあれば再リクエストせずに正規化処理を再実行できます。
APIキーは、CIのシークレットまたはオーケストレーターの環境変数を通じて渡してください。ログに保存されるURLへ含めたり、リクエストパラメーターオブジェクトを出力したり、キーの値を元のレスポンスと一緒に保存したりしないでください。定期実行する場合は、リクエストのタイムアウト、HTTPエラー処理、待機時間を設けた再試行を追加します。検索結果の異なるページが混ざらないよう、カーソルは必ず対応する検索語句とともに保存してください。
結果:動画を取りこぼさない統一テーブル
正規化後は、動画要素が `aweme_list` と `search_item_list[].aweme_info` のどちらに格納されていたかにかかわらず、後続のコードは単一の動画リストを受け取ります。IDで重複を除去し、任意のフィールドは明示的に空のまま保持できます。これにより、一方の配列だけを読み取ったためにレポートが空になるリスクを抑え、次のエクスポート、フィルタリング、分類といった処理を予測しやすくできます。
確認を始めるには、基本APIエンドポイントとデモへのリンクが掲載されたTikTok Scraper APIのページをご覧ください。連携には公式ドキュメントを使い、まず少数の要素で処理を確認します。必要に応じて `count` を増やし、ドキュメントに記載されたカーソルで検索結果を続けて取得してください。これにより、TikTok全体を網羅できるという前提ではなく、用途に応じた整然としたデータレイヤーを構築できます。