1
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?

PythonでX(Twitter)のツイートを検索・取得する【2026年版・開発者アカウント不要】

1
Posted at

本記事には筆者が開発に関わっているサービス(GetXAPI)の紹介を含みます。公式X APIとの料金・手順の比較はすべて執筆時点の公開情報に基づいています。

X(旧Twitter)のデータをPythonで取得したい。ツイートを検索したい、特定アカウントの投稿を集めたい、フォロワーを分析したい。よくあるニーズですが、2026年の今、「どのAPIをどう使うか」の前提が数年前とは大きく変わっています。

この記事では、現在のX APIの状況を整理した上で、開発者アカウントなしでツイート検索・取得を動かすまでを、コピペで動くPythonコードと一緒に解説します。検索演算子、ページネーション、エラーハンドリング、コスト試算まで一通りカバーします。

2026年のX APIの選択肢

2026年のX API事情を3分で整理する

まず前提の整理です。「Twitter APIは無料で使える」という古い記事がまだ大量に検索に出てきますが、現在の状況は違います。

公式X APIの現状(執筆時点の公開ドキュメントより):

  • 現在の公式料金ページには、一般向けの無料枠(Freeプラン)の記載がありません。プリペイドの従量課金と、個別見積もりのEnterpriseの2本立てです
  • 読み取りは「返されたリソース単位」で課金されます。標準のPost読み取りは1件$0.005。つまり100件返ってくる検索リクエスト1回で$0.50です
  • 書き込みはリクエスト単位で、標準の投稿作成は1回$0.015です
  • 従量課金には月300万件のPost読み取り上限があり、それを超える規模はEnterprise契約になります
  • 利用開始には開発者アカウントの作成、アプリの作成、認証情報の生成、支払い方法の登録が必要です

「返されたリソース単位」という課金モデルは見落としやすいポイントです。リクエスト数ではなく、レスポンスに含まれるツイート数で課金されるため、検索やタイムラインのような複数件返るエンドポイントでは、想定よりコストが速く積み上がります。1,000ツイートの読み取りで$5、10万ツイートで$500です。

返されたリソース単位で課金される仕組み

選択肢は実質3つ

選択肢 初期費用 1,000ツイートあたり 主なハードル
公式X API プリペイド購入 $5(標準Post読み取り) 開発者アカウント+アプリ設定、カード登録
サードパーティAPI(本記事) $0(無料クレジット) 約$0.05 登録のみ
OSSスクレイパー(snscrape等) $0 $0 ゲストエンドポイント廃止後はほぼ動作せず、保守が絶えない

snscrapeやtwikitのようなオープンソースのスクレイパーは、かつては定番でしたが、Xの仕様変更のたびに壊れる状態が続いています。ログイン型のものは実アカウントを使うため、アカウント制限のリスクも自分で抱えることになります。

本記事ではサードパーティAPIのGetXAPIを使います。筆者が開発に関わっているサービスなのでその点は割り引いて読んでいただきたいのですが、「Bearerキー1つで、コール単位の従量課金」というモデルはこの用途に素直にはまります。1コール$0.001で約20ツイートが返るため、1,000ツイートあたり約$0.05。登録時に$0.10の無料クレジット(約100コール、約2,000ツイート分)が付くので、この記事のコードは全部無料枠内で試せます。クレジットカードの登録は不要です。

セットアップ:30秒でAPIキーを取得する

  1. getxapi.com/signupでGoogleアカウントまたはメールで登録します
  2. ダッシュボードに表示されるBearerキーをコピーします
  3. 環境変数に入れます
export GETXAPI_KEY="コピーしたキー"

これで終わりです。開発者アカウントの作成もアプリの登録もOAuthの設定もありません。以降のすべてのリクエストは、この1つのキーをAuthorizationヘッダーに載せるだけです。

キーの管理について1点だけ。コードに直書きせず、必ず環境変数か秘密情報マネージャーから読んでください。公開リポジトリにキーをコミットしてしまった場合は、ダッシュボードから再発行(旧キーの無効化)ができます。

最初のリクエスト:ツイートを検索する

まずは動作確認を兼ねて、キーワードでツイートを検索します。依存はrequestsだけです。

pip install requests
import os
import requests

API_KEY = os.environ["GETXAPI_KEY"]
BASE_URL = "https://api.getxapi.com"

resp = requests.get(
    f"{BASE_URL}/twitter/tweet/advanced_search",
    params={"q": "生成AI lang:ja", "product": "Latest"},
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=30,
)
resp.raise_for_status()
data = resp.json()

for tweet in data.get("tweets", [])[:5]:
    print(tweet["text"][:80])

productパラメータは2種類あります。

  • Latest: 新着順。リアルタイム監視やアラート向き
  • Top: エンゲージメント順。話題のツイートのダイジェスト向き

省略した場合はLatestです。

検索演算子:欲しいツイートだけを取る

qパラメータには、Xの高度な検索と同じ演算子がそのまま使えます。クライアント側でフィルタするのではなく、クエリの時点で絞り込むのがコスト面でも正解です。

検索演算子で欲しいツイートだけに絞り込む

演算子 意味
from:ユーザー名 特定アカウントの投稿 from:nasa
to:ユーザー名 特定アカウント宛の返信 to:nasa
min_faves:N いいねN件以上 決算 min_faves:100
min_retweets:N リポストN件以上 地震 min_retweets:50
since: / until: 日付範囲 since:2026-01-01 until:2026-06-30
lang:ja 日本語の投稿のみ LLM lang:ja
filter:verified 認証済みアカウントのみ セキュリティ filter:verified
-filter:retweets リポストを除外 新製品 -filter:retweets

組み合わせの例です。「日本語で、リポストを除き、いいね50件以上の生成AI関連ツイート」なら:

query = "生成AI lang:ja -filter:retweets min_faves:50"

ページネーション:1,000件を確実に集める

1コールで返るのは約20ツイートです。まとまった件数が必要な場合は、レスポンスに含まれるnext_cursorを次のリクエストに渡して繰り返します。

カーソルでページを辿るイメージ

import os
import time
import requests

API_KEY = os.environ["GETXAPI_KEY"]
BASE_URL = "https://api.getxapi.com"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def search_tweets(query: str, max_tweets: int = 1000) -> list[dict]:
    """クエリに一致するツイートを、カーソルを辿って集める。"""
    tweets: list[dict] = []
    cursor = None

    while len(tweets) < max_tweets:
        params = {"q": query, "product": "Latest"}
        if cursor:
            params["cursor"] = cursor

        resp = requests.get(
            f"{BASE_URL}/twitter/tweet/advanced_search",
            params=params,
            headers=HEADERS,
            timeout=30,
        )

        if resp.status_code == 429:
            # レスポンスのretry_afterに従う。なければ短い指数バックオフ
            wait = int(resp.headers.get("retry-after", 0)) or 2
            time.sleep(wait)
            continue

        resp.raise_for_status()
        payload = resp.json()

        batch = payload.get("tweets", [])
        if not batch:
            break

        tweets.extend(batch)
        cursor = payload.get("next_cursor")
        if not cursor:
            break

    return tweets[:max_tweets]


if __name__ == "__main__":
    results = search_tweets("生成AI lang:ja -filter:retweets", max_tweets=1000)
    print(f"{len(results)}件取得")

1,000ツイートはおよそ50コール、コストにして約$0.05です。無料クレジットの範囲内に収まります。

ユーザー情報とフォロワーも同じキーで取れる

検索以外もエンドポイントを差し替えるだけです。

# プロフィール取得
resp = requests.get(
    f"{BASE_URL}/twitter/user/info",
    params={"userName": "nasa"},
    headers=HEADERS,
    timeout=30,
)
profile = resp.json()["data"]
print(profile["name"], profile["followers"])
# フォロワー一覧(こちらもカーソルでページネーション)
resp = requests.get(
    f"{BASE_URL}/twitter/user/followers",
    params={"userName": "nasa"},
    headers=HEADERS,
    timeout=30,
)
followers = resp.json()

ツイート詳細、リプライ、タイムライン、DM、リスト、トレンドなど、読み書き合わせて71のエンドポイントが同じBearerキーで使えます。全エンドポイントと単価は料金ページにまとまっています。

実践:収集したツイートをCSVに保存する

分析パイプラインの入り口としてよくある「検索してCSVに落とす」までを1本にまとめます。

import csv
import os
import time
import requests

API_KEY = os.environ["GETXAPI_KEY"]
BASE_URL = "https://api.getxapi.com"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def collect_to_csv(query: str, path: str, max_tweets: int = 500) -> None:
    tweets = []
    cursor = None

    while len(tweets) < max_tweets:
        params = {"q": query, "product": "Latest"}
        if cursor:
            params["cursor"] = cursor

        resp = requests.get(
            f"{BASE_URL}/twitter/tweet/advanced_search",
            params=params,
            headers=HEADERS,
            timeout=30,
        )
        if resp.status_code == 429:
            time.sleep(int(resp.headers.get("retry-after", 0)) or 2)
            continue
        resp.raise_for_status()

        payload = resp.json()
        batch = payload.get("tweets", [])
        if not batch:
            break
        tweets.extend(batch)
        cursor = payload.get("next_cursor")
        if not cursor:
            break

    with open(path, "w", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow(["id", "created_at", "author", "text", "likes", "retweets"])
        for t in tweets[:max_tweets]:
            author = t.get("author") or {}
            writer.writerow([
                t.get("id"),
                t.get("createdAt"),
                author.get("userName"),
                (t.get("text") or "").replace("\n", " "),
                t.get("likeCount"),
                t.get("retweetCount"),
            ])
    print(f"{min(len(tweets), max_tweets)}件を{path}に保存しました")


if __name__ == "__main__":
    collect_to_csv("決算 lang:ja min_faves:10", "tweets.csv", max_tweets=500)

このままpandasで読み込めば、頻度分析やセンチメント分析にそのまま進めます。

エラーハンドリング:実運用で当たる4つ

長時間動かすコードでは、次の4つを想定しておけば大半のトラブルは吸収できます。

429はretry_afterに従って落ち着いてリトライ

ステータス 意味 対処
401 キーの誤り・欠落・失効 ダッシュボードでキーを確認して再設定
402 クレジット残高切れ 自動課金はされず、チャージするまで402が返るだけ
429 レート制限(サービス側のキャパシティ制御、またはX側のアカウント上限) retry_afterに従って待ってからリトライ
5xx 一時的なサーバーエラー 短いバックオフでリトライ

残高が切れても勝手に課金されない(402が返るだけ)という挙動は、試験運用では安心材料です。

レート制限について補足すると、エンドポイント別のクォータ(公式APIの「15分あたりN回」のような時間窓)はありません。ただし持続的な高並列では全体的なスロットリングとして429が返ることがあるので、上のコードのようにリトライパスは必ず用意してください。

コストの考え方:リクエスト単価とツイート単価を区別する

APIのコスト比較で混乱しがちなのが、「1リクエストいくら」と「ツイート1件いくら」の混同です。

同じ1,000ツイートでもコストは大きく違う

  • GetXAPI: 1コール$0.001で約20ツイート。ツイート単価は約$0.00005
  • 公式X API: 返されたPost1件$0.005。ツイート単価がそのまま$0.005

同じ「1,000ツイートの読み取り」で並べると、約$0.05と$5になります。月10万ツイートを読むダッシュボードなら約$5と$500です。自分のボリュームで試算したい場合はコスト計算ツールが便利です。

なお、公式APIが適している場面もあります。エンドユーザーが自分のXアカウントでログインして操作を認可するOAuthのユーザー委任フローが必要なアプリや、プラットフォーム直結であることがコンプライアンス上必須のケースでは、公式API一択です。今回のような「公開データの収集・分析」がユースケースなら、サードパーティAPIの方が導入も運用も軽くなります。

まとめ

  • 2026年の公式X APIは従量課金制で、一般向け無料枠の記載はなく、読み取りは返されたリソース単位($0.005/Post)で課金される
  • 開発者アカウントなしでツイートを取得するなら、サードパーティAPIが現実的な選択肢
  • GetXAPIなら登録30秒、Bearerキー1つ、1,000ツイート約$0.05。$0.10の無料クレジットで本記事のコードはすべて試せる
  • 検索演算子で取得段階から絞り込み、カーソルでページネーション、429はretry_afterでリトライ

関連リンク:

質問やつまずいた点があればコメントでどうぞ。

1
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
1
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?