見出し画像

1時間でできるTwitterBOT作成

こんにちは。なんだかんだで投稿が3ケ月ぶりになってしまいました。
先日友達からこんなLINEが、、、

なんだこいつ

ってことで今回はめっちゃ優しく簡単にBOT作成やっていきたいと思います。



1.Google Apps Scriptプロジェクトの作成

今回もGoogle Apps Script(通称GAS)を使っていきます。
サーバー無しで簡単に動くからいいんですよコレ。

まずは下記にアクセスして
右上の「新しいプロジェクト」を押下して作成

そしたらこんな感じのものができたと思う

初期画面

Google Apps Scriptはお分かりの通りGoogleが提供しているプログラミング言語です。ベースはJavaScriptです。
最新のECMAScriptも対応しています。ということはclassも使えるということですね。

とりあえずJavaScriptを実行してみたいと思います。
最初のは消してこれをコピペでもいいので記入してみてください。

function hello() {
  const obj = "Hello World!!"
  console.log(obj)
}

意味
hello関数を作って
変数objにHello World!!を入れる
コンソールにobjを出力

プロジェクトはCtrl + Sで保存できるよ!!

GASは関数毎に別々に実行することができます。

実行する関数を確認して実行をクリック!!

そうすると…

実行できました!!!!


2.Twitter Developersに登録する。

※この操作はアカウントの2段階認証必須です。
電話番号を登録する必要があります。

そして本題、TwitterBOTを作っていきたいと思います。
まず、チャットボットとは

チャットボット(Chatbot)とは、リアルタイムで短文のやり取りを行うことを意味する「チャット」と、一定の作業を自動化するロボットを意味する「ボット」を合わせた名称で、簡単にいうとチャットでの質問に自動で返答するプログラムやアプリケーションのことです。

https://boxil.jp「チャットボットとは?AI自動会話の仕組みやメリット・活用事例・選び方」

らしい。

とりあえず、Twitter上でメンションしてくれた人に「巻き込んでますよ」と返信してくれるBOTを作っていきたいと思います。


右上にあるDeveloper Portal に移動します。もしかしたらログイン必要かもしれません。

黄色い線のところ!!

そしたら色々出てくると思う

とりあえずJapanで。
今回の目的はBOT作成なのでMaking a botにします。
その後プライバシーポリシーかなんか出てくると思うので
そのまま進みます。

メール認証しましょう


私の場合は英語での利用申請が必要でした(˘・_・˘)Twitter~
もし聞かれたらDeepLなどつかって翻訳しながら書いていきましょう。

App nameはお好みでどうぞ
決めたらGet keysでアクセストークンを発行してもらいます。

名前を決める


そしたらこんな画面が出てきたと思います。
API KeyとAPI Key Secretをどこかにメモっておきましょう
(付箋アプリおすすめ)

終わったらDashboardを押す

とりあえずTwitterアプリの作成は完了しました!

少しコーヒーでも飲んで休憩しましょう。
私も3時間ぐらいぶっ通しでやってるので休んできます。

ダンボール猫


3. コードを書く

さて、それではGASに戻ります。

+マークからスクリプトを新規追加します。
名前はなんでもいいですが、今回は、「TwitterClient」にします。

スクリプトを追加する

TwitterClient.gs

/**
* belltreeSzkさんからお借りしました。ありがとうございます。
* GitHub: https://github.com/belltreeSzk/TwitterClient
* HomePage: https://belltree.life/
*/

/**
* Twitterの認証に関わる処理をまとめたクラス
* 認証、API実行など
*/
class TwitterClient {
  /**
  * コンストラクタ
  */
  constructor(consumerKey, consumerSecret, clientName) {
    this.consumerKey = consumerKey;
    this.consumerSecret = consumerSecret;
    this.scriptId = ScriptApp.getScriptId();
    this.clientId = this.scriptId + clientName;
    this.oauth = this._getOAuthService();
  }

  /**
  * 認証開始
  */
  authorize() {
    if (this.oauth.hasAccess()) {
      Logger.log('既に認証されています');
    } else {
      let authorizationUrl = this.oauth.authorize();
      Logger.log('以下のURLからログインを行ってください');
      Logger.log(authorizationUrl);
    }
  }

  /**
  * authorize() の後にTwitterでログインした際に実行される処理
  * @return {TextOutput}
  */
  authCallback(request) {
    const isAuthorized = this.oauth.handleCallback(request);
    const mimeType = ContentService.MimeType.JSON;
    const result = {
      message: isAuthorized ? '認証に成功しました。このタブは閉じてください。' : '認証に失敗しました。',
    }
    return ContentService.createTextOutput(JSON.stringify(result)).setMimeType(mimeType);
  }

  /**
  * Twitterで作ったアプリに登録するための callbackUrl を取得する処理
  * @return {string} 
  */
  getCallbackUrl() {
    return OAuth1.getCallbackUrl(this.scriptId);
  }

  /**
  * 認証を解除する
  */
  reset() {
    this.oauth.reset();
    Logger.log('認証を解除しました');
  }

  /** 
  * POSTのAPIを実行する
  */
  postRequest(apiUrl, paramsObject) {
    if (this.oauth.hasAccess()) {
      const response = this.oauth.fetch(apiUrl, {
        'method': 'post',
        'muteHttpExceptions': true,
        'contentType': 'application/json',
        'payload': JSON.stringify(paramsObject)
      });
      Logger.log('実行しました: POST ' + apiUrl);
      const result = JSON.parse(response)
      if (Object.keys(result).some((elem) => elem === 'errors')) console.error(result) //APIのエラー処理
      return result
    } else {
      Logger.log('認証されていません');
      throw Error('認証されていません');
    }
  }

  /** 
  * GETのAPIを実行する
  */
  getRequest(apiUrl, paramsObject) {
    let paramsStr = '';
    for (var key in paramsObject) {
      // URLに日本語や記号を付けると上手く検索できないことがあるので#も変換する encodeURIComponent をする
      paramsStr += key + '=' + encodeURIComponent(paramsObject[key]) + '&'
    }
    if (paramsStr !== '') {
      // &が余計に付いているので削除しておく
      paramsStr = paramsStr.slice(0, -1);
    }

    if (this.oauth.hasAccess()) {
      let fetchUrl = ''
      if (paramsStr == '') {
        fetchUrl = apiUrl
      } else {
        fetchUrl = apiUrl + '?' + paramsStr
      }
      const response = this.oauth.fetch(fetchUrl);
      Logger.log('実行しました: GET ' + fetchUrl);
      const result = JSON.parse(response)
      return result
    } else {
      Logger.log('認証されていません');
      throw Error('認証されていません');
    }
  }

  /** 
  * OAuthのインスタンスを作る
  */
  _getOAuthService() {
    return OAuth1.createService(this.clientId)
      .setAccessTokenUrl('https://api.twitter.com/oauth/access_token')
      .setRequestTokenUrl('https://api.twitter.com/oauth/request_token')
      .setAuthorizationUrl('https://api.twitter.com/oauth/authorize')
      .setConsumerKey(this.consumerKey)
      .setConsumerSecret(this.consumerSecret)
      .setCallbackFunction('authCallback')
      .setPropertyStore(PropertiesService.getUserProperties());
  }
}

/**
* TwitterClientクラスを外部スクリプトから呼び出すための関数
* @return {TwitterClient}
*/
function getInstance(consumerKey, consumerSecret, clientName = '') {
  const client = new TwitterClient(consumerKey, consumerSecret, clientName);
  clientList[client.oauth.serviceName_] = client
  return client
}

const clientList = {}
/**
* TwitterClientクラスのインスタンスの一覧を取得
* @return {Array}
*/
function getClientList () {
  return clientList
}


次にコード.gsに書き込んでいきます。
元の文は消して下のコードをコピペ。

コード.gs

'use strict';

//ここにキーとシークレットキーを入れる
const consumerKey = 'CONSUMER_KEY'
const consumerSecret = 'CONSUMER_SECRET'

const client = getInstance(consumerKey,consumerSecret)

/**
 * ①Twitterで作ったアプリに登録するための callbackUrl を取得する
 */
function getCallbackUrl() {
  Logger.log('以下のURLをTwitterアプリのCallbackURLに登録');
  Logger.log(client.getCallbackUrl());
}

/**
 * ②認証を実行する
 */
function authorize() {
  client.authorize()
}


/**
 * 認証をリセット
 */
function reset() {
  client.reset()
}


/**
 * authorizeでTwitterでの認証後に実行される処理
 */
function authCallback(request) {
  return client.authCallback(request)
}


コード.gs

//ここにキーとシークレットキーを入れる
const consumerKey = 'CONSUMER_KEY'
const consumerSecret = 'CONSUMER_SECRET'

ここに先ほど控えたキーとシークレットキーを入れてください。

認証などはBelltreeさんのコードをお借りしました。



4. GASにライブラリを追加する

Twitter APIの認証はOAuthなのでGAS用のOAuthのライブラリを追加します。
ファイルを追加したときのようにライブラリと書いてある横の+を押します。
Oauth1のライブラリ スクリプトID  ↓↓↓↓

1CXDCY5sqT9ph64fFwSzVtXnbjpSfWdRymafDrtIZ7Z_hwysTY7IIhi7s

検索します。

バージョンは現在最新の18、そして追加


5. アプリにコールバックを設定する。

※TwitterClient.gsが一番上に配置するようにしてください‼
点々で変更できます。
上から読み込まれるんですね

ファイルを上に移動する

では、保存したのを確認して
コード.gsのgetCallbackUrlの関数を実行します。

関数を指定して実行をクリック

おそらく「承認が必要です」と出ると思います。承認しちゃってください。

危なくないはずなので大丈夫です!!

実行するとURLが出てくると思うのでコピーしておく。

行き来しちゃってすいません >︿<
このURLをTwitterアプリのコールバックに登録します。

作成したプロジェクトに移動

下のほうにあるUser authentication settings
Set up
をクリック

黄色いところ

やる事

  1. OAuth 1.0a をオンにする。

  2. App permissionの項目でRead and Writeにする。

  3. コールバックURLを入れる。

  4. 必須のWebsite URLはなんでもいい…

WebsiteURL: 自分はTwitterのプロフにした

終わったらSaveを押す。
権限を変更しますか→Yes



6. OAuth認証する

authorizeを実行してTwitter APIの認証をします。

実行!!
URLにアクセスしてログイン
連携アプリを認証を押下
{"message":"認証に成功しました。このタブは閉じてください。"}

このメッセージが表示されたらOKです。

次章でツイートしてみます!!



7. APIでツイートしてみる

では、Twitter APIをつかってツイートしてみます。
やっとこの時が…ドドド
この関数を追加して実行してみてください。

コード.gs

function tweetTest() {
  //お好きなメッセージ
  const message = "Twitter APIからのツイート"

  const params = {
    text: message
  }
  const result = client.postRequest('https://api.twitter.com/2/tweets',params) //ツイートのエンドポイント: https://api.twitter.com/2/tweets
  console.log(result)
}
できた!!!!

もしできないのであれば、エラーか何かしらログに書かれているはず

ドキュメントはここ



8. ボットをつくる

後はもうGASでコーディングしていくだけです簡単ですね。

reply.gsというファイルを作ります。

reply.gs    (コピペOK)

//自身のアカウント情報
const me = client.getRequest('https://api.twitter.com/2/users/me').data

/**
 * メンションされたツイートに返信する(1分おきにトリガー実行)
 */
function lookUpMension() {

  const params = {
    max_results: 10,//ツイートを取得する数
  }
  const newestId = ScriptProperties.getProperty('newestTweetId')
  if (newestId !== null) {
    params['since_id'] = newestId
  }
  const result = client.getRequest(`https://api.twitter.com/2/users/${me.id}/mentions`, params)
  console.log(result)
  if (result.meta.result_count !== 0) {
    ScriptProperties.setProperty('newestTweetId', result.meta.newest_id)
    reply() //返信する関数
  }

  function reply() {
    result.data.forEach(tweet => {
      console.log(tweet)
      const param = {
        //パラメーター
        text: '巻き込んでますよ。',
        reply: { in_reply_to_tweet_id: tweet.id } //返信パラメータ
      }
      const result = client.postRequest('https://api.twitter.com/2/tweets', param) //データをポストする
      console.log(result) //ログにresultを表示
    })
  }
}

function deleteScript() {
  ScriptProperties.deleteProperty('newestTweetId')
}

lookUpMension関数を実行すると.....

できてるはずです
あとはいつでも返信できるように5分おきに実行できるようにしていきます。

右にある目覚まし時計アイコン → トリガーを追加

トリガーを実行
この設定にする

こんな感じの設定にしていきます。

やっと完成です


結構長くなってしまって最後のほう雑になってしまいましたが一応完成です。8000文字以上書いたぜ。過去最高かも

個人的にはもっとコードの解説とかしたかったのですが、、
もし何か質問などあればTwitterのDMで受け付けます。
https://twitter.com/wakiwakkii

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?