読者です 読者をやめる 読者になる 読者になる

A little bit of everything

情報系大学院生の備忘録

RubyでTwitterのBotを作ってみた(後編)

RubyTwitterBotを作ってみた(前編)RubyでTwitterのBotを作ってみた(前編) - A little bit of everything のつづき。
OS X ver.10.9.5 でやってます。

テキストファイルにTweetする内容を列挙しておいて、Postするときにランダムに1つ取ってきてTweetする。みたいなことをやる。
まずは、txtファイルにTweet内容を列挙。

Hello World!
This is a message from Ruby.
I am a bot.
Are you serious?

これを tweet.txt として保存。
前編に書いたプログラムをちょっと修正。

# coding: utf-8
require "twitter"
require 'oauth'

client = Twitter::REST::Client.new do |config|
  config.consumer_key = "XXXXXX"
  config.consumer_secret = "YYYYYY"
  config.access_token        = "ZZZZZZ"
  config.access_token_secret = "XYZXYZ"
end

s=[]

#Fileは絶対パスじゃないと怒られる可能性あり
File.open("/XXX/YYY/ZZZ/tweet.txt","r") do |l|
  l.each_line do |line|
    s.push(line)
  end
end
client.update(s.sample)

参考 Rubyで書いたTwitterのbotをRaspberry Piで動かす - DesignAssembler

これをcronで動かす。
crontab -e でエディタが開くので、

*/1 * * * * ruby /XXX/YYY/ZZZ/index.rb

と書いてみる。
*/1は1分毎に実行という意味。(とりあえず動作を確認したいので、最初は1分毎)
あと、ファイル名は絶対パスじゃないと怒られる可能性あり。 (怒られる場合はcronから/var/mail/にメールが届く)
これでもしPermission Denied だったら、index.rbの権限を変えてあげる。 chmod u+x index.rb

これで1分に1回Tweetされれば成功!
あとはさっきのcrontabで、Tweetしてほしいタイミングに書き換えてあげればOK.

【追記】

tweet.txtの中身が日本語だとエラーが出た。

/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/uri/common.rb:304:in `gsub': invalid byte sequence in US-ASCII (ArgumentError)
    from /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/uri/common.rb:304:in `escape'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:32:in `escape'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:114:in `block (2 levels) in normalized_params'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:114:in `collect'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:114:in `block in normalized_params'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:114:in `collect'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:114:in `normalized_params'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:110:in `signature_base'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:101:in `hmac_sha1_signature'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:97:in `signature'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:77:in `signed_attributes'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:83:in `normalized_attributes'
    from /Library/Ruby/Gems/2.0.0/gems/simple_oauth-0.3.1/lib/simple_oauth/header.rb:65:in `to_s'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/headers.rb:36:in `auth_header'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/headers.rb:27:in `request_headers'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/rest/request.rb:31:in `perform'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/rest/utils.rb:50:in `perform_request'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/rest/utils.rb:72:in `perform_request_with_object'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/rest/utils.rb:64:in `perform_post_with_object'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/rest/tweets.rb:158:in `update!'
    from /Library/Ruby/Gems/2.0.0/gems/twitter-5.15.0/lib/twitter/rest/tweets.rb:128:in `update'
    from /Users/Yuuki/Desktop/bot/index.rb:19:in `<main>'

解決策は、tweet.txtを開くときにエンコードを指定してやる。こんなふうに。

# coding: utf-8
require "twitter"
require 'oauth'

client = Twitter::REST::Client.new do |config|
  config.consumer_key = "XXXXXX"
  config.consumer_secret = "YYYYYY"
  config.access_token        = "ZZZZZZ"
  config.access_token_secret = "XYZXYZ"
end

s=[]

#Fileは絶対パスじゃないと怒られる可能性あり
#Fileを開くときに、utf-8としてopen
File.open("/XXX/YYY/ZZZ/tweet.txt","r:utf-8") do |l|
  l.each_line do |line|
    s.push(line)
  end
end
client.update(s.sample)

これでOK!


【追記2】

実験をしていて、
①「同じ内容がTweetされないぞ?」とか、
②「1分間隔で設定しているのに、2分以上間隔をあけてTweetされたりするぞ?」
という現象が起こった。

調べたら、Twitterでは、ここの記事のとおり、同じ内容はある程度時間をおかないとTweetできないみたい(もしくは、10Post以上の間隔をあける)。これが原因。

cronでrbを実行して、ランダムにTweet内容を選んでTweetしようとしたけど、以前と同じ内容だったのでできない。というパターンが①。
何度かcronで実行するうちに、以前と違う内容が偶然選ばれればTweetされる。だから2分以上の間隔があいた。というパターンが②。