Sabigara

Twitter API v2 でスレッド内のツイート一覧を取得する

開発していたアプリの機能として、Twitterのスレッド内のツイートをまとめて取得する要件があった。

要件は以下の通り。

  1. ユーザーがスレッド内の任意のツイートURLを入力する
  2. アプリが対象スレッドのツイート(リプライを除く)をすべて表示する

簡単そうだが、意外とめんどくさかったので方法をメモしておく。

試行1: conversation_id

方法

API docsやフォーラムの投稿によると、リプライによるツイートのグループは conversation_id によって管理されていることがわかる。

Conversation IDファビコンdeveloper.twitter.com

Twitter Community

今回のアプリの場合は、あくまでスレッドの投稿者のツイートのみが対象であり、他ユーザーのリプライなどは除く必要があった。

一応は以下のようなコードで要件は達成できる。(node-twitter-api-v2 を使用)

async function getThreadTweets(statusId: string) {
  const tweetRes = await twitter.singleTweet(statusId, {
    "tweet.fields": "author_id,conversation_id",
  });
  const searchRes = await twitter.search(
    `conversation_id:${tweetRes.data.conversation_id} from:${tweetRes.data.author_id} to:${tweetRes.data.author_id}`
  );
}

fron:<author_id> to:<author_id> をクエリ条件に加えることで、他ユーザーのリプライを除いて、投稿者自身のツイートのみを抽出できる。

問題点

APIに2回リクエストを投げるだけで実現できるので簡単に見えるが、実は落とし穴がある。

Search APIは直近7日間のツイートしか取得できない。この制限を乗り越えるには Academic Research access 権限が必要。今回のアプリは学術研究ではないのであきらめるしかない。

試行2: referenced_tweets

方法

API docsによると各ツイートは referenced_tweets を持っている。

A list of Tweets this Tweet refers to. For example, if the parent Tweet is a Retweet, a Retweet with comment (also known as Quoted Tweet) or a Reply, it will include the related Tweet referenced to by its parent.

そのツイートがリプライしているツイートを取得できるのであれば、 スレッドの最後からどんどん遡っていけば、全ツイートをたどれそうだ。

export async function getThreadRecursive(
  statusId: string,
  results: TweetV2[] = []
) {
  const tweet = await twitter.singleTweet(statusId, {
    expansions: "referenced_tweets.id",
  });
  const previous = tweet.data.referenced_tweets?.find(
    (t) => t.type === "replied_to"
  );

  results.push(tweet.data);

  if (previous) {
    await getThreadRecursive(previous.id, results);
  }

  return results;
}

regerenced_tweets.typeretweeted , quoted , replied_to のいずれかなので、一応検証している。

リプライ先が本当に正しいのか、つまりスレッドの本流なのかは検証していないので、ここではユーザーの入力を信じるしかない。

問題点

まとめ

Academic Research accessがない以上、とりあえず試行2の方法を使うしかなさそう。

他に良いやり方があればぜひ教えてください。