Yahooリアルタイム検索のAPIが本当に有能だからみんな使ったほうがいい話
X(旧Twitter)の画像を検索したいとき、公式APIを使おうとすると月100ドル以上かかる。でも実はYahooリアルタイム検索のバックエンドAPIを使えば、認証不要・無料で大量のツイートと画像を取得できる。しかも思ったより高機能だったので紹介する。
TL;DR
GET https://search.yahoo.co.jp/realtime/api/v1/pagination?p=キーワード&md=h&results=40&mtype=image
これだけで認証なしにX(Twitter)の画像付きツイートが40件取れる。
基本的な使い方
const res = await fetch(
`https://search.yahoo.co.jp/realtime/api/v1/pagination?${new URLSearchParams({
p: "アニメ",
md: "h", // 人気順(省略すると新着順)
results: "40", // 最大40件
mtype: "image", // 画像付きのみ
})}`,
{
headers: {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json, text/plain, */*",
"Referer": "https://search.yahoo.co.jp/realtime/search",
},
}
);
const data = await res.json();
const entries = data.timeline.entry;
// entries[0].media[0].item.mediaUrl で画像URLが取れる
User-Agentを偽装しないとブロックされるので注意。それ以外は特に制約なし。
何がすごいのか
1. レート制限がない(検証済み)
500連続リクエスト・1000並列リクエストを試したが、エラーは一切なかった。レスポンスヘッダーにも X-RateLimit-* 等は存在しない。
2. 並列取得で爆速
start パラメータでオフセット指定ができるため、複数ページを同時にリクエストできる。
// 4ページを並列取得(逐次比4.1倍速を確認)
const pages = await Promise.all(
[1, 41, 81, 121].map(start =>
fetch(`...&start=${start}`).then(r => r.json()).then(d => d.timeline.entry)
)
);
const entries = pages.flat(); // 160件、重複なし
3. 最大10000件を並列取得 → さらにその先も取れる
start の上限は10000件だが、その後は oldestTweetId カーソルに切り替えることで無制限に続きを取得できる。600ページ(18000件超)以降も継続取得できることを確認済み。
// フェーズ1: start で並列取得(最大10000件)
const starts = Array.from({ length: 250 }, (_, i) => i * 40 + 1);
const pages = await Promise.all(starts.map(start => fetchPage({ start })));
const entries = pages.flat();
// フェーズ2: カーソルで続きを逐次取得(上限なし)
let cursor = entries.at(-1)?.id;
while (cursor) {
const page = await fetchPage({ oldestTweetId: cursor });
if (!page.length) break;
entries.push(...page);
cursor = page.at(-1)?.id;
}
4. 期間指定ができる
since / until にUnixタイムスタンプを渡すと期間絞り込みができる(日付文字列は無効)。
const since = Math.floor(new Date("2026-01-01").getTime() / 1000);
const until = Math.floor(new Date("2026-03-01").getTime() / 1000);
// ?since=1735689600&until=1740787200
5. クエリ演算子が使える
| 構文 | 説明 |
|---|---|
(A B) / A OR B
|
OR検索 |
A -B |
NOT検索 |
ID:username |
特定ユーザーの投稿 |
@username |
特定ユーザー宛て |
#hashtag |
ハッシュタグ |
URL:domain |
URL含む投稿 |
例:#イラスト -AI で非AI絵師のイラストのみ取得、ID:nhk_news でNHKの投稿のみ取得、など。
6. レスポンスが情報豊富
各ツイートに以下が含まれる:
- 画像/動画URL(
media[].item.mediaUrl) - いいね数・RT数・リプライ数・QT数
- ユーザー情報(ID・表示名・プロフィール画像)
- 認証バッジ(
badge.type:blue=個人認証、business=企業認証) - 引用ツイートの内容(
quotedTweet) - センシティブフラグ(
possiblySensitive) - 動画の長さ(
media[].item.durationミリ秒)
主なパラメータ一覧
| パラメータ | 値 | 説明 |
|---|---|---|
p |
文字列 | 検索クエリ |
md |
h / 省略 |
h=人気順、省略=新着順 |
results |
数値 | 取得件数(最大40) |
mtype |
image / video
|
画像のみ / 動画のみ |
start |
数値 | 取得開始位置(1始まり、上限10000) |
oldestTweetId |
ツイートID | カーソルページネーション |
since |
Unixタイムスタンプ | この時刻以降のみ |
until |
Unixタイムスタンプ | この時刻以前のみ |
注意点・制限
- 日本語ツイート特化:英語クエリでも日本語ツイートが返る。海外ユーザーのツイートはほぼ取得できない
-
mtype=image推奨:付けないとメディアなしツイートが大量に混入する(40件中6件程度しかメディアなし) -
start上限は10000件:それ以上はoldestTweetIdカーソルで取得 -
エンゲージメント絞り込み不可:
min_faves:100等のTwitter演算子は無効。クライアント側でフィルタするしかない -
GIFのみ絞り込み不可:
mtype=gifは無効。mediaType === "animated_gif"でクライアント側フィルタ
ユースケース
- 画像検索アプリ:キーワードで画像付きツイートを大量収集してギャラリー表示
-
ハッシュタグまとめ:
#イラスト+mtype=imageでハッシュタグ画像一覧 -
特定ユーザーの画像一覧:
ID:username+mtype=image -
バズ画像モニタリング:
md=h人気順でリアルタイムトレンド把握 -
期間アーカイブ:
since/untilで特定期間のツイートを収集 -
複数クエリ並列検索:
Promise.allでクエリ単位の並列実行
公式APIが有料化されて以来、X関連のデータ取得手段が限られていたが、このAPIは認証不要・レート制限なし・高機能と三拍子揃っている。日本語コンテンツに限定されるが、日本語圏のユーザーには十分すぎるほど使える。