Twitterボット作成のサービスなんて沢山あったり、今更ボットを一から作る人なんているのかなと思いつつ・・・今更ながら書いています。Twitterボットを作ると言うと、自分の場合Javaでの実装になります。じゃぁ作る時はTwitter4jを使って!などと即座に考えてしまいますが、実はそれらの利用はTwitterボットを作る上での一部にすぎません。
そのあたりのAPIを利用するという面では非常に多くの方がブログに書いていますが、その運用やサービスの構築に関しては書いているところが無いと思います。そこで自分が運用しているボットやボットフレームをサンプルに書いてみたいと思います。なのでこの文章を見て即座にTwitterボットが作れるようになるわけではありません。ボットプログラムのサンプルを探している人にこの文章は何の参考にもなりません。あと話の前提として、Twitterボット、それらを管理するWeb画面などがあるとします。
ボットを作るうえで必用なもの
自分の仕事にも通じるのですが、システム構築をする場合、そのシステム(ユーザーが見る画面や帳票など、この場合はボットがTwitter上で検索やらツイートやらするという意味です)以外にも必用なものがあります。それは帳票を夜間に作るバッチであったり、運用者が日々見る管理画面であったり、管理者がログインしたあと、管理者しか見れない画面であったり、開発環境と運用環境を分けるとかいった、色々な仕組みです。単にPCのプロセスとしてササーっとTwitterボットを作る以外はこれらバックヤード的なものが、どうしても必用になってきます。
まとめるとこんな機能です。
-
- 本番用IDと開発用ID
- 本番のIDで開発時の「ああああ」などをつぶやく人はいませんと思いますが、
- プロパティファイル
- いわゆる開発環境と本番環境の差分を吸収してあげます。サーバー名称とかTwitterIDとか・・・
- デバッグモードと本番モード
- 結構開発中は「つぶやいてほしくない」ものです。なので、Twitter4jを何らかの形でラップします。
- ログイン機能
- いわゆるユーザー/管理者がログインして設定を行うための機能です。
- バックヤード的なもの
- システムの開始、停止、無視ユーザーの管理などプログラムでいちいち修正したいたらキリがないので。
- イベント管理
- 何時につぶやく、いつまでつぶやくといったイベントを編集したり追加したりする機能です。
- 設計書
- 設計書大事です!キリッ!
- 本番用IDと開発用ID
開発用/本番用を分ける何か
ボットを運用する上で避けて通れないのがボットを作成する際と、運用中のボットの切り分けです。TwitterIDは本番用と開発用の二つを作るとして、プログラム自体で本番と開発の環境を分ける仕組みが必要です。まさか本番用のボットが定期ツイートしながら開発時に「あああああ」とか「てすと」とかつぶやく人はいないと思いますので。
まず、Twitterで本番用と開発用のIDを作ります。これは単にTwitter上の操作なので割愛します。実際に動くプログラムはプロパティファイルやデータベースに保存したボットのIDを基に動かすようにします。
まぁ、この辺はボット作成サービスを使用していない限り基本ですね。ただ、自分が一番初めに作成したボットは開発用と本番用のIDを分けていませんでした。そのときは後述するようにTwitterにつぶやく部分だけを開発時はログ出力で確認していたため、あまり気にならなかったのですが。面倒臭がらずにIDは2つ作りましょう。Javaで作る場合はまず以下の物が必用になります。(自分の場合です)
本番と開発版のプロパティファイル
環境を切り替えるのに使用します。自分の場合は、今現在、開発モードか本番モードか、あとボットの設定用にTwitterへログインしたりしますので、そのログイン方法(実際にoAuthを利用してログインするのか、ダミーの仕組みを使うのか)に使います。
開発時と運用時のマシンやデータベースが異なればそれだけで接続するサーバー、DBを切り替える値が必要です。また、後述するように開発時には迂回させていた機能を本番では使えるようにするといった使い方をします。
本番と開発版のcontext.xml
これはデータベースを使う場合です。違いはDBサーバーのマシン名、DB名、ユーザー、パスワード、コネクション数・・・(おい、殆どやんけ!)が開発と本番とで違う(ハズ)ですので分けます。
デバッグモードと本番モード
Twitterのボット(もそうですが、Twitterアプリ全般に言えますが)を作る際、開発中にTwitter4Jを使って実際につぶやいてしまうと非常にまずい場合もります。例えば公式リツイートとか、@付きメンションとか・・・開発の「ああああ」とかしかつぶやかない変なIDから飛ばされたら嫌ですよね。機能としてはつぶやいて欲しいですが実際つぶやいて欲しくない場合です。よくシステム構築でも開発モードとリリースモードを分けることがありますが、これも同じです。(って分けないシステムを見たことない・・・)
これも実際にはプロパティファイルやDBの値で切り分けます。デバッグモードではTwitter4jの必用な機能以外は迂回して実際につぶやいたりしない。ログにのみ出力する、本番モードでは実際にTwitter4jを使用してつぶやいたりする。と言った具合です。実装はとくに難しくありません。Twitter4jのユーティリティを作成してモードにより切り替えるだけです。
例えば以下のような感じです。Twitterオブジェクトはインターフェースで提供されるので、本筋であれば、開発用のダミー実装を作って開発者(自分ww)に意識させないシームレスな実装が良いですが、自分はこのようにしています。(作るの自分なんでww)※下記はあくまでイメージです。実際にはもっと面倒なことやっていたりします。
public class TwUtil { private TwUtil(){ // ユーティリティなので生成させない } // Twitterにつぶやく public static void updateStatus(Twitter tw, String text){ Logger logger = ... try{ if( /* デバッグモードの場合と条件 */){ // つぶやいたフリをする Logger.getLogger().debug("update_status " + tw.getUer().getScreenname() + " - " + text); } else{ // 実際につぶやく tw.updateStatus(text); } } catch(Exception e){ // ここでは握りつぶします。 logger.error("エラーだ、えらいこっちゃ"); // 管理IDにDMを送るなど } } ・・・その他ユーティリティメソッド }
コードイメージです。ちょっと謎言語になってます。
ログイン機能
TwitterボットやTwitterのサービスを作るうえで、気になるのがユーザーのログインシーケンスです。ユーザーと言うのはそのシステムにログインする管理者的な役割の人、この文章を読んでいる人であったり、そのサービス自身を使用する人です。あるボットAを作って、そのAの設定を変更するなら、Aでログインして設定を変更するよう作った方が自然です。
Twitter4JのoAuthを使えばTwitter上でのログインは比較的簡単に実装が可能です。でも開発中や、ネットが使えない状況などで、実際にoAuthが利用できない場合などは、そこを迂回させる必要がでてきます。自分は今のスマフォを買うまではモバイルなどのネット環境を持っていませんでしたので、まずスタンドアローンでも開発が進められる仕組みが必要でした。
これは前述のプロパティファイルで切り替えますが、「ログイン」を押されたら、デバッグモードならどのユーザーでログインするかの選択画面に飛ぶ、リリースモードならTwitterのoAuth認証に飛ぶなどです。自分の作るものの場合、切り替える判断は2重になっています。基本はデバッグモード(開発時)はTwitterのoAuthには飛びません。但し、開発時でもoAuth認証が必要な場合も出てくるので、プロパティファイルのtwitterログイン方法が”Twitterで”(※これは実際の値ではありません)となっていたら、実際にoAuthで認証に飛ぶようにします。
是非とも作りたいバックヤード的なもの
TwitterBOTを運用しているとうれしいww粘着なユーザーや検索するなら検索ワードの変更、最近だとひたすらRTするキーワードをツイートしてRTさせるアソビなどがあったりと結構いろんな事があったりします。なので、とりあえずボットを停止する、無視するユーザを設定する、検索するワードを変える、と言ったボットの動作を変える機能が必要になってきます。管理者だけが使える機能ですね。自分がいつも作るのは次のような機能です。
システムの起動/停止ボタン。
何か問題があったらとりあえずボットを停止したいです。そんなとき使ったりします。お昼休みに何か問題が起こっても会社のPCからTwitter見れない・・・と言う会社の方は多いと思います。とりあえずスマフォからログインして停止させといて夜にゆっくり解析する・・・そんな使い方ですね。
ツイートの一覧及び、削除など簡易Twitterクライアント機能
RTしてくれたユーザー一覧、Favしてくれたユーザー一覧、それらを見たり、返事をしたりする機能ですね。特にFavしてくれた人やRTしてくれた人は一覧になっていると楽です。あと@メンションなんかは一覧が無いと見過ごしてしまいがちになりますので、一覧から返事する・・・そんな使い方です。
無視ユーザー一覧と追加削除機能。(ユーザー管理画面でもよい)
例えば粘着ユーザーは無視するに限ります。そんなユーザーは家に帰ったらPG直してデプロイではなく気が向いたらスマフォで小指を立てながらログインして「無視」ってできるとスマートです。ついでにメガネをクイっと上げるともっといいかもしれませんね。
検索キーワード/RTキーワードのメンテナンス機能
結構大事です。キーワードの微妙な変更でいい具合になる場合もあります。検索してリツイートするボットであれば検索するキーワード、その後検索した結果は正規表現でとかいったパターンで、正規表現を直すってことにも使えます。
ボットIDの設定機能/管理者IDの設定機能
これは先に書いた開発用と本番用に分けるというのに続くのですが、管理画面からボットのIDを設定できるようにしておきます。永続先は別にプロパティだろうがDBだろうがどこでもいいです。お好きなように。
イベント管理
ボットがいつつぶやくかと言ったことをメンテナンスします。つぶやく、RTするといった事をイベントして取り扱うのですね。あとは何時間おきとか、週の何曜日だけとかはDBの項目次第でしょう。始めは1時間おきに検索していたが、考えてみたら5時間おきぐらいでも良かったから直すとか、つぶやく文章を増やすと言ったことです。
これはプロパティファイルなどのファイル管理でも良いですが、そうすると運用中のサーバーを変更するだの(こうなると開発環境と本番環境のファイルが違うくなるミスが・・・)ファイルを変更してwar作ってデプロイしなおすとか面倒です。自分はDBにテーブルを作って管理しています。最小限の項目はこんなもんでしょうか。(あくまでイメージです)
イメージとしては、EVENT_TBLテーブルのstartの時間が来たら(1分おきに時間が過ぎたレコードを検索する)seq_noに対応した各イベントを起動します。例えば、EVENT_TWEETテーブルであれば、条件(cond1,cond2)に合致するときはtweetで示す文字列をツイートします。例えばツイートする文字を可変にしたいときは、TWEETS_GROUPテーブルにつぶやくリストを登録しておき、その中からランダムにツイートします。こんな具合です。
設計書大事
正直プログラムだけじゃ追っていけません。僕の記憶は鶏並みですので。でも設計書ってアレですよ。要件をまとめたもの、簡単なクラスの構造、画面イメージ、処理概念図、データベースの項目集、その項目の値を作る前や作っているときに忘れないように書いている「メモ」決して作る前にプログラム部分を日本語で延々と書いているわけではありません。あ、エクセル方眼紙ですがww
これらを作っている最中に纏めながら保存していきます。なので作った後は不要なページなんか出てきます。もうソース見たほうが早いですしね。不要になったらばっさり削除または「こんなこと考えていたんだぁ・・・」と郷愁に浸りながらそっと閉じます。なので最終的にはDBの項目集(CREATE TABLEで、項目の意味とかをExcelに貼っつけたもの)だけが残る感じですかね。
その他こまごましたこと。
ランディングページは作りましょう。
せっかくWebでログインする仕組みを作ったならもったいないのでみんなが見れるページは作っておきましょう。ボットの宣伝にもなりますし、何よりGoogleとかがクロールしてくれまのでGoogle Adsense貼っとけ〜!みたいな。まぁ、まず儲かりませんがww。最近はトップページって言わずにランディングページなんて言うんだね。あと、ランディングページ、作るのいいですが当然のように嵐のようなクローラーが来ます。ちゃんと対策は取っておいた方がいいです。
ANT鉄板
もちろんMavenなどでもいいですが、、、プロパティファイルで開発時と本番を分けるって事は実行時のプロパティファイルが別物ってことです、当然ですがwarファイルを作成する際に
「プロパティファイルの項目を本番の値にいじってから作成する」って運用は止めましょうね。
必ずミスが付きまといます。いや、実際にその運用で本番に間違えて開発の値をデプロイしてしまい責任者からドヤされている現場を・・・おっとココまでにしておきましょう。ついでに言っておくとこういうのはその運用をあずかる人間(責任者)がミスをしない仕組みとして「2重チェック」しか思い浮かばないところに悲劇があったりします。自動化できる部分は自動化しましょう。
Executor使いましょう。
先ほどのイベント管理ですが、DBから値を引っ張ってきてイベント処理を起動する。その場合、処理の呼び出しから終了まで同期処理でもいいのですが、非同期で動かしたほうがいいです。イベントが重なったり異なるTwitter IDが同時刻あたりに処理をする場合なんかは特にそうです。
自分の作っているものはつい最近までExecutorの存在を知らなかったので(えぇ〜!イマサラかよ!)Threadをナマで扱っています。自前でキューを作って自前でスレッド管理して・・・これはこれで凄い苦労が・・・是非とも今からボットを作る人はExecutorで楽になってください。
管理画面で細々とした設定をできるようにする。
例えば毎日起動するボットがあるとして、19日に「明日はビッグコミックオリジナルの発売日だよ!」とつぶやく条件を加えたい場合ですが、どうでしょうか?プログラムいじる?そんなときに自由に条件を作れたら嬉しいです。自分の場合、基本はデータベースの項目でイベントを起動する条件を書き、オプショナルな条件としてGroovyで書けるようにしています。
コレの難点は、Groovyの処理(テキスト)ももちろん何がしかの永続化をする必要がありますが、ソースとして現れてこないので、後で「あれ?あの条件ってどこに書いたっけ?」なんてEclipseを舐めまわしても出てこなくなるところです。Groovy単体の処理ならいいのですが、そこにSQLが書いてあったり、自分で作ったクラスを利用していたりすると、Eclipseの参照で追えなくなってしまうので大変です。
最後に
勝手気ままな事書いてまとまりが無かったような気がします。「じゃぁ実際のコードはどうすんねん!」的な文章だったと思いますが、ここまで読んでいただき有難うございました。実装に関しては次の機会ということで。