Herokuを使って1日1回名言をツイートするTwitter Botの作り方

ここ最近、Google App EngineHerokuを使ってTwitter Botを作ろうと、いろいろ実験していた。以下はその関連記事。

Google App EngineのJRubyでSinatraを使ってHello worldする RubyでTwitterのOAuth認証に必要なトークンを取得する Google App EngineのJRubyでSinatraからTwitterにつぶやけなかった HerokuでSinatraを使ってHello worldする HerokuアプリをGitHubにもプッシュする HerokuとGitHubの両方にプッシュする時の秘密にしたい値の扱い HerokuのSinatraでTwitterにつぶやく Herokuのcronを使って自動でTwitterにつぶやく

で、これらを踏まえた試行錯誤の結果、HerokuとSinatraの組み合わせで目的のものが作れたので、その工程(情報)をキレイに1つにまとめてみる。それがこのエントリー。

完成品

まずはこれが完成品。喜劇王チャップリンの名言をツイートする全自動Twitter Bot。この記事を通して完成するのはこのレベルのTwitter Botで、黙々と1日1回つぶやくだけ。

チャーリー・チャップリン (chaplin_bot) on Twitter Rubyのソースコード一式

自分は昔からチャップリンが好きで、出勤途中のiPhone片手にTwitterを見てるときに、そのタイムライン上にチャップリンの名言が流れてきたらいいなぁと思ってこのTwitter Botを作ってみた。そういう理由でツイートする時間帯も毎朝9時頃に設定してある。

参考になる2つの動画

今回のTwitter Botを制作する際に必要な各ツールやサービスを利用する上で、ネット上の色々な記事を見て回ったけど、中でも以下の2つの解説ビデオが特に参考になった。映像の力はすごい。ので、もし時間に余裕があれば事前に見ておくと、制作がより捗るかもしれない。両方見ても20分程度。

8分21秒で分かるRubyとOAuthによるTwitterAPIの使い方(動画)

この動画は、TwitterでのOAuthの認証に必要なアプリ登録からアクセストークン取得までの一連の操作をわかりやすく解説してくれる。1

Ruby on Rails向けPaaS「Heroku」って、こんな感じです(スクリーンキャスト)

この動画は、プロジェクト作成からウェブ公開までのHerokuの一連の操作をわかりやすく解説してくれる。2

必要なもの

今回の制作に必要な環境は以下のとおり。

  • Ruby環境(今回使用したバージョンは1.8.7)
  • Git環境(Webアプリの公開に必要。Windowsの場合はmsysGitなど)
  • Bot用のTwitterアカウント
  • Botがツイートする言葉(31個あると都合が良いが、それ以下でもOK)
  • Herokuのアカウント(未取得ならサインアップ
  • クレジットカード(お金はかからないけど、Herokuで1日1回自動でつぶやくためのアドオンを有効化するのに必要)

個人的には、クレジットカード情報の登録が一番ハードルが高いと感じた。3 ちなみに、自動でツイートさせる必要がなかったり、Heroku上だけで完結させる必要がなかったり4するなら、クレジットカード情報の登録は必要ない。

ただ、Herokuには色々と便利なアドオンが用意されており、無料で使えるものもたくさんある。例えばメール配信機能だとか、バックアップ機能だとかの無料アドオンを使う場合でも、やはりクレジットカード情報の登録が必要になるので、たとえ無料部分しか使わないとしても、長く使っていくにはいずれ通る道な気がする。

開発の流れ(目次)

全体の流れを大雑把に説明すると以下の5ステップ。

  1. プロジェクトの準備[Git]
  2. Twitterとの認証[Twitter]
  3. プログラミング[Ruby]
  4. 公開[Heroku]
  5. 自動化[Heroku]

1. プロジェクトの準備

それでは始めよう。まず、この第1ステップでは、必要なRubyライブラリのインストールや、プロジェクト用フォルダの作成、Gitの初期化などを行う。全ステップの中で最も簡単な工程なので安心されたし。

必要なgemのインストール

今回必要になるgemをここで一気にインストールしてしまおう。コマンドプロンプトまたはターミナル(以降「コマンドプロンプト」と記述)で、タイプミスの無いように、以下のgem installコマンドを実行する。コピペ推奨。

$ gem install heroku sinatra bundler get-twitter-oauth-token --no-rdoc --no-ri

RVMを利用していない場合など、環境によってはインストール時にsudoが必要になることもあります。

インストールにはそんなに時間は掛からないはず。サクサク進もう。

Bot用フォルダを作成

次に、ローカルのHDD上にBot用のプロジェクトフォルダを作成する。

$ mkdir chaplin_bot
$ cd chaplin_bot
$ git init

今後の作業はすべて、このchaplin_botフォルダをベースに行う。git initは必須。これがないと最終的にHerokuでWebアプリを公開できない。

現時点でのプロジェクト構成

この時点でのchaplin_botフォルダの構成はこんなかんじ。

.
└── .git
1 フォルダ

最初は.gitフォルダだけ。これで第1ステップは完了。

2. Twitterとの認証

ここからはTwitterとOAuthでの認証処理を行う。この認証をすることで、WebアプリからTwitterにツイートできるようになる。以下は冒頭でも紹介したが、これからやる一連の認証作処理の雰囲気を掴むのに適しているので、8分21秒の時間の余裕があれば是非。

8分21秒で分かるRubyとOAuthによるTwitterAPIの使い方(動画)

ここからの工程には、Twitterのサイトに訪れて登録・認証を行うものが含まれていますが、普段メインで使用しているTwitterアカウントと、今回のBot用アカウントが混同しないように十分注意してください。普段使っているブラウザでメインのTwitterアカウントがログイン状態の場合は、事前にログアウトしておくことをおすすめします。

Twitter側での準備

Bot用Twitterアカウントにログインして、Twitterのアプリケーション登録申請のページから、「新しいアプリケーションを追加」をクリックして新規アプリを登録する。項目の中で必須なのは、以下の5つ。

アプリケーション名 チャップリン
アプリケーションの説明 チャップリンBotは、喜劇王Charlie Chaplinの名言をつぶやく全自動Botです。
アプリケーションのウェブサイトURL http://twitter.com/chaplin_bot
アプリケーションの種類 ブラウザアプリケーション
標準のアクセスタイプ Read & Write

で作成するとConsumer keyConsumer secretが表示されるので2つともメモる。

TwitterのOAuth認証に必要なトークンを取得

次に、第1ステップでインストールしたget-twitter-oauth-tokenライブラリを使用して、TwitterのOAuthでの認証に必要なトークンを取得する。

$ get-twitter-oauth-token

コマンドプロンプトから上記コマンドを実行する。get-twitter-oauth-tokenコマンドを実行すると、さきほどメモったConsumer keyConsumer secretを聞かれるのでペーストする。するとウェブブラウザが自動で開いて(Windowsの場合は手動でアドレスを入力して開いて)、Twitterのページが表示され「アプリを許可しますか?」と聞かれる。

許可すると、暗証番号(PIN)が表示されるのでそれをコピる。コマンドプロンプト側では、その暗証番号の入力待ち状態(PIN:)になっているのでペーストする。

すると、TwitterのOAuth認証に必要なTokenSecretが表示されるので2つともメモる。これでこの第2ステップは完了。

3. プログラミング

やっとプログラミングの段階に入る。ここではコード自体の説明は触れずに、作成する必要があるファイルのみを列挙する。ファイルはすべてUTF-8で作成する。コードの内容や、Ruby/Sinatraについて詳しく知りたい場合は、ページ末尾の参考リンクを参照されたし。

各種ファイルを作成

chaplin_botフォルダ直下に、新しく4つのファイルを作成する。最終的に以下のようなファイル構成になればOK

.
├── .git
├── Gemfile
├── app.rb
├── config.ru
└── tweet.rb
1 フォルダ, 4 ファイル

拡張子のないファイルもあるのでWindowsの場合は注意。まったく同じファイル名にすること。まず1つ目、Bundler用のGemfileファイルを作成する。ファイルの中身は以下。

source :rubygems
gem 'sinatra'
gem 'twitter'

2つ目、Rack用のconfig.ruファイルを作成する。中身は以下。

require 'app.rb'
run Sinatra::Application

3つ目、Sinatraの処理を記述するapp.rbファイルを作成する。中身は以下。

require 'rubygems'
require 'sinatra'
require 'tweet.rb'
get '/' do
  'under construction'
end
get '/random_tweet' do
  Tweet.new.random_tweet  # 動作チェックが終わったらコメントアウトすること
end

最後4つ目、Twitterに投稿する言葉(名言)やロジックを記述するtweet.rbファイルを作成する。中身は以下。

require 'rubygems'
require 'twitter'
class Tweet
  def initialize
    @text = <<-EOF.split("\n")
私の最高傑作は次回作だ。
映画の目的は笑わせることだ。しかし、そのなかには、二十世紀の世界に通じるシリアスな内容が含まれている。
いつも大人のなかにまぎれこんでしまった子供のような気がする。
孤児院にいたときでも、食べ物を求めて通りをうろつきまわっていたときでも、自分は世界一の俳優だと信じていた。自分自身にたいする揺るぎない自信に身をひたしている必要があった。それがなければ人生に押しつぶされていただろう。
母のパントマイムは私の見たかぎりにおいて、もっともすばらしいものであった。母の所作を見ているうちに、私は感情を手や顔で表現する技術ばかりでなく、人間というものを学びとることができた。
私は悲劇を愛する。悲劇の底にはなにかしら美しいものがあるからこそ悲劇を愛するのだ。
人生は恐れなければ、とても素晴らしいものなんだよ。
世の中には貪欲に知識を求める人間がいる。私もその一人だった。ただし動機から言うと、私のはそれほど純粋ではなかった。知識愛から求めたのではなく、ただ無知な人間にたいする世間の侮蔑から身を護るためにそうしたのだった。そんなわけで、暇さえあれば、古本屋漁りをしていた。
もし虹を探すのなら、下を見ては見つからない。
人生はクローズアップで見れば悲劇。ロングショットで見れば喜劇。
時は偉大な作家だ。つねに完璧な結末を書く。
笑いのない一日は無駄な一日である。
死と同じように避けられないものがある。それは生きることだ。
人生に必要なものは、勇気と想像力とほんの少しのお金だ。
幸福を手にするための戦いは美しいものです。
長い間の経験から、アイデアというものは、それを一心に求めてさえいれば必ずくるということを発見した。たえず求めているうちに、いわば心が想像力を刺激するような出来事を見張る一種の物見やぐらになってしまうのである。
私たちはみんなおたがいに助けあいたいと望んでいます。人間とはそういうものです。私たちは他人の不幸によってではなく、他人の幸福によって生きたいのです。
一人を殺せば殺人者だが、百万人を殺せば英雄だ。殺人は数によって神聖化させられる。
あなた方は機械ではない、人間です。人間を愛する心を持った人間です。憎んではいけません。愛を知らぬ人間、愛されたこともない人間だけが憎むのです。隷属のために戦ってはいけません。自由のために戦ってください。あなた方はこの人生をすばらしいものにする力を持っているのです。
人間には憎悪や不快を忘れさせてしまう性質がある。
大量殺人については、世界はそれを奨励しているのではありませんか。大量殺人という唯一の目的のために、破壊兵器を製造しているのではありませんか。
愛国心というものは、かつて世界に存在した最大の狂気である。愛国心がもてはやされた結果は、また新たな戦争である。
生きて行くことは美しく素晴らしい。クラゲにとってもね。
人生は願望だ、意味じゃない。
僅かな人間が決めた賞なんて、そうたいした名誉ではない。私のほしいものは大衆の喝采だ。大衆が私の仕事を賞賛してくれたならば、それで十分だ。
私は支配したくない。私は人の幸福を願いながら生きたい。貪欲が人類に憎悪をもたらし悲劇と流血をもたらした。思想だけがあって感情がなければ人間性は失われてしまう。
最初から多くのことを成し遂げようとして極端な努力をすると、たちまちのうちに全てを放棄することになる。
失敗は重要ではない。自分自身を馬鹿にするのは勇気がいる。
どうやってアイデアをつかむか? それには、ほとんど発狂一歩手前というほどの忍耐力がいる。苦痛に耐え、長期間にわたって熱中できる能力を身につけねばならぬ。
そうだ人生はすばらしい。何より大切なのは勇気だ、想像力だ。
"You?" "You can see now?" "Yes, I can see now."
EOF
    Twitter.configure do |config|
      config.consumer_key       = 'メモったConsumer keyを挿入する'
      config.consumer_secret    = 'メモったConsumer secretを挿入する'
      config.oauth_token        = 'メモったTokenを挿入する'
      config.oauth_token_secret = 'メモったSecretを挿入する'
    end
  end
  def random_tweet
    tweet = @text[rand(@text.length)]
    update(tweet)
  end
  def daily_tweet
    tweet = @text[Time.now.day - 1]
    update(tweet)
  end
  private
  def update(tweet)
    return nil unless tweet
    begin
      Twitter.update(tweet.chomp)
    rescue => ex
      nil # todo
    end
  end
end

4つ目のtweet.rbは、以下の2点を編集する必要がある。

ツイートする言葉の編集

まず見ての通り、Botがツイートする言葉(名言)が埋めこまれているのがわかる。8行目~38行目の文字列がそれで、1行あたり1ツイートに相当し、31個用意してある。この31個は1ヶ月の31日と対応しており、1日には1行目が、2日には2行目が、31日には31行目がツイートするようにプログラムされている。

なので、用意できる名言が31個より少なければ、重複しても良いので増やして31個になるように調整する。逆に、現時点では31個以上用意してもツイートされないので意味が無い。この仕様はあまり良いとは思ってないので、将来的にはたくさんある候補の中からランダムで1つツイートするように改善したいところ。とりあえず今回は上記のとおり、1行分=1日分の仕様で進める。

Twitter認証に必要な4つのキーを挿入

上記のツイートする言葉(名言)が埋めこまれている場所のすぐ下に、Twitter認証に必要な4つのキーを挿入する以下のコードがある。行数で言うと41行目~46行目。

    Twitter.configure do |config|
      config.consumer_key       = 'メモったConsumer keyを挿入する'
      config.consumer_secret    = 'メモったConsumer secretを挿入する'
      config.oauth_token        = 'メモったTokenを挿入する'
      config.oauth_token_secret = 'メモったSecretを挿入する'
    end

シングルクォートで囲まれた文字列に書いてある通り、2ステップ目のTwitter認証でメモったそれぞれのキーを該当する場所5に挿入する。ここが間違っているとTwitterに正常に投稿されない。

tweet.rbの上記の2点を編集し終えたら、この第3ステップは完了。

4. 公開

ついにステップ1~3までで制作したものを、Heroku側に送信してウェブに公開する。この第4ステップは、冒頭で紹介したHeroku解説ビデオを事前に見ておくとグッと理解が深まるので、時間に余裕があれば是非。

Ruby on Rails向けPaaS「Heroku」って、こんな感じです(スクリーンキャスト)

Heroku上にWebアプリを新規作成

まず、herokuコマンドを使って、Heroku上にWebアプリを新規作成する。Windowsの場合は、msysGit上での操作を推奨。ここで指定した名前が、他で使われていないものであればHerokuに登録され、それがサブドメインとなる。この名前(サブドメイン)は後からでも変更可能なので、とりあえず適当な名前でも大丈夫。6

$ heroku create chaplin

初回は、Herokuアカウントに登録したE-mailアドレスとパスワードを求められるので入力する。 正常にWebアプリを作成できると、Git remote heroku addedと表示され、gitコマンドのremote先にHerokuが追加される。

また、すぐにhttp://登録したアプリ名.heroku.com/にアクセスできるようになり、Herokuの管理画面にも今作成した新しいWebアプリが登録される。これでHerokuでのWebアプリの新規作成が完了。

公開する前の準備

公開に向けて、まず利用するgemの仕様書を整える儀式を行う。chaplin_botフォルダ内で以下のコマンドを実行する。

$ bundle install

Your bundle is complete!と表示されて、chaplin_botフォルダ内にGemfile.lockが生成されれば準備完了。chaplin_botフォルダ内がこんな配置になっていればOK

.
├── .git
├── Gemfile
├── Gemfile.lock  # これが追加
├── app.rb
├── config.ru
└── tweet.rb
1 フォルダ, 5 ファイル

Gitを使ってHerokuに送信

まず、ローカルのGitリポジトリにコミットする。

$ git add .
$ git commit -m 'first commit!'

Windowsの場合は、改行コードに関する警告(CRLFをLFに変換する云々)が出るが、とりあえずスルーでOK。そしてHerokuに向けてプッシュする。つまりネット上に公開する。

$ git push heroku master

これだけ。ちょうかんたん。

手動でツイート

プッシュが完了したら、もうウェブサイトにアクセスできるので、

$ heroku open

heroku openコマンドをすると、http://登録したアプリ名.heroku.com/をブラウザで開いてくれる。開いたページにunder constructionと表示されていればOK。それでブラウザのアドレス欄で、アドレスの末尾にrandom_tweetを追加して、http://登録したアプリ名.heroku.com/random_tweetにアクセスしてみよう。

英語の文字列がいっぱい表示されればTwitterへの発言は成功
何も表示されず真っ白なページなら失敗

成功していれば、Bot用Twitterアカウントのタイムラインを見てみよう。31個の中からランダムに選択された言葉がちゃんとツイートされているはず。ちゃんとツイートされていれば、この第4ステップは完了。

5. 自動化

最後に、手動ではなく自動でツイートするように設定する。ここでHerokuへのクレジットカード情報の登録が必要になる。

Herokuでcronアドオンを有効化

Herokuのアドオン一覧から、cronアドオンのページを開く。1日単位のcronなら無料で利用できるが、無料利用でもクレジットカード情報の登録が必要。というわけで、verify your accountのリンクをクリックして、クレジットカード番号や住所・電話番号などの情報を登録する。登録が終わってAccount verified.となったらOK

もういちどcronアドオンのページに行き、「Daily Cron」の方のAddボタンを押す。Herokuアプリの選択画面が出た場合は、登録したアプリ名を選択してSelectボタンを押す。実は、このSelectボタンを押してcronアドオンを追加した時の時間が、cronが発動する時間=自動でツイートする時間になる。

アドオンを有効にするのは、以下のコマンドラインからも可能(クレジットカード情報の登録は別)。

$ heroku addons:add cron:daily

手動ツイート機能を消す

動作チェックのためにhttp://登録したアプリ名.heroku.com/random_tweetにアクセスしてツイートした機能を消す。app.rbファイルの10行目の行頭に半角のシャープ記号を挿入してコメントアウトする。

get '/random_tweet' do
#  Tweet.new.random_tweet  # 動作チェックが終わったらコメントアウトすること
end

こうすれば、http://登録したアプリ名.heroku.com/random_tweetにアクセスしてもつぶやかれなくなる。真っ白なページが表示されるだけ。この機能を消す理由は、自分以外の人が上記のURLにアクセスして、Bot用Twitterにツイートされてしまう危険性を無くすため。

もし残したままにして、上記のURLを見つけた人が仮に連打したりすると、最悪の場合Bot用Twitterアカウントが凍結されてしまうこともある。

自動ツイート機能を追加

chaplin_botフォルダに、1日1回自動で投稿するHerokuへの指示を記述するRakefileファイルを作成する。いわゆるcronジョブ。中身は以下。

require 'tweet.rb'
task :cron do
  Tweet.new.daily_tweet
end

最終的にchaplin_botフォルダの構成は以下のようになる。

.
├── .git
├── Gemfile
├── Gemfile.lock
├── Rakefile  # これが追加
├── app.rb
├── config.ru
└── tweet.rb
1 フォルダ, 6 ファイル

もういちど公開

第5ステップで加えた変更点を、まずローカルのGitリポジトリにコミットする。

$ git add .
$ git commit -m 'second impact!'

そしてHerokuに向けてプッシュする。

$ git push heroku master

これで、さきほどcronアドオンのSelectボタンを押した時間の24時間後から、毎日cron処理(Rakefile)が走って自動でツイートされる。本当にツイートされるかどうかを確認するには、1日待ってみるしかない。果報は寝て待て。

このcronアドオンについて、さらに詳しい情報はこちらの記事を参照されたし。

Herokuのcronを使って自動でTwitterにつぶやく Herokuのタイムゾーンを日本時間に設定する

ここまでのソースコード

この時点でのchaplin_botのソースコードを、version 1.0としてタグを切ったので、GitHubからダウンロード可能。

ruedap/chaplin at 1.0 - GitHub

これで全ステップが完了。無事、1日1回名言をツイートするTwitter Botが完成。
おつかれさまでしたー

バージョンアップ

この記事を公開以降もTwitter Botに機能追加などを行ってバージョンアップしているので、興味のある方は以下の記事などからどぞー。

SinatraからDataMapperを使う(1) 動作チェック用のコード SinatraからDataMapperを使う(2) マイグレーションとモデルの分離 SinatraからDataMapperを使う(3) バリデーション SinatraからDataMapperを使う(4) シャッフルツイート機能 SinatraからDataMapperを使う(5) HerokuのPostgreSQLで使う

参考リンク

最後に、この記事を書くにあたって参考になったり、各ツールの使い方を勉強するのにとても役立ったページをまとめておく。情報を公開してくれている各ページの作者さんに感謝!

Ruby

Sinatra

Heroku

Git

  1. リンク先の動画では作者オリジナルスクリプト、このエントリーではget-twitter-oauth-tokenライブラリと、使っているトークン取得スクリプトが違うものの、認証処理自体はあまり違わないので大丈夫

  2. リンク先の動画ではRails3、このエントリーではSinatraと、使っているフレームワークが違うものの、Heroku自体の使い方自体はあまり違わないので大丈夫

  3. GAEで成功していればこれは要らなかったはず…

  4. たとえば別のサーバーやPCにcronジョブを仕込んでおいて、そこからHerokuアプリのツイート用URLを叩くとか

  5. シングルクォートで囲まれた内側

  6. この例での“chaplin”は既に使用されているので、他のフレーズを入力してください