2026-02-03追記
2026年に入ってから、X APIに大幅な変更があったようです。この記事の情報は2025年12月時点のものなのでご注意ください。
変更点を簡単にまとめると以下の通りです。
- 新規にDeveloper Portalへ登録したアカウントは無料でAPIを利用することができない
- APIの利用には最低5ドルの課金が必要だが、従量課金制に変更された
- 2026年以前にDeveloper Portalへ登録しておいたアカウントに関しては従来通り無料でAPIを使用可能(今のところは)
以下の記事で詳しく解説されています。
はじめに
この記事はMMA Advent Calendar 2025 - Adventarの2日目の記事です。前日は水素くんの記事でした。要件によってOSはしっかりと選びたいですね。
というわけでこんにちは。電気通信大学MMA4年生のUdonです。
皆さんはどのSNSをよく使っているでしょうか。絢爛な画像がメインとなるInstagram、実名でのやり取りが多いFacebookなど、この世には多くのSNSが存在します。
しかし、我々MMAのメンバーやMMAがある電気通信大学において最もシェア率の高いSNSは、やはりTwitter(現X) でしょう。
このSNSでは「ツイート=呟き(現ポスト)とそれに対する反応」という形で日々大量のテキストデータや画像・映像データがやりとりされています。それらの投稿は「リツイート(現リポスト)」という機能により拡散され、多くの人のタイムラインを駆け巡ることとなります。
また、Twitterは多くの企業や公的機関にとって貴重な情報公開の場となっています。テキストがメインであるという性質上、何かの情報公開の場として採用されやすいのでしょう。
これらのデータをたどることによって過去に何が起きたのかという事の流れを追うこともできるようになっており、もはや現代のアカシックレコードと言っても差支えがないような量のデータが蓄積され、刻々と増え続けている場、それがTwitter(現X)である、と自分は考えています。
さて、いくら有用なデータがあるといっても、利用にあたってやみくもに検索・収集していてはしょうがないです。何か効率よくデータに触れることができる仕組みが欲しいわけですね。
そういった仕組みとして真っ先に思いつくのは「スクレイピング」です。プログラミングによりウェブサイトのデータを自動的に抜き取り、収集するというわけですね。
しかし、X利用規約を読んでみると、「本サービスへのクローリングまたはスクレイピングを、当社による事前の書面での同意がないまま行うことは明示的に禁止されています」と書いてあります。こう言われてしまっているので、スクレイピングでデータを収集することは厳しそうです。規約違反と見なされて色々な罰則が生じるかもしれません。別の方法が必要になってきます。
そこで登場するのが今回の記事で紹介する「X API」です。APIとは「あるサービスが外部からリクエストを受け付ける窓口」のようなもので、これを適切に使うことでそのサービスから手軽にデータを収集することができます。
また、APIは利用頻度さえ守ればプログラム内から利用することができるので、ある程度自動的にデータを集めることが可能になります。
X API
というわけでXのAPIについて調べてみましょう。たいていのAPIにはドキュメントが用意されています。X APIもそれは例外ではありません。
ここからは、このドキュメントを参考にX APIを掘り下げていきましょう!
アクセスレベル
まずはどういったことができるのかをアクセスレベルの所で確認しましょう。
また、ここには上記に載っていない情報もあるので併せてチェックします(なぜ情報が分かれているかは不明)。
頑張って英語を読んでみると、以下のようなことが書かれています。
- Free
- 無料
- 1プロジェクトのみ
- 1アプリのみ
- 100ポスト/月(取得)
- 300ポスト/月(投稿)
- Basic
- 200ドル/月
- 1プロジェクトのみ
- 2アプリ
- 15000ポスト/月(取得)
- 50000ポスト/月(投稿)
- Pro
- 5000ドル/月
- 1プロジェクトのみ
- 3アプリ
- 1000000ポスト/月(取得)
- 300000ポスト/月(投稿)
目を引くのはやはり値段でしょう。この記事を書いてる時点で1ドル156円くらいだったので、Basicで31200円、Proに至っては78万円です!高すぎ。
そして、扱えるポストの数がレベルを上げるごとに跳ね上がっているのもわかります。Pro以外は投稿可能数が取得可能数より多いですね。Proはポスト解析に使われるのが前提なのでしょうか。
ドルで考えると、取得の場合Basicは0.013ドル/ポスト、Proは0.005ドル/ポストなので、一応プランのレベルが上がるほどコスパが良くなるみたいです。
OpenAIのような従量課金制ではないようですね。これは相当使う予定がない限り有料プランに申し込む勇気は出なさそうです。
今回は検証なので、Freeプランを使ってみます。
X Developers Portal
まずは「開発者ポータル」に登録し、アクセストークンを得る必要があります。
このサイトに行くと以下のような画面になります。
画面下の方の「Sign up for Free Account」をクリックします。すると、以下のような画面が出てきます。
Botでない証明なのか英作文をしろとのことです。「XのデータとAPIを利用するすべてのケースを書いてください」とあります。
画像にもありますが250字以上が必要なようです。適当に日本語で文章を考え、英訳したのを貼り付けました。
その後同意事項にチェックを入れたら「Submit」でリクエストを送ります。
送ると、割とすぐにダッシュボード画面に行く事ができます。
プロジェクト名は変更できませんが、アプリの名前は歯車アイコンから設定画面に行くと変更することができます。デフォルトはユーザ名+数字みたいなものなので、わかりやすいものに変えるのが吉です。
アクセストークンの取得
アプリの鍵アイコン(上記画像参照)から以下のような「鍵とトークン」のページに行けます。
上から2つ目の「Bearer Token」が必要なので、これをGenerateします。トークンが表示されるので、忘れずにコピーします。忘れたら再生成することとなります。
cURLでのアクセス
さて、ドキュメントにはAPIの用法が書かれています。丁寧なことに、以下の様に様々な言語での使用例が載っています。
今回はcURLを利用しましょう。詳しい話はほかの記事に譲りますが、簡単に言うと「リクエストヘッダなどのパラメータを自由に指定して通信を行えるコマンド」です。
APIの利用にあたっては先ほど取得したトークンが必要なので、このコマンドにトークン情報を付加して実行することが必要になります。
ポストの取得
ドキュメントによると、curlコマンドは以下のようにするといいみたいです。
curl --request GET \
--url https://api.x.com/2/users/{id}/tweets \
--header 'Authorization: Bearer <token>'
取得数はmax_resultsパラメータで5~100の範囲で指定できるようです。多すぎてもあれなので今回は5としてみます。これはクエリパラメータで指定するようです。
取得対象は電気通信大学MMAのアカウントとし、以下のようにコマンドを作ってみます。
ここで、上のidはuecmma(これはスクリーンネーム)ではないことに注意してください。このサイトでスクリーンネームをIDに変換できます。
MMAの場合は84645058でした。
curl --request GET \
--url 'https://api.x.com/2/users/84645058/tweets?max_results=5' \
--header 'Authorization: Bearer <token>'
実行すると以下のようになりました。jqにパイプをつないで見やすくし、-sオプションで余計な情報を省いています。
$ curl -s --request GET --url 'https://api.x.com/2/users/84645058/tweets?max_results=5' --header 'Authorization: Bearer <token>' | jq
{
"data": [
{
"text": "じゃんく市は盛況の中終了しました\n\nご来店いただき、ありがとうございました!\n\n#MMA #調布祭 #調布祭2025 #飛べ調布祭 https://t.co/VQxn10AUKc",
"edit_history_tweet_ids": [
"1992521582494027831"
],
"id": "1992521582494027831"
},
{
"text": "大特価6000円! https://t.co/CdMBPXnsrj",
"edit_history_tweet_ids": [
"1992510350189810165"
],
"id": "1992510350189810165"
},
{
"text": "\\\\じゃんく市 目玉商品紹介 その11//\n\n入試参考書\n\n本日はオープンキャンパスも開催しています\n\nどれも現役部員が受験生のときに使っていたのでご利益があるかも!?\n\n#調布祭 #調布祭2025 #飛べ調布祭 #MMA https://t.co/eXOs6tdi3g",
"edit_history_tweet_ids": [
"1992397022553591854"
],
"id": "1992397022553591854"
},
{
"text": "\\\\じゃんく市 目玉商品紹介 その10//\n\n小説\n\nあの名作\n\n 「夏の夜の夢•あらし」\n\nがあります\nシェイクスピアを読みたい人におすすめです\n\n#調布祭 #調布祭2025 #飛べ調布祭 #MMA https://t.co/eVzlRVAC3F",
"edit_history_tweet_ids": [
"1992034188577689938"
],
"id": "1992034188577689938"
},
{
"text": "\\\\じゃんく市 目玉商品紹介 その9//\n\n電子部品\n\n電子工作したい人にオススメ!\n\nまた、抵抗は0円です!\n\n#調布祭 #調布祭2025 #飛べ調布祭 #MMA https://t.co/sHlR4XrkdL",
"edit_history_tweet_ids": [
"1991774540037517511"
],
"id": "1991774540037517511"
}
],
"meta": {
"next_token": "7140dibdnow9c7btw4e3fk94zfu2yodc2ammkzwgw8isx",
"result_count": 5,
"newest_id": "1992521582494027831",
"oldest_id": "1991774540037517511"
}
}
取得する投稿は上から5つみたいで、ピン止めがある場合はそれは含まないみたいです。
利用枠をチェックすると、以下のように枠が5つ分減っています。
他にも「どのID以降か、どのID以前か」「どの期間か」などといったパラメータが指定できるみたいです。
ポストの取得ですが、一度取得した投稿は重複して利用枠にカウントされないようです。先ほどと同様にAPIを使って投稿を5個取ってみます。結果は以下の通り。
$ curl -s --request GET --url 'https://api.x.com/2/users/84645058/tweets?max_results=5' --header 'Authorization: Bearer <token>' | jq
{
"data": [
{
"edit_history_tweet_ids": [
"1992521582494027831"
],
"id": "1992521582494027831",
"text": "じゃんく市は盛況の中終了しました\n\nご来店いただき、ありがとうございました!\n\n#MMA #調布祭 #調布祭2025 #飛べ調布祭 https://t.co/VQxn10AUKc"
},
{
"edit_history_tweet_ids": [
"1992510350189810165"
],
"id": "1992510350189810165",
"text": "大特価6000円! https://t.co/CdMBPXnsrj"
},
{
"edit_history_tweet_ids": [
"1992397022553591854"
],
"id": "1992397022553591854",
"text": "\\\\じゃんく市 目玉商品紹介 その11//\n\n入試参考書\n\n本日はオープンキャンパスも開催しています\n\nどれも現役部員が受験生のときに使っていたのでご利益があるかも!?\n\n#調布祭 #調布祭2025 #飛べ調布祭 #MMA https://t.co/eXOs6tdi3g"
},
{
"edit_history_tweet_ids": [
"1992034188577689938"
],
"id": "1992034188577689938",
"text": "\\\\じゃんく市 目玉商品紹介 その10//\n\n小説\n\nあの名作\n\n 「夏の夜の夢•あらし」\n\nがあります\nシェイクスピアを読みたい人におすすめです\n\n#調布祭 #調布祭2025 #飛べ調布祭 #MMA https://t.co/eVzlRVAC3F"
},
{
"edit_history_tweet_ids": [
"1991774540037517511"
],
"id": "1991774540037517511",
"text": "\\\\じゃんく市 目玉商品紹介 その9//\n\n電子部品\n\n電子工作したい人にオススメ!\n\nまた、抵抗は0円です!\n\n#調布祭 #調布祭2025 #飛べ調布祭 #MMA https://t.co/sHlR4XrkdL"
}
],
"meta": {
"next_token": "7140dibdnow9c7btw4e3fk94zfu2yodc2ammkzwgw8isx",
"result_count": 5,
"newest_id": "1992521582494027831",
"oldest_id": "1991774540037517511"
}
}
情報は特に変わっていないみたいですね。利用枠をチェックしてみましょう。
利用枠は減っていませんでした。
また、これは以前別件で利用したときの知見なのですが、以下の情報も取得できます。
- いいね数
- リポスト数
- 返信数
これらの情報が変化した場合、同じ投稿を取得しても利用枠が減るようです。この辺は注意ですね。今回やったように投稿のIDやテキストだけを取得するなら「異なる投稿100件」を取得できそうです。
投稿
ドキュメントによると、curlコマンドは以下のようにするといいみたいです。
curl --request POST \
--url https://api.x.com/2/tweets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"card_uri": "<string>",
"community_id": "1146654567674912769",
"direct_message_deep_link": "<string>",
"edit_options": {
"previous_post_id": "1346889436626259968"
},
"for_super_followers_only": false,
"geo": {
"place_id": "<string>"
},
"media": {
"media_ids": [
"1146654567674912769"
],
"tagged_user_ids": [
"2244994945"
]
},
"nullcast": false,
"poll": {
"duration_minutes": 5042,
"options": [
"<string>"
],
"reply_settings": "following"
},
"quote_tweet_id": "1346889436626259968",
"reply": {
"exclude_reply_user_ids": [
"2244994945"
],
"in_reply_to_tweet_id": "1346889436626259968"
},
"reply_settings": "following",
"share_with_followers": false,
"text": "Learn how to use the user Tweet timeline and user mention timeline endpoints in the X API v2 to explore Tweet\\u2026 https:\\/\\/t.co\\/56a0vZUx7i"
}'
要素が結構ありますね。コミュニティ周りから返信設定まで色々あります。投票にするためのパラメータなどもありますね。これをいじるだけであらゆる形式の投稿ができるようです。
ここから単にテキストをツイートするために必要な要素を抜き出してみます。
curl --request POST \
--url https://api.x.com/2/tweets \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"text": "This is post from API!"
}'
意外とこれだけでした。トークンをつけ足して実行してみます。
{
"title": "Unsupported Authentication",
"detail": "Authenticating with OAuth 2.0 Application-Only is forbidden for this endpoint. Supported authentication types are [OAuth 1.0a User Context, OAuth 2.0 User Context].",
"type": "https://api.twitter.com/2/problems/unsupported-authentication",
"status": 403
}
あれれ、失敗してしまいました。どうやらBearer TokenによるOAuth 2.0 Application-Only認証では投稿はできないようです。
ならOAuth 1.0a User Context, OAuth 2.0 User Contextなるものを使えばいいようですが、調べてみるとこの方法では以下の記事のようにほかのトークンやキーを使って逐一認証を行う必要があるようです。
上の記事二つではどちらもプログラムに組み込んで投稿を行っていました。
しばらく調べましたが、cURLで投稿を行う例が見つかりませんでした。使うキーが増えている分明らかに難易度が高いので、おとなしく各種ライブラリを使ったほうが良さそうです。
今回は「cURLを用いて」という趣旨なので、いったんこれ以上は深入りしないこととします。
レート制限
一度curlをしたあと、もう一度やろうとすると以下のようになります。
{"title":"Too Many Requests","detail":"Too Many Requests","type":"about:blank","status":429}
どうやらリクエスト数が多い様子。これはパラメータをミスっていても起きます。ケチですね。
15分ほど待つとまたリクエストができるようになります。パラメータをミスってても利用枠は減らないようですが、リトライのために待たないといけないのは面倒です。
プログラムに組み込む場合も、リクエスト間隔を空ける処理が必須です。
その他
今回は検証しませんでしたが、他にも色々面白そうなAPIがありました。
- 投稿にいいねをする
- https://docs.x.com/x-api/users/like-post
- IDを指定した投稿にいいねができる
- フォロワーをリストアップ
- https://docs.x.com/x-api/users/get-followers
- 指定した人のフォロワー一覧を取得する
- DMを送信する
これらもゆくゆくは使ってみたいですね。利用枠がどれくらい消費されるのかも気になります(どれが「投稿枠」でどれが「取得枠」なんだろう、POSTなのかGETなのかの違いなんですかね)。
使ってみた感想
英作文をする必要があるのはかなり面倒ですが、最近はAIが発達しているのでそれに任せちゃえば良さそうですね。
連続リクエストができないのもかなりきつかったです。パラメータをミスっても15分待たないといけないというのは苦しいです。Bot対策とはいえこんなに間隔開けなくてもいいじゃないですか。
一か月100個しか投稿を取得できないのは結構渋いですが、IDとテキスト、付加された画像というかなりいい情報を取得できるので、工夫次第で便利なツールが作れそうです。
今回はcURL縛りをしていたので投稿までは掘り下げませんでしたが、いつかは投稿を自動化できるようにしたいですね。
おわりに
いかがだったでしょうか。調べてみると相当お金を取られるサービスみたいでした。
色々便利な使い方ができそうですが、検証にも割と手間がかかるのでその辺は微妙かな、という感じです。
ただドキュメントを見る限りAPIとしては相当洗練されたものなので、Xのデータを扱いたい!と思っている人は是非利用してみてください!
それではまた。
明日はさいんさんの記事です。よろしくお願いします!
参考文献
Twitter APIを初めて触ってみる(ツイートを取得) #curl - Qiita
Twitter API v2(X API Free)の使い方・移行(2025年)【GAS】 #JavaScript - Qiita






