X APIの使い方メモ

X APIを使い始めたのでそのメモ。

目次

準備(Free前提)

X Developers

アカウント作成。ちなみに誓約文みたいなの最初に書かされるが、僕は以下のように書いて提出した。

I plan to use the Twitter API to automate the posting and deletion of my own tweets. The frequency will be a few times per day at most. Additionally, I want to explore the capabilities of the Twitter API to evaluate potential business use cases. This includes testing API functionalities to understand their limitations and usability. The data accessed through the API will not be resold or used for commercial redistribution.

Freeプランなら、アカウント作成した時点でアプリがデフォルトでなんかできてる。デフォルトのやつを選択して、以下をGenerateする。

  • API Key
  • API Secret
  • Access Token
  • Access Token Secret

最初にできるのはReadだけ。

WriteにはOAuth2.0による認証認可が必要になる。

  1. Twitter Developer Portal (https://developer.twitter.com/en/portal/dashboard) にアクセス
  2. 作成したアプリを選択
  3. "Settings" > "User authentication settings" に移動
  4. App permissionsを編集し、"Read and Write" を選択
  5. 権限変更後、トークンを再生成

以後、Access TokenとAccess Token Secretを置き換えることで、Writeもできるようになる。

レート制限

レート制限がキツイので、最初に書いておく。

公式を参照しつつ。

Rate limits - X

  • 15分が一つの単位
    • Free Limitだと、ほとんどのWrite系リクエストは15分に1度しか許されない
  • 負荷が重そうなものは1日単位
    • 削除については、1日あたり17回までのようだ。17ってどっから出てきたんだろう……。
    • トレンドやユーザ情報取得系に至っては1日に1回しかできない。とてもカジュアルに試せるものではない。
  • トレンド系はBasic以上($200/月……)じゃないと使えない
  • ユーザ検索などPro以上($5000/月……)じゃないと使えないものもある

例によってマスクがマスクであるために、現時点(2025-02-12)における情報でしかない。またすぐ変わりそうだが、緩和される可能性は低い。

基本的な使い方

プロフィール取得、投稿、削除。Free Limitは制限めっちゃ厳しいので、カジュアルに実行するとすぐ制限くらう。自分の情報取得は何度か使える。

import requests
from requests_oauthlib import OAuth1

API_KEY = "xxxx"
API_SECRET = "xxxx"
ACCESS_TOKEN = "xx-xx"
ACCESS_SECRET = "xxxx"

# OAuth 1.0a 認証
auth = OAuth1(API_KEY, API_SECRET, ACCESS_TOKEN, ACCESS_SECRET)

def get_user_info():
    """
    自分のユーザー情報を取得する関数
    """
    API_URL = "https://api.twitter.com/2/users/me"
    response = requests.get(API_URL, auth=auth)
    
    if response.status_code == 200:
        print(response.json())
        user_data = response.json().get("data", {})
        print(f"ユーザー情報取得")
        print(f"ID: {user_data.get('id')}")
        print(f"名前: {user_data.get('name')}")
        print(f"ユーザー名: {user_data.get('username')}")
        return user_data
    else:
        print(f"エラー発生: {response.status_code}")
        print(response.json())
        return None

def post_tweet(text):
    """
    指定したテキストでツイートを投稿する関数
    """
    API_URL = "https://api.twitter.com/2/tweets"
    payload = {"text": text}
    
    response = requests.post(API_URL, json=payload, auth=auth)
    
    if response.status_code == 201:
        tweet_id = response.json().get("data", {}).get("id")
        print(f"ツイート成功 ID: {tweet_id}")
        return tweet_id
    else:
        print(f"エラー発生: {response.status_code}")
        print(response.json())
        return None

def delete_tweet(tweet_id):
    """
    指定したIDのツイートを削除する関数
    """
    API_URL = f"https://api.twitter.com/2/tweets/{tweet_id}"
    
    response = requests.delete(API_URL, auth=auth)
    
    if response.status_code == 200:
        print(f"ツイート削除成功 ID: {tweet_id}")
        return True
    else:
        print(f"エラー発生: {response.status_code}")
        print(response.json())
        return False


# 関数を使用する例
user_info = get_user_info()
# tweet_id = post_tweet("テストツイート")
# delete_tweet(tweet_id)

usernameからユーザの情報を取得する

Free Limitでも15分に3回使えて比較的緩い。

ここからは認証認可をOAuth 2.0でやる。Bearer Tokenをデベロッパーポータルから取得し、それを使ってアクセスする。

import requests

# Bearer Token認証を使用
BEARER_TOKEN = "xxxx"

def get_user_by_username(username):
    """
    指定したユーザー名のユーザー情報を取得
    username: @を除いたユーザー名
    """
    API_URL = f"https://api.twitter.com/2/users/by/username/{username}"
    
    headers = {
        "Authorization": f"Bearer {BEARER_TOKEN}"
    }
    
    params = {
        'user.fields': 'description,created_at,profile_image_url,public_metrics'
    }
    
    response = requests.get(API_URL, headers=headers, params=params)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"⚠️ エラー発生: {response.status_code}")
        print(response.json())
        return None

# 特定ユーザーの情報を取得
user = get_user_by_username("tamasan774")
print(user)

結果

{
   "data":{
      "name":"tama",
      "id":"3302753743",
      "profile_image_url":"https://pbs.twimg.com/profile_images/1428753262660833284/zUwv5vPL_normal.png",
      "description":"技術者の響きだけで生きてる。酒が飲みたい。",
      "username":"tamasan774",
      "public_metrics":{
         "followers_count":154,
         "following_count":93,
         "tweet_count":24154,
         "listed_count":8,
         "like_count":17991,
         "media_count":222
      },
      "created_at":"2015-07-31T19:15:51.000Z"
   }
}

指定した条件でツイートのカウント

基本的に無課金おじさんお断りだが、/GET /2/tweets/counts/recentだけはFreeプランでも使える。

import requests

# Bearer Token認証を使用
BEARER_TOKEN = "xxxx"

def get_recent_tweet_counts(query, start_time=None, end_time=None):
    """
    過去7日間の特定クエリに一致するツイート数を時系列で取得
    
    params:
    - query: 検索クエリ(例: "#Python")
    - start_time: 集計開始時間(ISO 8601形式)
    - end_time: 集計終了時間(ISO 8601形式)
    """
    API_URL = "https://api.twitter.com/2/tweets/counts/recent"
    
    headers = {
        "Authorization": f"Bearer {BEARER_TOKEN}"
    }
    
    params = {
        'query': query,
        'granularity': 'hour'  # hour, day, minuteから選択可能
    }
    
    if start_time:
        params['start_time'] = start_time
    if end_time:
        params['end_time'] = end_time
        
    response = requests.get(API_URL, headers=headers, params=params)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"エラー発生: {response.status_code}")
        print(response.json())
        return None

counts = get_recent_tweet_counts("ほげほげ")
print(counts)
結果
{
   "data":[
      {
         "end":"2025-02-05T02:00:00.000Z",
         "start":"2025-02-05T01:53:04.000Z",
         "tweet_count":135
      },
      {
         "end":"2025-02-05T03:00:00.000Z",
         "start":"2025-02-05T02:00:00.000Z",
         "tweet_count":1289
      },
      {
         "end":"2025-02-05T04:00:00.000Z",
         "start":"2025-02-05T03:00:00.000Z",
         "tweet_count":1775
      },
      {
         "end":"2025-02-05T05:00:00.000Z",
         "start":"2025-02-05T04:00:00.000Z",
         "tweet_count":1487
      },
      {
         "end":"2025-02-05T06:00:00.000Z",
         "start":"2025-02-05T05:00:00.000Z",
         "tweet_count":1599
      },
      {
         "end":"2025-02-05T07:00:00.000Z",
         "start":"2025-02-05T06:00:00.000Z",
         "tweet_count":1469
      },
      {
         "end":"2025-02-05T08:00:00.000Z",
         "start":"2025-02-05T07:00:00.000Z",
         "tweet_count":1613
      },
      {
         "end":"2025-02-05T09:00:00.000Z",
         "start":"2025-02-05T08:00:00.000Z",
         "tweet_count":1620
      },
      {
         "end":"2025-02-05T10:00:00.000Z",
         "start":"2025-02-05T09:00:00.000Z",
         "tweet_count":1964
      },
      {
         "end":"2025-02-05T11:00:00.000Z",
         "start":"2025-02-05T10:00:00.000Z",
         "tweet_count":1923
      },
      {
         "end":"2025-02-05T12:00:00.000Z",
         "start":"2025-02-05T11:00:00.000Z",
         "tweet_count":1864
      },
      {
         "end":"2025-02-05T13:00:00.000Z",
         "start":"2025-02-05T12:00:00.000Z",
         "tweet_count":1938
      },
      {
         "end":"2025-02-05T14:00:00.000Z",
         "start":"2025-02-05T13:00:00.000Z",
         "tweet_count":1923
      },
      {
         "end":"2025-02-05T15:00:00.000Z",
         "start":"2025-02-05T14:00:00.000Z",
         "tweet_count":1768
      },
      {
         "end":"2025-02-05T16:00:00.000Z",
         "start":"2025-02-05T15:00:00.000Z",
         "tweet_count":1334
      },
      {
         "end":"2025-02-05T17:00:00.000Z",
         "start":"2025-02-05T16:00:00.000Z",
         "tweet_count":962
      },
      {
         "end":"2025-02-05T18:00:00.000Z",
         "start":"2025-02-05T17:00:00.000Z",
         "tweet_count":555
      },
      {
         "end":"2025-02-05T19:00:00.000Z",
         "start":"2025-02-05T18:00:00.000Z",
         "tweet_count":440
      },
      {
         "end":"2025-02-05T20:00:00.000Z",
         "start":"2025-02-05T19:00:00.000Z",
         "tweet_count":462
      },
      {
         "end":"2025-02-05T21:00:00.000Z",
         "start":"2025-02-05T20:00:00.000Z",
         "tweet_count":735
      },
      {
         "end":"2025-02-05T22:00:00.000Z",
         "start":"2025-02-05T21:00:00.000Z",
         "tweet_count":1271
      },
      {
         "end":"2025-02-05T23:00:00.000Z",
         "start":"2025-02-05T22:00:00.000Z",
         "tweet_count":1902
      },
      {
         "end":"2025-02-06T00:00:00.000Z",
         "start":"2025-02-05T23:00:00.000Z",
         "tweet_count":1858
      },
      {
         "end":"2025-02-06T01:00:00.000Z",
         "start":"2025-02-06T00:00:00.000Z",
         "tweet_count":1623
      },
      {
         "end":"2025-02-06T02:00:00.000Z",
         "start":"2025-02-06T01:00:00.000Z",
         "tweet_count":1415
      },
      {
         "end":"2025-02-06T03:00:00.000Z",
         "start":"2025-02-06T02:00:00.000Z",
         "tweet_count":1286
      },
      {
         "end":"2025-02-06T04:00:00.000Z",
         "start":"2025-02-06T03:00:00.000Z",
         "tweet_count":1682
      },
      {
         "end":"2025-02-06T05:00:00.000Z",
         "start":"2025-02-06T04:00:00.000Z",
         "tweet_count":1108
      },
      {
         "end":"2025-02-06T06:00:00.000Z",
         "start":"2025-02-06T05:00:00.000Z",
         "tweet_count":1046
      },
      {
         "end":"2025-02-06T07:00:00.000Z",
         "start":"2025-02-06T06:00:00.000Z",
         "tweet_count":1029
      },
      {
         "end":"2025-02-06T08:00:00.000Z",
         "start":"2025-02-06T07:00:00.000Z",
         "tweet_count":1096
      },
      {
         "end":"2025-02-06T09:00:00.000Z",
         "start":"2025-02-06T08:00:00.000Z",
         "tweet_count":1058
      },
      {
         "end":"2025-02-06T10:00:00.000Z",
         "start":"2025-02-06T09:00:00.000Z",
         "tweet_count":1128
      },
      {
         "end":"2025-02-06T11:00:00.000Z",
         "start":"2025-02-06T10:00:00.000Z",
         "tweet_count":1145
      },
      {
         "end":"2025-02-06T12:00:00.000Z",
         "start":"2025-02-06T11:00:00.000Z",
         "tweet_count":1286
      },
      {
         "end":"2025-02-06T13:00:00.000Z",
         "start":"2025-02-06T12:00:00.000Z",
         "tweet_count":1282
      },
      {
         "end":"2025-02-06T14:00:00.000Z",
         "start":"2025-02-06T13:00:00.000Z",
         "tweet_count":1103
      },
      {
         "end":"2025-02-06T15:00:00.000Z",
         "start":"2025-02-06T14:00:00.000Z",
         "tweet_count":974
      },
      {
         "end":"2025-02-06T16:00:00.000Z",
         "start":"2025-02-06T15:00:00.000Z",
         "tweet_count":863
      },
      {
         "end":"2025-02-06T17:00:00.000Z",
         "start":"2025-02-06T16:00:00.000Z",
         "tweet_count":551
      },
      {
         "end":"2025-02-06T18:00:00.000Z",
         "start":"2025-02-06T17:00:00.000Z",
         "tweet_count":332
      },
      {
         "end":"2025-02-06T19:00:00.000Z",
         "start":"2025-02-06T18:00:00.000Z",
         "tweet_count":294
      },
      {
         "end":"2025-02-06T20:00:00.000Z",
         "start":"2025-02-06T19:00:00.000Z",
         "tweet_count":288
      },
      {
         "end":"2025-02-06T21:00:00.000Z",
         "start":"2025-02-06T20:00:00.000Z",
         "tweet_count":439
      },
      {
         "end":"2025-02-06T22:00:00.000Z",
         "start":"2025-02-06T21:00:00.000Z",
         "tweet_count":682
      },
      {
         "end":"2025-02-06T23:00:00.000Z",
         "start":"2025-02-06T22:00:00.000Z",
         "tweet_count":1159
      },
      {
         "end":"2025-02-07T00:00:00.000Z",
         "start":"2025-02-06T23:00:00.000Z",
         "tweet_count":1232
      },
      {
         "end":"2025-02-07T01:00:00.000Z",
         "start":"2025-02-07T00:00:00.000Z",
         "tweet_count":971
      },
      {
         "end":"2025-02-07T02:00:00.000Z",
         "start":"2025-02-07T01:00:00.000Z",
         "tweet_count":860
      },
      {
         "end":"2025-02-07T03:00:00.000Z",
         "start":"2025-02-07T02:00:00.000Z",
         "tweet_count":964
      },
      {
         "end":"2025-02-07T04:00:00.000Z",
         "start":"2025-02-07T03:00:00.000Z",
         "tweet_count":1237
      },
      {
         "end":"2025-02-07T05:00:00.000Z",
         "start":"2025-02-07T04:00:00.000Z",
         "tweet_count":826
      },
      {
         "end":"2025-02-07T06:00:00.000Z",
         "start":"2025-02-07T05:00:00.000Z",
         "tweet_count":791
      },
      {
         "end":"2025-02-07T07:00:00.000Z",
         "start":"2025-02-07T06:00:00.000Z",
         "tweet_count":766
      },
      {
         "end":"2025-02-07T08:00:00.000Z",
         "start":"2025-02-07T07:00:00.000Z",
         "tweet_count":654
      },
      {
         "end":"2025-02-07T09:00:00.000Z",
         "start":"2025-02-07T08:00:00.000Z",
         "tweet_count":661
      },
      {
         "end":"2025-02-07T10:00:00.000Z",
         "start":"2025-02-07T09:00:00.000Z",
         "tweet_count":692
      },
      {
         "end":"2025-02-07T11:00:00.000Z",
         "start":"2025-02-07T10:00:00.000Z",
         "tweet_count":773
      },
      {
         "end":"2025-02-07T12:00:00.000Z",
         "start":"2025-02-07T11:00:00.000Z",
         "tweet_count":1072
      },
      {
         "end":"2025-02-07T13:00:00.000Z",
         "start":"2025-02-07T12:00:00.000Z",
         "tweet_count":1054
      },
      {
         "end":"2025-02-07T14:00:00.000Z",
         "start":"2025-02-07T13:00:00.000Z",
         "tweet_count":1021
      },
      {
         "end":"2025-02-07T15:00:00.000Z",
         "start":"2025-02-07T14:00:00.000Z",
         "tweet_count":917
      },
      {
         "end":"2025-02-07T16:00:00.000Z",
         "start":"2025-02-07T15:00:00.000Z",
         "tweet_count":573
      },
      {
         "end":"2025-02-07T17:00:00.000Z",
         "start":"2025-02-07T16:00:00.000Z",
         "tweet_count":386
      },
      {
         "end":"2025-02-07T18:00:00.000Z",
         "start":"2025-02-07T17:00:00.000Z",
         "tweet_count":310
      },
      {
         "end":"2025-02-07T19:00:00.000Z",
         "start":"2025-02-07T18:00:00.000Z",
         "tweet_count":217
      },
      {
         "end":"2025-02-07T20:00:00.000Z",
         "start":"2025-02-07T19:00:00.000Z",
         "tweet_count":179
      },
      {
         "end":"2025-02-07T21:00:00.000Z",
         "start":"2025-02-07T20:00:00.000Z",
         "tweet_count":227
      },
      {
         "end":"2025-02-07T22:00:00.000Z",
         "start":"2025-02-07T21:00:00.000Z",
         "tweet_count":348
      },
      {
         "end":"2025-02-07T23:00:00.000Z",
         "start":"2025-02-07T22:00:00.000Z",
         "tweet_count":486
      },
      {
         "end":"2025-02-08T00:00:00.000Z",
         "start":"2025-02-07T23:00:00.000Z",
         "tweet_count":632
      },
      {
         "end":"2025-02-08T01:00:00.000Z",
         "start":"2025-02-08T00:00:00.000Z",
         "tweet_count":683
      },
      {
         "end":"2025-02-08T02:00:00.000Z",
         "start":"2025-02-08T01:00:00.000Z",
         "tweet_count":581
      },
      {
         "end":"2025-02-08T03:00:00.000Z",
         "start":"2025-02-08T02:00:00.000Z",
         "tweet_count":671
      },
      {
         "end":"2025-02-08T04:00:00.000Z",
         "start":"2025-02-08T03:00:00.000Z",
         "tweet_count":741
      },
      {
         "end":"2025-02-08T05:00:00.000Z",
         "start":"2025-02-08T04:00:00.000Z",
         "tweet_count":703
      },
      {
         "end":"2025-02-08T06:00:00.000Z",
         "start":"2025-02-08T05:00:00.000Z",
         "tweet_count":556
      },
      {
         "end":"2025-02-08T07:00:00.000Z",
         "start":"2025-02-08T06:00:00.000Z",
         "tweet_count":581
      },
      {
         "end":"2025-02-08T08:00:00.000Z",
         "start":"2025-02-08T07:00:00.000Z",
         "tweet_count":769
      },
      {
         "end":"2025-02-08T09:00:00.000Z",
         "start":"2025-02-08T08:00:00.000Z",
         "tweet_count":863
      },
      {
         "end":"2025-02-08T10:00:00.000Z",
         "start":"2025-02-08T09:00:00.000Z",
         "tweet_count":742
      },
      {
         "end":"2025-02-08T11:00:00.000Z",
         "start":"2025-02-08T10:00:00.000Z",
         "tweet_count":746
      },
      {
         "end":"2025-02-08T12:00:00.000Z",
         "start":"2025-02-08T11:00:00.000Z",
         "tweet_count":782
      },
      {
         "end":"2025-02-08T13:00:00.000Z",
         "start":"2025-02-08T12:00:00.000Z",
         "tweet_count":882
      },
      {
         "end":"2025-02-08T14:00:00.000Z",
         "start":"2025-02-08T13:00:00.000Z",
         "tweet_count":702
      },
      {
         "end":"2025-02-08T15:00:00.000Z",
         "start":"2025-02-08T14:00:00.000Z",
         "tweet_count":536
      },
      {
         "end":"2025-02-08T16:00:00.000Z",
         "start":"2025-02-08T15:00:00.000Z",
         "tweet_count":306
      },
      {
         "end":"2025-02-08T17:00:00.000Z",
         "start":"2025-02-08T16:00:00.000Z",
         "tweet_count":234
      },
      {
         "end":"2025-02-08T18:00:00.000Z",
         "start":"2025-02-08T17:00:00.000Z",
         "tweet_count":170
      },
      {
         "end":"2025-02-08T19:00:00.000Z",
         "start":"2025-02-08T18:00:00.000Z",
         "tweet_count":149
      },
      {
         "end":"2025-02-08T20:00:00.000Z",
         "start":"2025-02-08T19:00:00.000Z",
         "tweet_count":129
      },
      {
         "end":"2025-02-08T21:00:00.000Z",
         "start":"2025-02-08T20:00:00.000Z",
         "tweet_count":133
      },
      {
         "end":"2025-02-08T22:00:00.000Z",
         "start":"2025-02-08T21:00:00.000Z",
         "tweet_count":202
      },
      {
         "end":"2025-02-08T23:00:00.000Z",
         "start":"2025-02-08T22:00:00.000Z",
         "tweet_count":288
      },
      {
         "end":"2025-02-09T00:00:00.000Z",
         "start":"2025-02-08T23:00:00.000Z",
         "tweet_count":400
      },
      {
         "end":"2025-02-09T01:00:00.000Z",
         "start":"2025-02-09T00:00:00.000Z",
         "tweet_count":389
      },
      {
         "end":"2025-02-09T02:00:00.000Z",
         "start":"2025-02-09T01:00:00.000Z",
         "tweet_count":391
      },
      {
         "end":"2025-02-09T03:00:00.000Z",
         "start":"2025-02-09T02:00:00.000Z",
         "tweet_count":367
      },
      {
         "end":"2025-02-09T04:00:00.000Z",
         "start":"2025-02-09T03:00:00.000Z",
         "tweet_count":377
      },
      {
         "end":"2025-02-09T05:00:00.000Z",
         "start":"2025-02-09T04:00:00.000Z",
         "tweet_count":306
      },
      {
         "end":"2025-02-09T06:00:00.000Z",
         "start":"2025-02-09T05:00:00.000Z",
         "tweet_count":356
      },
      {
         "end":"2025-02-09T07:00:00.000Z",
         "start":"2025-02-09T06:00:00.000Z",
         "tweet_count":386
      },
      {
         "end":"2025-02-09T08:00:00.000Z",
         "start":"2025-02-09T07:00:00.000Z",
         "tweet_count":394
      },
      {
         "end":"2025-02-09T09:00:00.000Z",
         "start":"2025-02-09T08:00:00.000Z",
         "tweet_count":441
      },
      {
         "end":"2025-02-09T10:00:00.000Z",
         "start":"2025-02-09T09:00:00.000Z",
         "tweet_count":557
      },
      {
         "end":"2025-02-09T11:00:00.000Z",
         "start":"2025-02-09T10:00:00.000Z",
         "tweet_count":680
      },
      {
         "end":"2025-02-09T12:00:00.000Z",
         "start":"2025-02-09T11:00:00.000Z",
         "tweet_count":574
      },
      {
         "end":"2025-02-09T13:00:00.000Z",
         "start":"2025-02-09T12:00:00.000Z",
         "tweet_count":491
      },
      {
         "end":"2025-02-09T14:00:00.000Z",
         "start":"2025-02-09T13:00:00.000Z",
         "tweet_count":425
      },
      {
         "end":"2025-02-09T15:00:00.000Z",
         "start":"2025-02-09T14:00:00.000Z",
         "tweet_count":622
      },
      {
         "end":"2025-02-09T16:00:00.000Z",
         "start":"2025-02-09T15:00:00.000Z",
         "tweet_count":479
      },
      {
         "end":"2025-02-09T17:00:00.000Z",
         "start":"2025-02-09T16:00:00.000Z",
         "tweet_count":271
      },
      {
         "end":"2025-02-09T18:00:00.000Z",
         "start":"2025-02-09T17:00:00.000Z",
         "tweet_count":156
      },
      {
         "end":"2025-02-09T19:00:00.000Z",
         "start":"2025-02-09T18:00:00.000Z",
         "tweet_count":78
      },
      {
         "end":"2025-02-09T20:00:00.000Z",
         "start":"2025-02-09T19:00:00.000Z",
         "tweet_count":91
      },
      {
         "end":"2025-02-09T21:00:00.000Z",
         "start":"2025-02-09T20:00:00.000Z",
         "tweet_count":162
      },
      {
         "end":"2025-02-09T22:00:00.000Z",
         "start":"2025-02-09T21:00:00.000Z",
         "tweet_count":259
      },
      {
         "end":"2025-02-09T23:00:00.000Z",
         "start":"2025-02-09T22:00:00.000Z",
         "tweet_count":380
      },
      {
         "end":"2025-02-10T00:00:00.000Z",
         "start":"2025-02-09T23:00:00.000Z",
         "tweet_count":457
      },
      {
         "end":"2025-02-10T01:00:00.000Z",
         "start":"2025-02-10T00:00:00.000Z",
         "tweet_count":520
      },
      {
         "end":"2025-02-10T02:00:00.000Z",
         "start":"2025-02-10T01:00:00.000Z",
         "tweet_count":504
      },
      {
         "end":"2025-02-10T03:00:00.000Z",
         "start":"2025-02-10T02:00:00.000Z",
         "tweet_count":508
      },
      {
         "end":"2025-02-10T04:00:00.000Z",
         "start":"2025-02-10T03:00:00.000Z",
         "tweet_count":616
      },
      {
         "end":"2025-02-10T05:00:00.000Z",
         "start":"2025-02-10T04:00:00.000Z",
         "tweet_count":420
      },
      {
         "end":"2025-02-10T06:00:00.000Z",
         "start":"2025-02-10T05:00:00.000Z",
         "tweet_count":421
      },
      {
         "end":"2025-02-10T07:00:00.000Z",
         "start":"2025-02-10T06:00:00.000Z",
         "tweet_count":407
      },
      {
         "end":"2025-02-10T08:00:00.000Z",
         "start":"2025-02-10T07:00:00.000Z",
         "tweet_count":437
      },
      {
         "end":"2025-02-10T09:00:00.000Z",
         "start":"2025-02-10T08:00:00.000Z",
         "tweet_count":724
      },
      {
         "end":"2025-02-10T10:00:00.000Z",
         "start":"2025-02-10T09:00:00.000Z",
         "tweet_count":1152
      },
      {
         "end":"2025-02-10T11:00:00.000Z",
         "start":"2025-02-10T10:00:00.000Z",
         "tweet_count":1525
      },
      {
         "end":"2025-02-10T12:00:00.000Z",
         "start":"2025-02-10T11:00:00.000Z",
         "tweet_count":1474
      },
      {
         "end":"2025-02-10T13:00:00.000Z",
         "start":"2025-02-10T12:00:00.000Z",
         "tweet_count":1636
      },
      {
         "end":"2025-02-10T14:00:00.000Z",
         "start":"2025-02-10T13:00:00.000Z",
         "tweet_count":1460
      },
      {
         "end":"2025-02-10T15:00:00.000Z",
         "start":"2025-02-10T14:00:00.000Z",
         "tweet_count":1157
      },
      {
         "end":"2025-02-10T16:00:00.000Z",
         "start":"2025-02-10T15:00:00.000Z",
         "tweet_count":765
      },
      {
         "end":"2025-02-10T17:00:00.000Z",
         "start":"2025-02-10T16:00:00.000Z",
         "tweet_count":530
      },
      {
         "end":"2025-02-10T18:00:00.000Z",
         "start":"2025-02-10T17:00:00.000Z",
         "tweet_count":429
      },
      {
         "end":"2025-02-10T19:00:00.000Z",
         "start":"2025-02-10T18:00:00.000Z",
         "tweet_count":344
      },
      {
         "end":"2025-02-10T20:00:00.000Z",
         "start":"2025-02-10T19:00:00.000Z",
         "tweet_count":298
      },
      {
         "end":"2025-02-10T21:00:00.000Z",
         "start":"2025-02-10T20:00:00.000Z",
         "tweet_count":415
      },
      {
         "end":"2025-02-10T22:00:00.000Z",
         "start":"2025-02-10T21:00:00.000Z",
         "tweet_count":654
      },
      {
         "end":"2025-02-10T23:00:00.000Z",
         "start":"2025-02-10T22:00:00.000Z",
         "tweet_count":965
      },
      {
         "end":"2025-02-11T00:00:00.000Z",
         "start":"2025-02-10T23:00:00.000Z",
         "tweet_count":1048
      },
      {
         "end":"2025-02-11T01:00:00.000Z",
         "start":"2025-02-11T00:00:00.000Z",
         "tweet_count":1275
      },
      {
         "end":"2025-02-11T02:00:00.000Z",
         "start":"2025-02-11T01:00:00.000Z",
         "tweet_count":1100
      },
      {
         "end":"2025-02-11T03:00:00.000Z",
         "start":"2025-02-11T02:00:00.000Z",
         "tweet_count":1105
      },
      {
         "end":"2025-02-11T04:00:00.000Z",
         "start":"2025-02-11T03:00:00.000Z",
         "tweet_count":1168
      },
      {
         "end":"2025-02-11T05:00:00.000Z",
         "start":"2025-02-11T04:00:00.000Z",
         "tweet_count":1165
      },
      {
         "end":"2025-02-11T06:00:00.000Z",
         "start":"2025-02-11T05:00:00.000Z",
         "tweet_count":1243
      },
      {
         "end":"2025-02-11T07:00:00.000Z",
         "start":"2025-02-11T06:00:00.000Z",
         "tweet_count":1260
      },
      {
         "end":"2025-02-11T08:00:00.000Z",
         "start":"2025-02-11T07:00:00.000Z",
         "tweet_count":1230
      },
      {
         "end":"2025-02-11T09:00:00.000Z",
         "start":"2025-02-11T08:00:00.000Z",
         "tweet_count":1436
      },
      {
         "end":"2025-02-11T10:00:00.000Z",
         "start":"2025-02-11T09:00:00.000Z",
         "tweet_count":1387
      },
      {
         "end":"2025-02-11T11:00:00.000Z",
         "start":"2025-02-11T10:00:00.000Z",
         "tweet_count":1572
      },
      {
         "end":"2025-02-11T12:00:00.000Z",
         "start":"2025-02-11T11:00:00.000Z",
         "tweet_count":1283
      },
      {
         "end":"2025-02-11T13:00:00.000Z",
         "start":"2025-02-11T12:00:00.000Z",
         "tweet_count":1303
      },
      {
         "end":"2025-02-11T14:00:00.000Z",
         "start":"2025-02-11T13:00:00.000Z",
         "tweet_count":1188
      },
      {
         "end":"2025-02-11T15:00:00.000Z",
         "start":"2025-02-11T14:00:00.000Z",
         "tweet_count":1151
      },
      {
         "end":"2025-02-11T16:00:00.000Z",
         "start":"2025-02-11T15:00:00.000Z",
         "tweet_count":819
      },
      {
         "end":"2025-02-11T17:00:00.000Z",
         "start":"2025-02-11T16:00:00.000Z",
         "tweet_count":486
      },
      {
         "end":"2025-02-11T18:00:00.000Z",
         "start":"2025-02-11T17:00:00.000Z",
         "tweet_count":292
      },
      {
         "end":"2025-02-11T19:00:00.000Z",
         "start":"2025-02-11T18:00:00.000Z",
         "tweet_count":231
      },
      {
         "end":"2025-02-11T20:00:00.000Z",
         "start":"2025-02-11T19:00:00.000Z",
         "tweet_count":224
      },
      {
         "end":"2025-02-11T21:00:00.000Z",
         "start":"2025-02-11T20:00:00.000Z",
         "tweet_count":322
      },
      {
         "end":"2025-02-11T22:00:00.000Z",
         "start":"2025-02-11T21:00:00.000Z",
         "tweet_count":536
      },
      {
         "end":"2025-02-11T23:00:00.000Z",
         "start":"2025-02-11T22:00:00.000Z",
         "tweet_count":689
      },
      {
         "end":"2025-02-12T00:00:00.000Z",
         "start":"2025-02-11T23:00:00.000Z",
         "tweet_count":736
      },
      {
         "end":"2025-02-12T01:00:00.000Z",
         "start":"2025-02-12T00:00:00.000Z",
         "tweet_count":699
      },
      {
         "end":"2025-02-12T01:53:04.000Z",
         "start":"2025-02-12T01:00:00.000Z",
         "tweet_count":664
      }
   ],
   "meta":{
      "total_tweet_count":137215
   }
}

指定した条件でサーチする

多分だいたいみんなこれをやりたいんじゃないかと思うんだが、GET /2/tweets/search/recentつまり7日間でよければFreeプランでも使える。しかも15分に1回。今なら一応。それ以外はプロ以外お断りだ。

個人でも関心が高い話題についての情報収集くらいには使えるかも?流行言葉は制約的に厳しいと思うけど。

import requests

# Bearer Token認証を使用
BEARER_TOKEN = "xxxx"

def search_recent_tweets(query, max_results=10):
    """
    過去7日間のツイートを検索
    
    params:
    - query: 検索クエリ
    - max_results: 取得する最大ツイート数(10-100)
    """
    API_URL = "https://api.twitter.com/2/tweets/search/recent"
    
    headers = {
        "Authorization": f"Bearer {BEARER_TOKEN}"
    }
    
    params = {
        'query': query,
        'max_results': max_results,
        'tweet.fields': 'created_at,author_id,public_metrics'
    }
    
    response = requests.get(API_URL, headers=headers, params=params)
    return response.json()

tweets = search_recent_tweets("手取りを増やす")
print(tweets)

# そのほかの使用例
# 画像付きの「猫」ツイートを検索
#tweets = search_recent_tweets("猫 has:images -is:retweet")

# 「Python」を含む日本語ツイート
#tweets = search_recent_tweets("Python lang:ja")

# 特定ユーザーの返信を除外したツイート
#tweets = search_recent_tweets("from:username -is:reply")
結果
{
   "data":[
      {
         "public_metrics":{
            "retweet_count":11,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"2929390645",
         "edit_history_tweet_ids":[
            "1889497408155095532"
         ],
         "created_at":"2025-02-12T02:11:01.000Z",
         "id":"1889497408155095532",
         "text":"RT @oef4raF1ZW3D4WI: 国民民主「国民の手取りを増やす」\n維新「高校無償化」\n\n自民「企業に補助金。今まで以上に」\n\n少なくとも自民は無いわな。国民に益なし\n\nだいたい過去数十年失敗し続けてるのに、同じことをまだやろうってんだから反省も自浄作用もないわけだ。自…"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"999818589673668608",
         "edit_history_tweet_ids":[
            "1889496996140163153"
         ],
         "created_at":"2025-02-12T02:09:23.000Z",
         "id":"1889496996140163153",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"129119756",
         "edit_history_tweet_ids":[
            "1889496791734943868"
         ],
         "created_at":"2025-02-12T02:08:34.000Z",
         "id":"1889496791734943868",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":32,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"855312372818264064",
         "edit_history_tweet_ids":[
            "1889496781559656931"
         ],
         "created_at":"2025-02-12T02:08:32.000Z",
         "id":"1889496781559656931",
         "text":"RT @shinjukuacc: 国民民主党が羨ましい?\n他の政党も「手取りを増やす」を掲げて選挙を戦えば良いだけの話では?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"1516766731095580677",
         "edit_history_tweet_ids":[
            "1889496743823433959"
         ],
         "created_at":"2025-02-12T02:08:23.000Z",
         "id":"1889496743823433959",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"808024200",
         "edit_history_tweet_ids":[
            "1889496377258025115"
         ],
         "created_at":"2025-02-12T02:06:56.000Z",
         "id":"1889496377258025115",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"1709033536626593792",
         "edit_history_tweet_ids":[
            "1889496311738802543"
         ],
         "created_at":"2025-02-12T02:06:40.000Z",
         "id":"1889496311738802543",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"265293455",
         "edit_history_tweet_ids":[
            "1889496046285496570"
         ],
         "created_at":"2025-02-12T02:05:37.000Z",
         "id":"1889496046285496570",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"1307860410",
         "edit_history_tweet_ids":[
            "1889496035309048008"
         ],
         "created_at":"2025-02-12T02:05:34.000Z",
         "id":"1889496035309048008",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      },
      {
         "public_metrics":{
            "retweet_count":682,
            "reply_count":0,
            "like_count":0,
            "quote_count":0,
            "bookmark_count":0,
            "impression_count":0
         },
         "author_id":"1140189324614361088",
         "edit_history_tweet_ids":[
            "1889495481585377443"
         ],
         "created_at":"2025-02-12T02:03:22.000Z",
         "id":"1889495481585377443",
         "text":"RT @kirishima_O3: 国民民主党って「手取りを増やす」が公約なんだよね?\nだったら103万の壁にこだわるより、社会保険料増税に反対することの方が優先度高いんじゃないの?"
      }
   ],
   "meta":{
      "newest_id":"1889497408155095532",
      "oldest_id":"1889495481585377443",
      "result_count":10,
      "next_token":"b26v89c19zqg8o3frr9u7r3w21gbm3z1eldrda7d2ug71"
   }
}

この記事をいいなと思っていただけた方、よければ高評価・チャンネル登録……はないので、コメント・SNSでシェア・ブックマーク、RSSフィード登録を、よろしくお願い致します。

コメント

コメントする

目次