0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

TiktokAPIの認証情報を取得する手法

Posted at

🎯 目的

TikTokのAPI:

https://ads.tiktok.com/creative_radar_api/v1/popular_trend/list

からトレンド動画リストを取得したい。

postman.png

しかし、このAPIを直接呼び出すには以下のヘッダーが必要です:

  • anonymous-user-id
  • user-sign
  • timestamp

これらはブラウザ内で動的に生成されるため、通常のHTTPクライアントでは再現できません

そこで、本コードでは仮想ブラウザ環境(jsdom)を使ってヘッダーを抽出するというアプローチをとっています。

🔎 なぜ anonymous-user-iduser-sign が必要なのか?

TikTokは非公開APIへのアクセスに対して、リクエストの正当性を確認するための署名ヘッダーを要求します。

  • anonymous-user-id は匿名ユーザーの識別用
  • user-sign はユーザーIDやタイムスタンプを元に生成される署名トークン

これらがないと、APIはエラーや空データを返します。

❗ 課題

  • 必要なヘッダーはブラウザ上でJavaScriptにより生成される
  • 単純なHTTPリクエストではヘッダーを再現できず、APIアクセスが拒否される

✅ 解決方法

本コードは、以下のステップでヘッダーを取得します:

  • got-scraping でページHTMLを取得
  • jsdom で仮想DOMを生成し、JavaScriptを実行
  • XMLHttpRequestsetRequestHeader をフックしてヘッダーを傍受
  • 全ヘッダーが揃うまで待機して値を取得

🧠 コードの概要(補足)

// TikTok API用の認証ヘッダーを生成する
import { JSDOM, VirtualConsole } from 'jsdom'; // Layer jsdomから
import { gotScraping } from 'got-scraping'; // Layer got-scrapingから

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

async function getApiUrlWithVerificationToken(body, url) {
  // JSDOMを使用してAPIセッションヘッダーを取得
  console.log('JSDOMでAPIセッションヘッダーを取得開始...');
  console.log('ページURL: ', url);
  console.log('ページ内容の長さ: ', body.length);

  const virtualConsole = new VirtualConsole();
  const { window } = new JSDOM(body, {
    url,
    contentType: 'text/html',
    runScripts: 'dangerously',
    resources: 'usable',
    pretendToBeVisual: false,
    virtualConsole,
  });

  virtualConsole.on('error', (err) => {
    // JSDOMエラーをログ
    console.error('JSDOMエラー: ', err);
  });

  const apiHeaderKeys = ['anonymous-user-id', 'timestamp', 'user-sign'];
  const apiValues = {};
  let retries = 10;
  let headersFound = false;

  window.XMLHttpRequest.prototype.setRequestHeader = (name, value) => {
    if (apiHeaderKeys.includes(name)) {
      apiValues[name] = value;
      console.log(`取得したヘッダー: ${name}=${value}`);
      if (Object.keys(apiValues).length === apiHeaderKeys.length) {
        headersFound = true;
        console.log('すべてのヘッダーを取得: ', apiValues);
      }
    }
  };

  window.XMLHttpRequest.prototype.open = (method, urlToOpen) => {
    console.log(`XHRリクエスト開始: ${method} ${urlToOpen}`);
  };

  // ヘッダー取得ロジック
  console.log('ヘッダー取得ループ開始...');
  while (retries > 0 && !headersFound) {
    console.log(`試行残り: ${retries}, 取得済みヘッダー: `, Object.keys(apiValues));
    await sleep(1000);
    retries--;
  }

  console.log('ヘッダー取得ループ終了、headersFound: ', headersFound);
  window.close();

  if (!headersFound) {
    console.error('最終的に取得できたヘッダー: ', apiValues);
    throw new Error('トークン生成に失敗: 必要なヘッダーをすべて抽出できませんでした。');
  }

  console.log('API認証ヘッダーの取得に成功: ', apiValues);
  return apiValues;
}

export async function getHeaders() {
  // 初期ページをフェッチしてヘッダーを生成
  console.log('ヘッダー生成のために初期ページをフェッチ中...');
  const url = 'https://ads.tiktok.com/business/creativecenter/inspiration/popular/hashtag/pad/en';
  try {
    console.log('gotScrapingリクエスト開始: ', url);
    const response = await gotScraping({
      url,
      timeout: { request: 30000 },
    });
    console.log('ページフェッチ成功、ステータスコード: ', response.statusCode);
    return await getApiUrlWithVerificationToken(response.body.toString(), url);
  } catch (error) {
    console.error(`${url} からページフェッチ失敗: `, error.message);
    throw error;
  }
}
  • getHeaders()
    • 初期ページのHTMLを取得し、getApiUrlWithVerificationToken() に渡す
  • getApiUrlWithVerificationToken(body, url)
    • ヘッダーを検出するため、仮想DOM内でスクリプトを実行
    • XMLHttpRequest を上書きし、必要なヘッダー値を取得

💡 工夫したこと

  • jsdomの virtualConsole を使って、仮想ブラウザ内のエラーもログに出力
  • ヘッダーが揃うまで最大10回リトライし、安定して値を取得できるように設計
  • 本来セキュリティ対策として隠されている内部通信を、副作用(XHR)を利用して自然に取得

📌 まとめ

TikTokの内部APIを扱う際に必要な認証ヘッダーを、仮想ブラウザで抽出する手法です。

  • 公開されていないAPIにアクセスしたい
  • JavaScript内で生成される認証ヘッダーが必要
  • 通常のクローリング手法では不十分

といった場面で、このような仮想実行+傍受のアプローチが有効です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?