見出し画像

【NodeRed】ローコード(LowCode)でTwitterBotを作ろう!

どうも、スウェーデンでITエンジニアをしているあめぞう(@amezousan)です。

今回は下記の記事で紹介した「Node Red」を使ってTwitterBotを作ってみます。

今回の目標は「特定のキーワードに自動返信する」ボットの作成です。

NodeRedでHelloWorld

まだ実際に使ったことがないので軽く「HelloWorld」を表示できるまでの手順を取ります。

■テスト環境
・Vagrant: https://github.com/amezousan/vagrant-dev
・nodejs v12.16.2
・git version 2.26.0
・Twitter API取得済み (Qiita - Twitter API 登録方法)

1. 早速「NodeRed」のGithubレポジトリからファイルをコピーします。

$ git clone https://github.com/node-red/node-red.git
$ cd node-red/
✅ここに筆者がハマった!(Vagrantを使ってない人はスキップしてOKです)
Vagrantには何故かnpm installに失敗するバグが存在します。回避策として、任意のnode_modulesフォルダを作成し、npm installする際のフォルダ上にリンクを作成します。

(例)
node-red$ mkdir -p ~/symlinks/node-red/node_modules
node-red$ ln -s ~/symlinks/node-red/node_modules node_modules

参考: https://github.com/npm/npm/issues/7308#issuecomment-209463993

2. Node-Redに必要なパッケージをインストール

node-red$ npm install

3. コードをビルド

node-red$ npm run build

4. コードを実行

node-red$ npm start
...
18 Apr 21:22:49 - [info] Server now running at http://127.0.0.1:1880/

5. npm start時に表示されたURLにアクセスします。例ではhttp://127.0.0.1:1880/

6. injectとdebugを使って簡単なフローを作ります。

画像1

7. 右上の「デプロイ」をクリックした後はinjectの左にある□をクリックします。そうすると虫マークのデバッグ画面にてHelloWorldが表示されます。

画像2

次は実際にtwitter botを作ってみましょう。

NodeRedでTwitter拡張機能を試す

NodeRedでは拡張機能がついているのでそれを利用します。

※1 - 今回使う機能には注釈があり、Twitterが仕様変更した場合動かなくなります。100%の動作が保証されていないのであくまで検証用と考えてください。
※2 - Twitter APIの申請は既に終えているものとします。詳しい手順はQiita - Twitter API 登録方法が参考になります。

1. READMEの手順通りに下記の通りインストールをし、再度node-redフォルダ上で「npm start」コマンドを実行します。

$ cd ~/.node-red
~/.node-red$ npm install node-red-node-twitter
~/.node-red$ cd <your-path-to>/node-red/
node-red$ npm start

2. ソーシャル部分に「twitter in」(ツイッター読み込み)と「twitter out」があるのを確認します。

画像3

3. 今回の検索条件は「@minbunseki」ユーザに対して「#test」タグを付けた全ての公開ツイートを読み込む、です。

画像4

4. 実際の呟きがこちら

画像5

5. NodeRed上で検知したデータがこちら。

画像6

githubのコードを確認すると「twitter in」は1分間ごとにTwitterの情報を取得します。以下のようなフローをNodeRedで作成してみます。

画像7

NodeRed上で検知したデータを元に次のように上記フローを実装していきます。

その前に、ただ適当にIF文の条件を書くのではなく、なるべく自分で理解しやすい形で書きましょう。例えば、1分以内のツイートを判別する方法として次の2パターンがあります。

画像9

パターン1「ツイート時刻が「前回実行時刻」及び「現時刻」の範囲内であれば正しい、処理を継続
パターン2「ツイート時刻が「前回時刻」または「現時刻」の範囲外であれば間違い、処理を終了

この2つをIF文に直すと、

// コード例: パターン1

if (ツイート時刻 >= 前回実行時刻 && ツイート時刻 <= 現時刻) {
  // 処理を継続
}else{
  // 処理をしない
}

パターン2は実際のところ、前回実行時刻よりもツイート時刻が古ければ処理しなければ良い、と考えることもできるので、

// コード例: パターン2

if (ツイート時刻 <= 前回実行時刻) {
  // 処理をしない
}

// 処理を継続

IF文が少ない数であればどちらの条件でも問題ありませんが、100個のIF文があるとどうでしょうか。それに合わせたIF - ELSEを書くと非常に長くなってしまいます。

このようにIF文を「否定条件」から考えていく手法がコードを短く、かつわかりやすくしてくれる場合があります。

このことを頭に踏まえた上で次のような条件式を作成します。

const obj_tweet = msg.tweet;

// 1. Check if it's tweeted 1 min ago
if(obj_tweet.timestamp_ms <= last_runtime) {
   node.warn("Skipping: Tweet is too old")
   return false
}

// 2. Check if it's tweeted by myself
if(obj_tweet.user.id === my_user_id) {
   node.warn("Skipping: Tweet is done by myself")
   return false
}

// 3. Check if it's tweeted in the specific thread
if(obj_tweet.in_reply_to_status_id !== my_thread_id) {
   node.warn("Skipping: Tweet is not in a specific thread")
   return false
}

//処理を継続

■「1分以内のツイート」
この条件を入れておくことで、例えば15分置きに実行して15分間分の情報を取得する際などに役立ちます。(Twitter APIの時間の絞り込みは面倒なので…)

・条件「前回実行時より古いツイートは処理しない」

■「自分のツイートでない」
自分の返信に自分で答えないようにします。

・条件「ツイートが自分のものであれば処理しない」

■「特定ツイートのスレ内か」
全ての返信に対応するのではなく、特定のスレッド内のみでTwitterBotに返信させます。

・条件「ツイートが特定スレッド内でなければ処理しない」

✅ここがポイント!
全てを否定条件にすると「条件に適さないものだけ処理しない」と非常にシンプルに考えることができます。

■「ツイートをくれたユーザに対して呟く」
オプション無しの「twitter out」は単に呟くだけなので情報に記載されている通りTwitterのドキュメントに従って「msg.params」を指定してツイートさせます。

画像8

NodeRedでTwitterBotを作る

先程確認した情報を元に下記のようなフローを作成しました。

画像10

✅ここに筆者がハマった!
Vagrantの時刻が現時刻とずれている場合「twitter in」で401エラー(認証失敗)が発生します。その場合はVagrantを再起動させるか、時刻をリセットすると治ります。

(例) $ sudo timedatectl set-ntp off && sudo timedatectl set-ntp on && date

参考: https://github.com/sixohsix/twitter/issues/285

■fetchRecentTweet

画像11

■createPayloadWithTweet

画像13

/***
* Common Variables
*/
const now_timestamp = Date.now();
const last_runtime  = flow.get('last_runtime') || now_timestamp;
const my_user_id    = 1230923398211043328;
const my_thread_id  = 1252106804215058433;
const obj_tweet     = msg.tweet;
// Set the last_runtime
flow.set('last_runtime', now_timestamp);
/***
* Main Flow
*/
// 1. Check if it's tweeted 1 min ago
if(obj_tweet.timestamp_ms <= last_runtime) {
   node.warn("Skipping: Tweet is too old")
   return false
}
// 2. Check if it's tweeted by myself
if(obj_tweet.user.id === my_user_id) {
   node.warn("Skipping: Tweet is done by myself")
   return false
}
// 3. Check if it's tweeted in the specific thread
if(obj_tweet.in_reply_to_status_id !== my_thread_id) {
   node.warn("Skipping: Tweet is not in a specific thread")
   return false
}
return {
   "payload": `Hello @${obj_tweet.user.name} at ${obj_tweet.created_at}`,
   "params": {"in_reply_to_status_id": obj_tweet.id_str, "auto_populate_reply_metadata": true}
}

自身のユーザIDは「TwitterのIDチェッカー」のような機能を使い調べます。

特定のスレッドIDは「Twitter埋め込み」ページへアクセスした時に表示される数字をコピーします。

画像13

■replyToUser

画像14

■msg

画像15

✅ここに筆者がハマった!
自動リプライする際には必ず毎回異なるメッセージになるように注意してください。同じメッセージが連続投稿できないようにTwitter側で制限されています。

ツイート例

画像16

画像17

Node Red側のデバッグ出力例

画像18

これでTwitterBotが完成しました!

最後に

いかがでしたでしょうか。ここまで読んだ方はお気づきかもしれませんが、twitter botを作成するに当たって僕はコードらしいコードを書いていません。

書いたといえばIF文と、どこにどんなことをツイートするかを決めた程度。これがローコード(LowCode)の力で、後で別の機能に変えたい場合でも、少ないコードで変更可能です。

今後もこういった少ない労力で「やりたいこと」を実現させ、空いた時間で本来すべきことに時間をもっと注ぐ形のビジネスが増えることが予想されます。

プログラミングだけがエンジニアの実力ではなく、こういったアイディアを実現できる「発想力」も必要な要素です。

今回紹介したNodeRedは無料で使えるオープンソースのプロジェクトです。皆さんもぜひ1度使ってみてはいかがでしょうか。

この記事が気に入ったら、サポートをしてみませんか?気軽にクリエイターを支援できます。

スキ、ありがとうございます!
3
【クラウド未経験から海外でクラウドエンジニア】高校、大学受験失敗、大学中退で挫折の連続 / 🇯🇵でセキュリティ4年→🇸🇪でクラウドエンジニア3年目 / ゼロからスウェーデン語を学びC1レベルに到達 / 言語習得 x エンジニア x 海外文化の情報をシェア!

この記事が入っているマガジン

週刊あめぞうさん
週刊あめぞうさん
  • 7本

本記事では主にビジネステック、海外エンジニアの体験系の記事を扱うマガジンです。例としては「Low-Codeの実例紹介・検証、TwitterBotの作り方、気になった技術の検証」や「クラウド技術の紹介、海外エンジニアの日常、資格取得への道」など。

コメント (1)
はじめまして。8月からストックホルム大学院に留学する予定です。ただ現在の状況にとても不安です。いろいろな情報をおしえていただけたら幸いでございます。宜しくお願いいたします。 https://www.facebook.com/yamanao7083
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。