記事一覧に戻る

Twitter API V2に移行したぞ!

2023.05.01: 旧APIの廃止状況と、4月末に発生したAPIアクセスの停止処分について追記しました。

はじめに

2023年2月2日、Twitter DevがTwitter APIの無料プランを廃止する、といきなり発表しました。

twitter-api-announcement

このツイートは、API利用者に大きな衝撃をもって迎えられました。このページを見られている方も、きっとその中の1人でしょう。上の画像はそのときのツイートですが、1.1億回も表示されています笑。どこかの世界的大富豪のツイートみたいですね。

その後、新しいプランの情報がなかなか出てこなかったり、無料利用期間が延長されたり、様々な混乱がありましたが、、、2023年3月30日、ついに新APIローンチのツイートが投稿されました。

twitter-new-api-announcement

新しいAPIのバージョン(Twitter API v2)ではFree Tier(無料)、Basic Tier(月額$100)、Enterprise Tier(企業向け:月額制)の3プランの提供となることが決まりました。ややこしいですが、旧APIにもEssential v2といった、「v2」が付く名前のプランがあります。こちらは最初のツイートのとおり最終的には廃止になります。

気になる旧APIの利用期間については、同日に以下のとおり言及されています。

twitter-api-deprecation-announcement

「30日でdeprecate」というところが、「非推奨になる」のか、「廃止になるのか」、解釈が分かれるところでしょうか。普通なら前者かと思いますが、最近の動きを考えると、あまり楽観的に捉えないほうが良いかもしれません。

仮に良い方に捉えても、結局は非推奨です。「next 30 days」と期限も切られているので、早めに移行しておいたほうが良いでしょう。

※ 30日経過後の最新の状況は旧APIの廃止状況(2023.05.01追記)に記載しています。

前置きが長くなりましたが、そんな訳でTwitter API v2に移行しました。旧APIの時からですが、TwitterのAPIはドキュメントが迷路みたいで探しにくいですし、日本語ページが少なかったり、英語ページでも何か英語が変だったり、、、お世辞にも分かりやすいとは言えませんので、参考にしていただければと思います。

この記事の目的

Twitter API v1.1からv2(Free Tier)に移行した時の私の手順と、行ったプログラムの修正内容を共有します。移行に悩んでいる方や、移行がうまく出来ない方の参考になれば幸いです。

前提

現在利用しているAPIのバージョン

  • Standard v1.1

移行するAPIのバージョン

  • Twitter API v2(Free Tier)

対象エンドポイント(ツイート投稿)

  • https://api.twitter.com/1.1/statuses/update.json

利用している言語

  • Python3.9.6

利用しているライブラリ

認証方法

  • OAuth1.0

従来のOAuth1.0に加えて、OAuth2.0も可能になっていますが、1.0を利用します。

前提知識

requestsの簡単な使い方(GET,POSTの実行ができる)を知っている方を念頭に記載しています。

Twitter API v2(Free Tier)について

Free TierのAccess Level

ドキュメントでは、Twitter API v2(Free Tier)のアクセス・レベルは以下のようになっています。

free-tier-access-level

これだけだと、解釈が分かれそうな部分もありますが、私は以下のように理解しています。

  • ツイート投稿、メディア・アップロードのエンドポイントへの低レート・リミット・アクセス
  • アプリ単位で1か月1,500ツイート
  • 1アプリのみ
  • 「Twitterでログイン」利用可能
  • 無料

実質利用できるのが、ツイート投稿、メディア・アップロード、「Twitterでログイン」に限られてしまうのが、大きな変更点でしょうか。

「低レート・リミット」はAPIのアクセス制限が緩い、という程度に捉えています。「1か月1,500ツイート」はツイート投稿のみなのか、メディアアップロードも含むのかはまだ確認できていません。ただ、メディア・アップロードが無制限にできるとは考えにくいですし、含めて1,500の制限なのかな、と思っています。

アクセス・トークン等について

ドキュメントには以下の記載がありました。

token-elevation

「2021年11月15日以前に開発者アカウントの承認がされている場合、Elevated Accessに自動的に更新されます。これは、まだv1.1エンドポイントへのアクセスも可能で、全てのユーザアクセス・トークンは有効であるという意味です。v2エンドポイントの利用をしたければ、Projectにアプリを登録し、そのアプリの認証情報を使ってください」

私は2022年11月15日より前に承認されていて、もともとProjectにアプリを登録していたためか(記憶はありませんが、、、)、アクセス・トークン等はそのまま使えました。

参考までに、私の開発者ポータル画面のOverviewページです。v1.1 ACCESSとV2 ACCESSのマークが確認出来ます。調べたところ、プロジェクトに追加されていないアプリは、下部の「Standalone Apps」のほうに表示されるようです。推測になってしまいますが、v2 ACCESSのマークがついていて、画面上部にアプリが表示されていれば(Standalone Appsに表示されていなければ)、認証情報はそのまま利用できると思います。

dev-portal

新旧比較

ツイート投稿用のエンドポイントを前提にしています。

  • v1.1(旧): https://api.twitter.com/1.1/statuses/update.json
  • v2(新): https://api.twitter.com/2/tweets

エンドポイント比較

ツイート投稿用のエンドポイントの新旧比較です。公式ドキュメントからの引用です。

compare-endpoint

エンドポイントのパスが「/2/tweets」に変わっています。後はレート・リミットに、15分で200ツイートの制限が追加されています。

APIドキュメント比較

大きな変更点として、今までクエリ・パラメタで指定していたものが、全てBODYに指定することになっています。また、ツイート本文は旧ではstatusで指定していましたが、新ではtextになっており、キー名の変更も行われています。

さらに、アップロード画像を付けるときには、{media_ids:"id1,id2,id3"}のようにコンマ区切りで指定が必要でしたが、新では{media:{media_ids:[id1,id2,id3]}}のように、リストで指定するように変更されています。キーの指定もさりげなくmedia_idsから、media.media_idsに変更されています。

ツイート投稿

例えば、Hello,Worldと投稿する場合、新旧では以下のような違いが出ます。

v1.1(旧API)の場合

from requests_oauthlib import OAuth1Session as session

URL = "https://api.twitter.com/1.1/statuses/update.json"

# 認証情報は取得したものを設定する
req = session("API_KEY", "API_SECRET",
        "ACCESS_TOKEN", "ACCESS_SECRET")

params = {"status":"Hello,World"}

# クエリ・パラメタに指定してPOST
req.post(URL, params=params)

v2(新API)の場合

from requests_oauthlib import OAuth1Session as session

URL = "https://api.twitter.com/2/tweets"

# 認証情報は取得したものを設定する
req = session("API_KEY", "API_SECRET",
        "ACCESS_TOKEN", "ACCESS_SECRET")

body = {"text":"Hello,World"}

req.post(URL,json=body)

旧ではクエリ・パラメータに"status"で投稿メッセージを設定していますが、新ではリクエストのBODY部に"text"で設定しています。これだけなので、ツイート投稿だけなら変更も簡単ですね。

*json=*で指定すると、JSON文字列への変換と、ヘッダにContent-Type:application/jsonを自動で追加してくれるので便利です。

メディア付き投稿

現時点では、v2ではメディア・アップロードは出来ません。COMING SOONとのことなので、近いうちに公開されると思いますが、今はV1.1のhttps://upload.twitter.com/1.1/media/upload.jsonを使う必要あります。

画像付きツイート投稿の流れは以下の通りです。

  1. APIで画像をアップロードし、media_idを取得
  2. 1で取得したidをmedia_idsに指定して、ツイート投稿のAPIを実行

1.の部分がV1.1のままと言っても、2.のツイート投稿の部分でmedia_idsの指定の仕方が変更されているので、画像付きツイートをするには プログラムを修正する必要があります。

v1.1(旧API)の場合

旧ではmedia_idsはクエリ・パラメタで、"id1,id2,id3"のようにcsv形式で記述することになっていました。

# media_upload関数は /1.1/media/upload.jsonのエンドポイントを実行し、
# media_idを"id1,id2,id3"のcsv形式で返す関数とします。
media_ids = media_upload(*img_paths)

params = {
  "status": txt,
    "media_ids":media_ids
}

# reqはtwitter認証情報で初期化したoOAuth1Sessionとします。
res = req.post(URL, params=params)

v2(新API)の場合

新では、上述のとおりリクエストのBODYに設定します。また、[id1,id2,id3]のようにリストで指定するよう変更されています。

そして、キー名も以下のように変更されています。

{
    "media":{
        "media_ids":["id1","id2"]
    }
}

V1.1の例をそのまま書き換えると、以下のようになります。

# media_upload関数は /1.1/media/upload.jsonのエンドポイントを実行し、
# media_idを"id1,id2,id3"のcsv形式で返す関数とします。
media_ids = media_upload(*img_paths)

params = {
    # v2はstatusではなく、text
  "text": txt,
    "media":{
        # 文字列"id1,id2,.."をリスト["id1","id2",...]に変換
        "media_ids":media_ids.split(",")
    }
}

# reqはtwitter認証情報で初期化したoOAuth1Session 
# クエリパラメタでなく、json形式でbodyに設定
res = req.post(URL_TWEET, json=body)
  • media_idsは文字列(csv)でなくリスト
  • media_idsでなく、media.media_idsの形で設定
  • クエリパラメタでなく、BODYにjson形式で設定

これを押さえれば大丈夫です。

参考:Github

パッケージというほどではありませんが、V2でツイートするパッケージををGithubにあげました。V1.1ですが、画像投稿も出来ます。よかったら使ってみてください。

旧APIの廃止状況(2023.05.01追記)

2023年3月29日にTwitter Devが「30日後に旧APIはdeprecateにする」とツイートしてから、約30日が経過しました。5月1日時点の状況を追記します。

4月21日に以下のツイートが投下されています。

Today, we are deprecating our Premium v1.1 API, including Premium Search and Account Activity API.

On 3/29 we announced that deprecations across our legacy Twitter API access tiers would be completed by 4/29. Unwinding Premium is one step closer to full deprecation of those legacy tiers.

Premium v1.1は既に廃止され、残りの旧APIは4/29までに廃止されるとのことです。また、deprecateは、「非推奨」になるのではなく、「廃止」であることが明確になりました。

なお、現時点ではv2ではメディア・アップロードはCOMING SOONのままでリリースされていません。そして、Standard v1.1 APIのメディア・アップロードは、廃止されておらずまだ使えている状況です。

今後の取扱いについては、明確な情報は公式からは発信されていません。v2でリリースされるまで、このままにしておくつもりなのですかね。。。

APIアクセスの停止処分(2023.05.01追記)

4月上旬から新APIを利用していますが、4月29日から401エラーが出てしまい、APIが使えなくなってしまいました。Twitterを見ると、同じように401エラーが出ている人が多数いたようです。

エラーの内容

アプリから出力しているため、少し見た目は異なるかもしれません。

{
  "title": "Unauthorized",
  "type": "about:blank",
  "status": 401,
  "detail": "Unauthorized"
}

開発画面

Twitterの開発者画面を確認すると、アプリがsuspended(停止)されていました。

api-violation

原因と対策

v2(新API)のfree tierから、有料のbasic tierに自動昇格していたのが原因でした。利用料の支払いがないため、401エラーが出ていたようです。

開発者画面のサイドメニューの「Products」→「Twitter API v2」をクリックし、「Downgrade」ボタンを押したら、suspendedの表示がなくなりました。そこからはエラーも出なくなり、自動投稿が可能になりました!

downgrade

もし同じエラーになっている方がいたら、開発者画面を確認してみてください。

最後に

プログラムの修正を伴うような変更もあるものの、対応自体はそこまで難しくありませんでした。それより、ドキュメントを探すのに苦労した気がします。

どちらかというと、無料プランのツイート数制限(1500ツイート/月)や、「書き込みのみ」といった制限のほうが影響が大きかったのかな、と思います。幸い、私は画像付き投稿を1日数回する程度だったので、ほとんど新API移行の影響はありませんでした。

まぁ、メディア・アップロードはこれからリリースされるので、また修正が必要になりますが。。。

Elon MuskさんがTwitter社を買収してから、変更・変化が多いですね。サードパーティ製のアプリが禁止になったり、大きな打撃を受けた人もいると思います。

とはいえ、Twitter社の経営状況はあまり良くないようで、一連の改革も今後利益を出していくための戦略なのかと思います。ベストなやり方なのかは分かりませんが、、、。ただ、今回無料プランが残ってくれたことは個人的には嬉しく思っています。

今後もまわりの反応を見ながらTwitter社もいろいろ手を打ってくると思いますので、将来的により良い方向に改修がされていくことを期待しています。

記事一覧に戻る