岩本隆史の日記帳(アーカイブ)

はてなダイアリーのサービス終了をうけて移行したものです。更新はしません。

Twitter botのプログラムを晒してみる

どんなbot

カラオケって、歌いたい曲が配信されてなかったりしますよね。

そのモヤモヤを救済するために、JOYSOUNDという超最高なカラオケ配信サービスが、配信リクエストを受け付けてくれています。リアルタイムリクエストです。投票で毎月200位までに入った曲が(なんらかの問題がないかぎり)配信されます。

投票にはポイントが必要で、このポイントを無駄にしないためには、なるべく200位ギリギリで通過させる戦略が求められます(ちょっと大げさか)。戦略を考えるにあたっては、順位の移り変わりをチェックしておくのが基本となります。

ぼくはキリンジというバンドのファンで、同じくキリンジファンの方々とTwitterで交流しているので、キリンジの曲の順位をチェックしてつぶやくTwitter botがあると便利だと思いました。実物はこれです。

事前準備

botのプログラムを書く前に、bot用のTwitterアカウントを用意したり、投稿に必要な各種キーを取得したり、といった事前準備が必要でした。下記ページの「OAtuhによるログイン方法」を参考にしました。

環境

早く公開したかったので、ぼくなりに早く書けるRubyを選びました。バージョンは 1.9.2-p136 です。

プログラム

美しくて堅牢なプログラムを書こうなどとは最初から思わなかったので、ざっと書いたら、こんな感じになりました。特に解説はしません。

# encoding: utf-8

require 'nokogiri'
require 'open-uri'
require 'twitter'
require 'escape_utils'
require 'escape_utils/url/rack'  # Rack::Utils#escapeのwarningを防ぐ

def utasuki_doc(singer)
  url = 'http://joysound.com/ex/utasuki/request/search.htm' +
        '?searchKbnGet=2' +
        "&searchKeyWordGet=#{EscapeUtils.escape_url(singer)}" +
        '&sortkey=8'
  Nokogiri::XML(open(url))
end

def songs(doc)
  xpath = "//tr[@class='odd' or @class='even' or @class='evenlast']"
  doc.xpath(xpath).map do |row|
    {rank:  row.xpath('./td[2]').text,
     title: row.xpath('./td[3]').text,
     votes: row.xpath('./td[6]').text}
  end
end

def songs_chunk(songs, hashtag)
  [] if songs.size == 0
  songs_chunk = [[]]
  songs.each do |song|
    if status(songs_chunk.last + [song], hashtag).size <= 140
      songs_chunk.last.push(song)
    else
      songs_chunk.push([song])
    end
  end
  songs_chunk
end

def statuses(songs, hashtag)
  songs_chunk(songs, hashtag).map {|ss| status(ss, hashtag)}
end

def status(songs, hashtag)
  songs_text = songs.map {|s| song_text(s)}.join('')
  "【うたスキ】#{songs_text} ##{hashtag} #{Time.now.strftime('%H:%M')}"
end

def song_text(song)
  "#{song[:rank]}位「#{song[:title]}#{song[:votes]}"
end

def tweet(statuses)
  Twitter.configure do |config|
    config.consumer_key = '{consumer_key}'
    config.consumer_secret = '{consumer_secret}'
    config.oauth_token = '{oauth_token}'
    config.oauth_token_secret = '{oauth_token_secret}'
  end
  statuses.each do |status|
    Twitter.update(status)
  end
end

doc = utasuki_doc('キリンジ')
songs = songs(doc)
abort 'no songs' if songs.size == 0
statuses = statuses(songs, 'kiririku')
tweet(statuses)

puts 'done.'

下記のライブラリを使っています。

  • twitter (1.1.1)
  • nokogiri (1.4.4)
  • escape_utils (0.1.9)

定期実行

上記のプログラムを /home/iwamot/projects/kirikara/bot.rb に保存し、crontabで毎時5分に実行しています。設定は下記の通りです。

$ crontab -l
GEM_HOME=/home/iwamot/.rvm/gems/ruby-1.9.2-p136
5 * * * * /home/iwamot/.rvm/rubies/ruby-1.9.2-p136/bin/ruby /home/iwamot/projects/kirikara/bot.rb