Python での Twitter API:動くコード付き 2026年版チュートリアル
Python で Twitter/X データを取得するには、requests か Tweepy のようなクライアントで X データ API を呼び、リクエストごとにキーを送って、カーソルをたどりながら1ページずつ読みます。公式 X API は投稿1件につき$0.005かかります。
結論: Tweepy と X の SDK である xdk は、公式 X API 向けの無料ライブラリです。ただし公式 X API には、開発者アカウント、ベアラートークン、前払いクレジットが必要で、料金は投稿1件につき$0.005、2026年11月22日からは投稿者を含めると$0.015です。公開データの取得なら、requests で Sorsa API を使います。キー1つ、1リクエスト20ツイート、1,000件あたり$0.07から。100回分の無料リクエストで2,000ツイートをカバーできます。
- エンドポイント
POST /search-tweets- ページサイズ
- 1リクエストあたり20ツイート
- 料金
- 1,000ツイートあたり$0.07から
#2026年も Tweepy は使えますか?
はい。Tweepy 4.17.0 は2026年7月2日にリリースされ、X は自社の Python SDK である xdk をバージョン 0.10.6 で公開しています。どちらも公式 X API のクライアントなので、呼び出しのたびに開発者アカウント、アプリのベアラートークン、前払いクレジットが必要です。
古いチュートリアルが書いていないのが、クレジットの話です。新規開発者向けの無料プランはなく、X はレスポンスが返すオブジェクトごとに課金します。投稿は1件$0.005、ユーザーは1件$0.010で、投稿の読み取りは月300万件までです(X の料金表(新しいタブで開きます))。2026年11月22日からは、展開(expansions)で付随して取得される投稿者などのオブジェクトにも同じ料金がかかります(10月23日付の X の告知(新しいタブで開きます))。そのため、よくある Tweepy の検索は、付いてくる投稿者の分まで課金されます。
import tweepy
client = tweepy.Client(bearer_token="YOUR_BEARER_TOKEN")
resp = client.search_recent_tweets(
"python lang:en",
max_results=100,
expansions=["author_id"],
)
# 100 posts: $0.50. From Nov 22, 2026, with authors: up to $1.50
ライブラリ自体は無料のオープンソースです。ホームページには今も、背後の API には無料プランと有料プランがあると書かれていますが、新規アカウントには当てはまりません。料金、上限、日付の一覧は X API の料金にまとめています。
公式ルートで最初の呼び出しの前に必要なもの
- console.x.com の開発者アカウント。X アカウントで開設し、X の開発者契約に同意しておきます。
- アプリ。そのベアラートークンは X が一度しか表示しません(X のアクセスガイド(新しいタブで開きます))。
- 事前に購入するクレジット。返された投稿とユーザーごとに消費されます。
- 投稿、いいね、フォローを行う処理のための OAuth ユーザートークン。
公開されている投稿やプロフィールの読み取りに、これらは一切不要です。独自のキーを持つ Twitter/X データ API は素の HTTPS で応答するので、スクリプトに必要なクライアントは requests だけです。
#キー1つで Python からツイートを取得する
Python から X データを読むには、Twitter(X)API 兼スクレイピングツールである Sorsa API を使います。OAuth の代わりに ApiKey ヘッダー1つ、無料アカウントを含む全プランで毎秒20リクエスト、検索結果は1,000ツイートあたり$0.07からです。公開された投稿、プロフィール、フォロワーを JSON で返し、どのツイートにも投稿者のプロフィール全体が含まれます。X のログインを求められることはないので、あなたの X アカウントに危険が及ぶことはありません。
キーを用意して最初のリクエストを送る
-
キーを取得する。 サインアップして、ダッシュボードから API キーをコピーします。最初の100リクエストは無料で、カード不要、有効期限もありません。
-
requests をインストールしてキーを保存する。 キーはコードに書かず環境変数に置き、API はスクリプトかサーバーから呼び出してください。ブラウザの JavaScript からは呼ばないでください。
Terminal pip install requests export SORSA_API_KEY="your_key" # PowerShell: $env:SORSA_API_KEY="your_key" -
ツイートを検索する。 X の検索構文のクエリを、
ApiKeyヘッダーにキーを付けてPOST /search-tweets(新しいタブで開きます) に送ります。import os import requests API = "https://api.sorsa.io/v3" HEADERS = {"ApiKey": os.environ.get("SORSA_API_KEY", "YOUR_API_KEY")} r = requests.post( f"{API}/search-tweets", headers=HEADERS, json={"query": "python lang:en", "order": "latest"}, timeout=30, ) r.raise_for_status() for tweet in r.json()["tweets"]: print(tweet["user"]["username"], tweet["full_text"][:60]) -
ページを読む。 各レスポンスには最大20ツイートと、次のページ用の
next_cursorが入っています。以下の値は、ドキュメントどおりの形式のデモデータです。Response200 OK { "tweets": [ { "id": "1985432176540981234", "full_text": "Loaded a week of #python posts into pandas in four lines.", "created_at": "2026-11-01T18:42:07Z", "lang": "en", "likes_count": 42, "retweet_count": 7, "reply_count": 3, "quote_count": 1, "view_count": 3810, "bookmark_count": 5, "is_reply": false, "user": { "id": "1592041833471827968", "username": "py_data_notebook", "display_name": "Py Data Notebook", "followers_count": 1840, "verified": false } } ], "next_cursor": "DAABCgABF7Y8kQ3wAAA" }
すべてのツイートにカウントと投稿者が付いて届くので、スクリプトで expansions やフィールド一覧を指定する必要はありません。多くのスクリプトが読むフィールドは次のとおりです。
| フィールド | 内容 | 例 |
|---|---|---|
id | 19桁のツイート ID。文字列として送られるので、文字列のまま保持すること | 1985432176540981234 |
full_text | 投稿の全文 | Loaded a week of #python posts |
created_at | 投稿された日時。UTC の ISO 8601 形式 | 2026-11-01T18:42:07Z |
likes_count, retweet_count, reply_count, quote_count | エンゲージメント数 | 42 |
view_count, bookmark_count | 表示数とブックマーク数 | 3810 |
user | 投稿者のプロフィール。username や followers_count など19フィールド | py_data_notebook, 1840 |
quoted_status, retweeted_status | 引用元またはリポスト元のツイート(同じ形式) | ツイートオブジェクト |
id- 内容
- 19桁のツイート ID。文字列として送られるので、文字列のまま保持すること
- 例
1985432176540981234
full_text- 内容
- 投稿の全文
- 例
- Loaded a week of #python posts
created_at- 内容
- 投稿された日時。UTC の ISO 8601 形式
- 例
2026-11-01T18:42:07Z
likes_count,retweet_count,reply_count,quote_count- 内容
- エンゲージメント数
- 例
42
view_count,bookmark_count- 内容
- 表示数とブックマーク数
- 例
3810
user- 内容
- 投稿者のプロフィール。
usernameやfollowers_countなど19フィールド - 例
py_data_notebook,1840
quoted_status,retweeted_status- 内容
- 引用元またはリポスト元のツイート(同じ形式)
- 例
- ツイートオブジェクト
#429 とサーバーエラーを1つのヘルパーでリトライする
すべてのリクエストを、リトライする価値のあるものだけを再試行する1つの関数に通します。429 は、あなたのキーで1秒以内に20を超えるリクエストを開始したという意味で、5xx はサーバー側の一時的な障害です。このガイドの以降のコードは、この call ヘルパーを土台にしています。
import os
import time
import requests
API = "https://api.sorsa.io/v3"
RETRY = {429, 500, 502, 503, 504}
KEY = os.environ.get("SORSA_API_KEY", "YOUR_API_KEY")
session = requests.Session()
session.headers["ApiKey"] = KEY
def call(method, path, **kwargs):
"""Send one request; retry 429 and 5xx up to 4 times."""
for attempt in range(5):
r = session.request(method, API + path, timeout=30, **kwargs)
if r.status_code not in RETRY or attempt == 4:
break
time.sleep(2 ** attempt) # 1, 2, 4, 8 seconds
r.raise_for_status()
return r.json()
401 や 403 はリトライする価値がありません。キーが間違っているか未指定であるか、リクエストを使い切っているかのどれかで、どれなのかは JSON の message フィールドに書かれています。失敗したリクエストは課金されないので、リトライに費用はかかりません。Sorsa API のエンドポイントはすべて読み取りだけを行うため、/search-tweets のような POST をリトライしても何かが二重に作られることはなく、制限は毎秒リセットされるので、1秒待てば最初の 429 は解消します。
#next_cursor でページをたどる
カーソルは、結果の次のページへの不透明なキーです。next_cursor は変更せずに送り返し、レスポンスに含まれなくなったら止めます。検索とタイムラインは1ページあたり最大20ツイートを返しますが、まだ続きがあってもページの件数が少ないことがあるため、件数で終わりに達したかどうかは判断できません。
def pages(path, body, max_pages=100):
"""Yield the pages of a POST endpoint until the cursor runs out."""
for _ in range(max_pages):
page = call("POST", path, json=body)
yield page
cursor = page.get("next_cursor")
if not cursor:
break
body = {**body, "next_cursor": cursor}
for page in pages("/search-tweets", {"query": "python lang:en"}):
for tweet in page["tweets"]:
print(tweet["id"], tweet["created_at"])
1つのカーソルをたどる間は、クエリと order を変えないでください。max_pages は予算として扱いましょう。そうすれば、広いクエリでも想定より多く消費することはありません。GET エンドポイントはカーソルをクエリパラメーターで受け取ります。1ページあたり最大200プロフィールを返す GET /followers(新しいタブで開きます) は、params から next_cursor を読みます。2つの作業には、専用の完成したスクリプトがあります。ユーザーの全ツイートをダウンロードは、保存したカーソルからタイムライン全体を再開でき、Twitter のフォロワーをエクスポートするガイドは、フォロワー一覧を CSV に書き出します。
#1リクエストで100件のツイートやプロフィールを取得する
ID やユーザー名をすでに持っているなら、バッチで送ります。POST /tweet-info-bulk(新しいタブで開きます) は最大100件のツイート ID またはリンクを受け取り、GET /info-batch(新しいタブで開きます) は最大100件のユーザー名を受け取ります。どちらも1リクエストです。
def chunks(items, size=100):
for i in range(0, len(items), size):
yield items[i:i + size]
tweets = []
for batch in chunks(tweet_ids):
tweets += call("POST", "/tweet-info-bulk",
json={"tweet_links": batch})["tweets"]
profiles = []
for batch in chunks(usernames):
profiles += call("GET", "/info-batch",
params={"usernames": batch})["users"]
リクエストは何を返しても同じ料金なので、100ツイートのバッチも1ツイートと同じコストです。1,000ツイートあたり$0.014から、公式 X API の$5.00の250分の1以下です。requests では、params に渡したリストは繰り返しパラメーター(usernames=a&usernames=b)として送られ、これが GET /info-batch の読む形式です。バッチのレスポンスにカーソルはありません。1回のレスポンスにバッチ全体が tweets または users に入っています。
#ツイートを CSV か pandas の DataFrame に保存する
pandas.json_normalize を使うと、ツイートオブジェクトのリストが1回の呼び出しで DataFrame になり、入れ子の投稿者は user.username のようなドット区切りの列になります。
import pandas as pd
rows = []
for page in pages("/search-tweets", {"query": "python lang:en"},
max_pages=50):
rows += page["tweets"]
df = pd.json_normalize(rows)
df = df[["id", "created_at", "user.username", "full_text",
"likes_count", "retweet_count", "view_count"]]
df["created_at"] = pd.to_datetime(df["created_at"])
df.to_csv("tweets.csv", index=False)
50ページで1,000ツイートになり、ノートブックに向いた量です。pandas 版は最後まですべての行をメモリに保持するため、数十万ツイート以上のジョブでは csv 版に切り替えてください。ページが届くたびに書き出すので、実行がどれだけ長くなってもメモリ使用量は一定です。
知っておきたいこと
ツイート ID は19桁ですが、Excel が保持できるのは15桁なので、ダブルクリックで開いた CSV では、すべての ID の下の桁が0になってしまいます。ファイルを読み戻すときは
pd.read_csv("tweets.csv", dtype={"id": str})を使い、Excel では「データ」の「テキストまたは CSV から」で取り込んで、ID の列をテキストに設定してください。
#asyncio で毎秒最大20リクエストを実行する
Sorsa API はキー1つにつき毎秒20リクエストを全プランで許可しており、作業が独立したチェーンに分かれていれば、Python のプロセス1つで asyncio によってこのレートに届きます。1つのカーソルチェーンは分けられません。各ページが直前のページのカーソルを必要とするからです。そこで、アカウントごと、または検索の日ごとに複数のチェーンを並べて実行し、キーを上限以下に保つ共有のペーサーを1つ置きます。このバージョンには pip install httpx が必要です。
import asyncio
import os
import time
from datetime import date, timedelta
import httpx
API = "https://api.sorsa.io/v3"
HEADERS = {"ApiKey": os.environ.get("SORSA_API_KEY", "YOUR_API_KEY")}
RETRY = {429, 500, 502, 503, 504}
class Pace:
"""Start at most `rate` requests a second, evenly spaced."""
def __init__(self, rate=20):
self.gap, self.next = 1 / rate, 0.0
self.lock = asyncio.Lock()
async def wait(self):
async with self.lock:
now = time.monotonic()
start = max(self.next, now)
self.next = start + self.gap
await asyncio.sleep(start - now)
async def fetch(client, pace, body):
for attempt in range(5):
await pace.wait()
r = await client.post("/search-tweets", json=body)
if r.status_code not in RETRY or attempt == 4:
break
await asyncio.sleep(2 ** attempt)
r.raise_for_status()
return r.json()
async def lane(client, pace, query, max_pages=100):
"""One cursor chain: its pages run one after another."""
body, tweets = {"query": query}, []
for _ in range(max_pages):
page = await fetch(client, pace, body)
tweets += page["tweets"]
if not page.get("next_cursor"):
break
body = {**body, "next_cursor": page["next_cursor"]}
return tweets
async def main(queries):
pace = Pace(19) # one pacer per key, one start under the limit
async with httpx.AsyncClient(base_url=API, headers=HEADERS,
timeout=30) as client:
return await asyncio.gather(
*(lane(client, pace, q) for q in queries))
day = date(2026, 10, 1)
days = [day + timedelta(n) for n in range(32)] # Oct 1 to Nov 1
queries = [f"python lang:en since:{a} until:{b}"
for a, b in zip(days, days[1:])]
results = asyncio.run(main(queries)) # Jupyter: await main(queries)
Pace は、待っているレーンがいくつあっても、開始時刻を均等に割り当てます。毎秒19回なら開始1回分の余裕が残るので、ネットワークのジッターで Sorsa API の20回を超えることはなく、それでもすり抜けた 429 はリトライが拾います。ペーサーはキー1つにつき1つにしてください。ペーサーを持つプロセスを2つ動かすと、両者の合計で上限の2倍の開始になることがあります。毎秒20リクエストなら、100件のバッチで毎秒最大2,000ツイート、検索ページで400ツイートを処理できます。
知っておきたいこと
Jupyter ノートブックではすでにイベントループが動いているため、
asyncio.run(main(queries))は RuntimeError で止まります。ノートブックのセルでは、代わりにresults = await main(queries)と書いてください。
次のプランナーは、ジョブをリクエスト数、1つのキーでの所要時間、Sorsa API の最低レートでのコストに換算します。
- リクエスト数
- 5,000
- 1キーでの最短時間
- 約 4分
- Sorsa API
- 最安 $7
- 無料の100リクエスト
- 2,000
1リクエストあたり20ツイート
毎秒20リクエストの場合
1,000リクエストあたり$1.40
ツイート、カード不要
検索は1本のカーソルの連なりです。日付範囲に分割し、レーンとして並行実行すると、この速度に届きます。
表示している時間は1キーで出せる最短です。1本のカーソルの連なりはそれより遅いため、大きなジョブはレーンに分割してください。
#Python のジョブのコスト
Sorsa API はエンドポイントが何を返すかにかかわらず、リクエスト単位で課金します。検索結果は1,000ツイートあたり$0.07から、バッチは$0.014からで、失敗したリクエストは課金されません。公式 X API はオブジェクト単位で課金します。1,000投稿あたり$5.00で、2026年11月22日からは、ほとんどの Tweepy スクリプトのように各投稿の投稿者を展開すると、1,000投稿あたり最大$15.00になります。
公式 X API
$5,000
1Mツイートの場合
1投稿$0.005
Sorsa API
$70から
1Mツイートの場合
1,000件あたり$0.07から
投稿者はすべてのツイートに含まれています
1,000リクエストあたりの単価は、Starter の$4.90から Hyperscale の$1.40までで、どのプランもすべてのエンドポイントに同じ単価を適用します。残りの確認は無料で行えます。GET /key-usage-info(新しいタブで開きます) はリクエストとしてカウントされません。
usage = call("GET", "/key-usage-info")
print(usage["remaining_requests"], "left until", usage["valid_until"])
#Tweepy のコードを Sorsa API へ移す
Tweepy の呼び出しの大半は Sorsa API のエンドポイント1つに対応し、コードは短くなります。すべてのツイートが最初から投稿者とカウントを持つので、expansions もフィールド一覧も要りません。次の表は、Tweepy の Client の各メソッドとエンドポイントを対応させたものです。コードベース全体を移すなら、Twitter/X API からの移行のガイドが v2 の全エンドポイントとレスポンスのフィールドを対応づけています。
| Tweepy のメソッド | エンドポイント | 変わる点 |
|---|---|---|
search_recent_tweets | POST /search-tweets | 直近7日間だけでなく、2006年までさかのぼれる |
search_all_tweets | POST /search-tweets | 同じエンドポイントで、クエリに since: と until: を指定 |
get_users_tweets | POST /user-tweets | ユーザー名だけでよく、3,200件の上限がない |
get_tweets | POST /tweet-info-bulk | 1リクエストあたり100件の ID またはリンク |
get_users | GET /info-batch | 1リクエストあたり100ユーザー名 |
get_users_followers | GET /followers | 1ページあたり200フォロワー |
get_retweeters | POST /retweeters(新しいタブで開きます) | 同じカーソルのループ |
create_tweet | なし | 読み取り専用:投稿は公式 X API で |
search_recent_tweets- エンドポイント
POST /search-tweets- 変わる点
- 直近7日間だけでなく、2006年までさかのぼれる
search_all_tweets- エンドポイント
POST /search-tweets- 変わる点
- 同じエンドポイントで、クエリに
since:とuntil:を指定
get_users_tweets- エンドポイント
POST /user-tweets- 変わる点
- ユーザー名だけでよく、3,200件の上限がない
get_tweets- エンドポイント
POST /tweet-info-bulk- 変わる点
- 1リクエストあたり100件の ID またはリンク
get_users- エンドポイント
GET /info-batch- 変わる点
- 1リクエストあたり100ユーザー名
get_users_followers- エンドポイント
GET /followers- 変わる点
- 1ページあたり200フォロワー
get_retweeters- エンドポイント
POST /retweeters(新しいタブで開きます)- 変わる点
- 同じカーソルのループ
create_tweet- エンドポイント
- なし
- 変わる点
- 読み取り専用:投稿は公式 X API で
フィールド名も変わります。text は full_text に、public_metrics["like_count"] は likes_count に、author_id と includes["users"] は user オブジェクトに、next_token は next_cursor になります。Tweepy の wait_on_rate_limit=True に相当する設定はありません。X の15分間のウィンドウはコードから消え、毎秒リセットされる制限は call のリトライとペーサーが処理するからです。POST /user-tweets(新しいタブで開きます) は、公式のタイムラインが止まる最新3,200件の投稿よりも先まで届きます(X のタイムラインのドキュメント(新しいタブで開きます))。
#今日、最初の検索を実行する
X のデータを Python に取り込むのに必要なのは、requests、キー1つ、そして4つの小さなヘルパーです。リトライ用の call、カーソル用の pages、100件のバッチ用の chunks、毎秒20リクエスト用の Pace です。まずは、公開された X データを大規模に読むために作られた Twitter API である Sorsa API から始めましょう。検索は1リクエスト20ツイートで1,000件あたり$0.07から、すべてのツイートに投稿者が含まれ、100回分の無料リクエストはカード不要で期限もありません。JavaScript での同じ呼び出しは Node.js での Twitter API のガイドにあり、ノーコードのワークフローからは n8n での Twitter API で利用できます。
#よくある質問
Python 向けの無料の Twitter API はありますか?
公式 X API に、新規開発者向けの無料プランはありません。Tweepy と xdk は無料ですが、読み取りのたびに前払いクレジットが投稿1件あたり$0.005消費されます。Sorsa API は、すべてのアカウントに、有効期限がなくカードも不要な100回分の無料リクエストを付けています。Python からなら、検索で2,000ツイート、100件のバッチなら最大1万ツイートを収集できます。
Python ではどの Twitter API を使うべきですか?
Python から X データを読むなら Sorsa API を使います。OAuth の代わりに requests で API キー1つ、検索結果は1,000ツイートあたり$0.07から、バッチは$0.014から、全プランで毎秒20リクエスト、検索は2006年までさかのぼれます。X へのログインは不要なので、あなたのアカウントが危険にさらされることはありません。投稿も行いたい場合は、公式 X API と組み合わせてください。
開発者アカウントなしで Python から Twitter データを取得できますか?
できます。Sorsa API に必要なのは自社のキーだけです。サインアップして ApiKey ヘッダーを設定すれば、Python から45あるエンドポイントのどれでも呼べます。X の開発者アカウントも、アプリの審査も、OAuth も不要です。ユーザー名やブラウザの Cookie でログインして X を読むライブラリは、そのアカウントを危険にさらします。トレードオフは 開発者アカウントなしの Twitter API で比較しています。
Sorsa API で Python からツイートを投稿できますか?
できません。Sorsa API は設計上、読み取り専用です。公開された投稿、プロフィール、フォロワーを読み取るだけで、投稿、いいね、フォロー、メッセージ送信は行わないため、キーで X アカウントを操作することはできません。Python から投稿するには、OAuth ユーザートークンを使った公式 X API を使います。たとえば Tweepy の create_tweet は1投稿$0.015です。読み取りには Sorsa API を使い続けてください。
Sorsa API 向けの Python SDK や pip パッケージはありますか?
パッケージは不要です。Sorsa API は JSON を使う素の REST なので、requests か httpx で全エンドポイントをカバーでき、このガイドのヘルパーは約40行に収まります。api.sorsa.io/v3/swagger.json の最新の OpenAPI リファレンスに45のエンドポイントがすべて載っているので、必要なら openapi-generator のようなジェネレーターで型付きのクライアントを生成できます。
#検証方法
このガイドのすべてのリクエストを、Sorsa API の最新の OpenAPI リファレンス(45エンドポイント)と、レート制限、ページネーション、エラーに関するドキュメントから書きました。いずれも2026年11月2日に確認しています。今回は Sorsa API のキーがなかったため、表示したレスポンスはデモ値です。Python のブロックはすべて、ドキュメントどおりの形式で応答するローカルのモックに対して実行しました。リトライ、カーソルのループ、100件のバッチ、pandas と csv の書き出し、そして asyncio のペーサーです。毎秒19回の開始では31レーンが 429 なしで動き、ちょうど20回にすると、タイミングのジッターで1、2件のリクエストがリトライ側に送られました。同じ日に、docs.x.com にある公式 X API の料金、アクセス手順、検索とタイムラインの制限、展開の課金に関する X の告知、そして Tweepy と xdk の PyPI ページを確認しました。
情報源
- X API pay-per-usage pricing (docs.x.com)(新しいタブで開きます)
- Getting Access (docs.x.com)(新しいタブで開きます)
- Tools and libraries: the official Python SDK (docs.x.com)(新しいタブで開きます)
- X API PPU: expansions update (X Developers, October 23, 2026)(新しいタブで開きます)
- Search Posts (docs.x.com)(新しいタブで開きます)
- tweepy on PyPI(新しいタブで開きます)
- xdk on PyPI(新しいタブで開きます)
- Sorsa API reference, OpenAPI
- Sorsa API rate limits(新しいタブで開きます)
- Sorsa API pagination(新しいタブで開きます)