LoginSignup
3
4

Twitter API:動かなくなったTwitter botを復活させる

Last updated at Posted at 2023-08-03

はじめに

Twitter APIを使用してTwitter botを作成していたのですが、APIの仕様変更により、2023年6月頃のツイートを最後に実行されなくなってしまいました。
bot復活までの対処についてまとめます。

botは次のような仕組みで実装していました。

  1. GAS(Google Apps Script)をトリガーにPHPのスクリプトをキック
  2. PHPからTwitterOAuthというライブラリを使用してTwitter APIを操作
  3. ツイートのポストやファボ、ツイートを取得する

サーバー環境は次のとおりです。

改修前のアプリのバージョンです。

  • PHP:7系
  • TwitterOAuth:0.7.2(おそらく)
  • Twitter API:v1.1

改修後のアプリのバージョンです。

  • PHP:8系
  • TwitterOAuth:6.6.6
  • Twitter API:v1.1とv2の併用

2017年に作成したきりほとんど改修もしていなかったためTwitter API以外の改修範囲も多く、また、開発環境と本番環境で手順が異なり戸惑ったりと、bot復活までにかなり苦労しました。
結局はTwitter APIの無料プランでは使用できるエンドポイント(Twitter APIにアクセスするためのアドレス)がかなり限定されており、完全に復活させることはできませんでした。

おおまかな手順

bot復活までのおおまかな手順です。

  1. Twitter APIのバージョン変更
  2. プロジェクトとアプリの設定
  3. PHPのライブラリ「TwitterOAuth」の最新化
  4. PHPのバージョンを8に変更
  5. PHPのスクリプトの改修

原因の究明

ログの確認

スクリプト実行時のログを確認したところ、次のメッセージが出ていました。

object(stdClass)#17 (1) { ["errors"]=> array(1) { [0]=> object(stdClass)#11 (2) { ["code"]=> int(32) ["message"]=> string(27) "Could not authenticate you." } } }

「あなたを認証できませんでした」とのことです。

認証情報の確認

Twitterのデベロッパーサイトで認証情報を確認しました。

Twitter APIのバージョンアップ

The v1.1 APIs have been deprecated and your app is no longer able to access those v1.1 APIs. Please create a new application using one of our v2 Free, Basic or Pro plans today!

「v1.1のAPIは廃止されアクセスできなくなりました。今すぐv2の無料プラン、ベーシックプラン、プロプランのいずれかを使用して新しいアプリケーションを作成してください!」とのことです。

対処

Twitter APIのバージョン変更

まずはTwitter APIのバージョンをv1.1からv2に変更します。

  1. Twitter DevelopersのTwitter API v2のページから無料プランへのダウングレードのボタンをクリックする
    Downgrade

  2. バージョンが変更される
    successfully

バージョン変更後、スクリプトを実行したところ、エラーログが出ました。

object(stdClass)#8 (1) { ["errors"]=> array(1) { [0]=> object(stdClass)#3 (2) { ["message"]=> string(272) "You currently have access to a subset of Twitter API v2 endpoints and limited v1.1 endpoints (e.g. media post, oauth) only. If you need access to this endpoint, you may need a different access level. You can learn more here: https://developer.twitter.com/en/portal/product" ["code"]=> int(453) } } }

「Twitter APIのエンドポイントへアクセスするには、別のアクセスレベルが必要です。詳しくはこちらをご覧ください」とのことです。

詳しくをこちらのURLへアクセスし、v2エンドポイントの詳細を確認します。

v2 endpoints

Migrate

In order to use v2 endpoints, you will need the following things:

A developer account
A developer App created within a Project
Keys and tokens from that Project’s developer App

「v2エンドポイントを使用するには、次のものが必要」とのことです。

  • 開発者アカウント
  • プロジェクト内に作成された開発者アプリ
  • プロジェクトの開発者アプリのキーとトークン

If you would like to start using v2 endpoints, you will need to attach an App to a Project and use the credentials from that App when making requests to v2 endpoints.

また、「v2エンドポイントの使用を開始する場合は、Appをプロジェクトにアタッチし、v2エンドポイントへのリクエスト時にそのAppの認証情報を使用する必要があります」とのことです。

プロジェクトとアプリの設定

Twitter API v2を利用するにはプロジェクトが必要とのことなので、プロジェクトを作成し、アプリをひもづけます。

  1. Twitter DevelopersのDashboardページから「Create Project」をクリックする
    Create Project

  2. プロジェクト名を入力する
    Name Your Project

  3. 使用用途は「ボット作成」を選択する
    Which best describes you?

  4. プロジェクトの説明を記入する
    Describe your new Project

  5. 「既存のアプリを追加」を選択する
    Add an existing App

  6. ひもづけるアプリを選択する
    Add your App

  7. ひもづけ完了
    Confirmation

PHPのライブラリ「TwitterOAuth」の最新化

Twitter APIを操作するためのライブラリ「TwitterOAuth」がTwitter APIのv1.1にしか対応していなさそうだったので、最新版をインストールします。

インストールには、PHPのパッケージライブラリ管理ツールである「Composer」が必要です。
公式サイトのIntroduction - Composerのローカルインストールの手順にしたがってまずは「Composer」をインストールします。

Composerのインストール

  1. Composerのサイトから、phpではじまる4行のスクリプトをコピーし、インストールしたいパスでコマンドを実行する

    php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
    php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
    php composer-setup.php
    php -r "unlink('composer-setup.php');"
    

    ※サイトに記載されているスクリプトは更新されるようなので、サイトから最新のスクリプトをコピーしてください

コマンドを実行した階層に「composer.phar」が作成されていればインストールは完了です。

TwitterOAuthのインストール

「Composer」と同じ階層に「TwitterOAuth」をインストールします。

  1. カレントディレクトリはそのままで、次のコマンドを実行します。

    php composer.phar require abraham/twitteroauth
    
  2. もし「The zip extension and unzip/7z commands are both missing, skipping.」エラーが出た場合は、zipコマンドをインストールする

    sudo yum install php-zip
    sudo yum install -y zip unzip
    
  3. Apacheを再起動して、再度twitteroauthをインストールする

    sudo service httpd restart
    php composer.phar require abraham/twitteroauth
    

「composer.json」「composer.lock」ファイルと、「vendor」フォルダーの中にabraham/twitteroauthのファイル群が作成されていればインストールは完了です。

PHPライブラリ読み込みパスの変更

指定したパスにvendor\abraham\twitteroauthフォルダーが作成されました。
既存のフォルダー構成と異なってしまったので、パスを指定している箇所を変更します。

  • 変更前

     require "twitteroauth/autoload.php";
     require "twitteroauth/src/TwitterOAuth.php";
     use Abraham\TwitterOAuth\TwitterOAuth;
    
  • 変更後

     require "vendor/autoload.php";
     use Abraham\TwitterOAuth\TwitterOAuth;
    

「TwitterOAuth.php」は読み込まなくてもよくなったようです。
自分はこれを読み込んでいたせいで、なぜか開発環境では実行できるのに本番環境では500エラーになる現象がおき、3日間理由がわからず苦しみました…。

変更後、スクリプトを実行したところ、エラーログが出ました。

Composer detected issues in your platform:

Your Composer dependencies require a PHP version ">= 8.0.0". You are running 7.1.33.

どうやら最新の「TwitterOAuth」はPHP8にしか対応していないそうです。
調べるとPHP7のサポートは終了しているようで、PHP8を利用したほうがよさそうでした。

PHPのバージョンを8に変更

開発環境

Vagrantで構築した仮想環境のCentOS7.5にPHP8をインストールします。

  1. 現在のPHPのバージョンを確認する

    php -v
    

    実行結果

    PHP 7.1.33 (cli) (built: Nov 15 2021 10:04:41) ( NTS )
    Copyright (c) 1997-2018 The PHP Group
    Zend Engine v3.1.0, Copyright (c) 1998-2018 Zend Technologies
    	with Xdebug v2.9.8, Copyright (c) 2002-2020, by Derick Rethans
    
  2. インストール済みのPHP関連パッケージを確認する(念のためメモしておく)

    yum list installed php*
    

    実行結果

    Loaded plugins: fastestmirror
    Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
    Loading mirror speeds from cached hostfile
    * base: ftp.riken.jp
    * epel: ftp.riken.jp
    * extras: ftp.riken.jp
    * remi-safe: ftp.riken.jp
    * updates: ftp.riken.jp
    Installed Packages
    php.x86_64                                     7.1.33-19.el7.remi                            @remi-php71
    php-cli.x86_64                                 7.1.33-19.el7.remi                            @remi-php71
    php-common.x86_64                              7.1.33-19.el7.remi                            @remi-php71
    php-devel.x86_64                               7.1.33-19.el7.remi                            @remi-php71
    php-gd.x86_64                                  7.1.33-19.el7.remi                            @remi-php71
    php-json.x86_64                                7.1.33-19.el7.remi                            @remi-php71
    php-mbstring.x86_64                            7.1.33-19.el7.remi                            @remi-php71
    php-pdo.x86_64                                 7.1.33-19.el7.remi                            @remi-php71
    php-pecl-xdebug.x86_64                         2.9.8-1.el7.remi.7.1                          @remi-php71
    php-xml.x86_64                                 7.1.33-19.el7.remi                            @remi-php71
    
  3. PHPを削除する

    sudo yum remove "php*"
    
  4. epel-releaseのアップデートをする

    sudo yum update epel-release
    
  5. remiのリポジトリを検索し、remi-php81.repoがあるか確認する

    ll /etc/yum.repos.d/ | grep remi-
    

    ない場合は、次のコマンドでリポジトリをインストールする

    yum install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
    
  6. PHP8.1をインストールする

    sudo yum -y install --enablerepo=remi,remi-php81 php php-cli php-common php-devel php-mbstring php-pdo php-gd php-xml php-mcrypts php-pecl-xdebug
    
  7. PHPのバージョンを確認し、PHP8.1になっていれば完了

    php -v
    
  8. Apacheを再起動する

    sudo service httpd restart
    

本番環境

本番環境である「さくらのレンタルサーバ」のPHPのバージョンを変更します。
こちらの手順を参考にPHP8.1.20へ変更しました。
PHPのバージョンを変更したい | さくらのサポート情報

PHPのバージョン

PHPのスクリプトの改修

PHPのバージョンを8.1にしてもスクリプトは実行されず、調べるとTwitter API v2になったことにより使えなくなったエンドポイントあるようです。
PHPのスクリプトをTwitter API v2用に書き換える必要がありました。

エンドポイントの移行表はこちらにまとめられています。
Twitter API endpoint map | Docs | Twitter Developer Platform

ざっくり次のようにPHPを書き換えました。

文字のみのツイート

  • 変更前

     //引数で渡したメッセージを呟く
     function tweet($message){
     	// ツイッターにアクセスする
     	$connection = new TwitterOAuth(
     		CONSUMER_KEY,
     		CONSUMER_SECRET,
     		ACCESS_TOKEN,
     		ACCESS_TOKEN_SECRET
     	);
    
     	//つぶやく
     	$result = $connection->post("statuses/update", array("status" => $message));
    
     	//返ってきた内容を確認してみる
     	return var_dump($result);
     }
    
  • 変更後

     //引数で渡したメッセージを呟く
     function tweet($message){
     	// ツイッターにアクセスする
     	$connection = new TwitterOAuth(
     		CONSUMER_KEY,
     		CONSUMER_SECRET,
     		ACCESS_TOKEN,
     		ACCESS_TOKEN_SECRET
     	);
     	//v2の動作にする
     	$connection->setApiVersion('2');
    
     	//つぶやく
     	$result = $connection->post("tweets", ["text" => $message], true);
    
     	//返ってきた内容を確認してみる
     	return var_dump($result);
     }
    

v1.1ではpostはできなくなってしまったようです。
なので、明示的にAPIのバージョン2を指定してあげて、postをv2の書き方に変えてあげる必要がありました。

画像付きのツイート

  • 変更前

     //引数で渡した画像とメッセージを呟く
     function tweetMedia($message, $mediaURL){
     	// ツイッターにアクセスする
     	$connection = new TwitterOAuth(
     		CONSUMER_KEY,
     		CONSUMER_SECRET,
     		ACCESS_TOKEN,
     		ACCESS_TOKEN_SECRET
     	);
    
     	//画像をアップロードし、画像のIDを取得する
     	$imageId = $connection->upload("media/upload", array("media" => "$mediaURL"));
    
     	//つぶやく
     	$result = $connection->post("statuses/update", array("status" => $message, 'media_ids' => implode(',', [$imageId->media_id_string])));
    
     	//返ってきた内容を確認してみる
     	return var_dump($result);
     }
    
  • 変更後

     //引数で渡した画像とメッセージを呟く
     function tweetMedia($message, $mediaURL){
     	// ツイッターにアクセスする
     	$connection = new TwitterOAuth(
     		CONSUMER_KEY,
     		CONSUMER_SECRET,
     		ACCESS_TOKEN,
     		ACCESS_TOKEN_SECRET
     	);
     	//v1.1の動作にする(Twitter API v2は画像のアップロードがまだ未対応のため)
     	$connection->setApiVersion('1.1');
    
     	//URLから画像コンテンツを取得する
     	$contents = file_get_contents($mediaURL);
    
     	//MIME_TYPEを取得する
     	$finfo = finfo_open(FILEINFO_MIME_TYPE);
     	$mime_type = finfo_buffer($finfo, $contents);
     	finfo_close($finfo);
    
     	//拡張子を設定する
     	if(substr($mime_type,0,6) == 'image/'){
     		$extension = substr($mime_type,6);
     	}else{
     		//画像じゃない場合は文字のみツイートする
     		tweet($message);
     		Exit;
     	}
    
     	//画像を保存するパスを指定する
     	$mediaPath = dirname(__FILE__) . "/image/TMP_image." . $extension;
    
     	print var_dump($mediaPath);
    
     	//画像をサーバーに保存する(上書き保存)
     	file_put_contents($mediaPath, $contents);
    
     	//画像をアップロードし、画像のIDを取得する
     	$imageId = $connection->upload("media/upload", ["media" => $mediaPath]);
    
     	//これ以降はv2の動作にする
     	$connection->setApiVersion('2');
    
     	$parameters = [
     		'text' => $message,
     		'media' => [
     			'media_ids' => [$imageId->media_id_string],
     		]
     	];
    
     	//つぶやく
     	$result = $connection->post('tweets', $parameters, true);
    
     	//返ってきた内容を確認してみる
     	return var_dump($result);
     }
    

こちらはちょっとややこしいです。
画像のuploadはv2ではまだ未実装のため、upload処理はv1.1で行い、ツイートのpostはv2で行います。

さらにこのスクリプトでは、画像はファイルそのものをuploadするのではなく、Google Driveに格納している画像のURLを指定しています。
昔はURLの指定でuploadできたのですが、最新版ではファイルパスを指定しないとuploadできなくなっていました。
そのため一度サーバーに画像ファイルを保存してからuploadしています。ファイルを保存するときに拡張子を判定しています。

いいね、リプライなど

こちらについては、Twitter API v2の無料プランでは実行できなくなりました。
無料プランで使用できるエンドポイントは、次の3種類だけです。

  • POST /2/tweets(ツイートのポスト)
  • DELETE /2/tweets/:id(ツイートの削除)
  • GET /2/users/me(自分のユーザー情報の取得)

プランによって使用できるエンドポイントは、Twitter DevelopersのTwitter API v2のページに記載されています。
Twitter API v2

Docsに現在掲載されているアクセスレベル(プラン)についてのドキュメントは古いものも混在していそうです。

こちら「Essential」「Elevated」…といったアクセスレベルは、申し込みページに遷移してもページが存在せず廃止された情報と思われます。
What's new with Twitter API v2 | Docs | Twitter Developer Platform
old - Access levels

おそらく最新の情報はこちらです。
Twitter API Documentation | Docs | Twitter Developer Platform
New - Access level

情報がいろいろと混在していますが、2023/08/03現在では、Twitter APIのアクセスレベルとエンドポイントについてはこのページの情報が正しそうです。

Getting Started with the Twitter API | Docs | Twitter Developer Platform
Twitter API access levels and versions

このページによると、無料プランで使用できるエンドポイントは次のとおりです。

  • Twitter API v2:Tweet作成のみ
  • Twitter API v1.1:メディアのuploadなど限定されたもののみ

よって、v2でツイートの検索ができないからといって、かわりにv1.1で行うこともできないようです。

さいごに

ここ数か月でのTwitter(正しくはXですね…)の動きは目まぐるしく、最新の情報を探し出すのがかなり大変でした。
botを復活させるのに結局5日ほどかかってしまい、めちゃ大変でした。

出典

3
4
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
3
4