2012-01-29
● [プログラミング] TwitterのツイートをtDiaryにポストするスクリプト (とりあえず最後)
昨日の続きです。
(1) tDiaryへの投稿
まず、実際に update.rb へツイートを投稿する部分を作ります。今までファイルに書き込んでいた write_to_file というメソッドを少し改造します。
参考にするのは、tDiary の contrib に含まれている posttdiary.rb というファイルで、これは電子メールで送付されてきた日記をウェブ経由で tDiary にポストするプログラムです。なぜファイルの入出力を使わないのかとも思いましたが、おそらく前方互換性なりファイルシステムの変更なりに対応するためということでしょう。ファイルI/Oが使えないなら最初からRubyで作る必要もなかったか…という気もしますが。
このあたりはあまり悩む必要もなく純粋にPOSTでデータを渡すだけなので、ほぼコピー&ぺーストで作っていきます。なお、update.rb の場所、Basic認証のユーザ名・パスワード等は、今のところグローバル変数で定義しています。
$tdiary_url = 'http://.../update.rb' # update.rb のURL $tdiary_uname = '.....' # update.rb にアクセスするのに必要な Basic 認証用ユーザ名 $tdiary_pass = '.....' # update.rb にアクセスするのに必要な Basic 認証用パスワード $diary_heading = '![Twitter] 本日のツイート' # 日記のサブタイトル
def post_tweets(day, tweets) if tweets.size > 0 then html_data = $diary_heading + "\n" tweets.sort {|x,y| x.created_at <=> y.created_at }.reverse.each do |t| html_data += tweet2html(t) + "\n" end data = "year=#{day.year}&month=#{day.month}&day=#{day.day}" data << "&body=#{CGI::escape html_data}" data << "&append=true" data << "&makerss_update=false" uri = URI.parse($tdiary_url) inre = /<input type="hidden" name="csrf_protection_key" value="([^"]+)">/ Net::HTTP.start(uri.host, uri.port) do |http| auth = ["#{$tdiary_uname}:#{$tdiary_pass}"].pack('m').strip res, = http.get(uri.path, "Authorization" => "Basic #{auth}", "Referer" => $tdiary_url) if inre =~ res.body then data << "&csrf_protection_key=#{CGI::escape(CGI::unescapeHTML($1))}" end res, = http.post(uri.path, data, "Authorization" => "Basic #{auth}", "Referer" => $tdiary_url) end puts day.strftime("Posted tweets for %Y/%m/%d. Sleeping for 1 sec.") sleep 1 end end
(2) コマンドラインオプションに対応する
この時点で概ねやりたいことには対応していますが、動作検証しやすいよう、コマンドラインオプションを付け加えていきます。
以前は Ruby も他の言語と同様 getopts を使ってコマンドラインオプションをパースしていましたが、最近(Ruby 1.8.2以降)は OptionParser というものを使うそうです。
parser = OptionParser.new cmd_opts = Hash.new("#{__FILE__}: post tweets to tdiary.\nUsage: #{__FILE__} [options]")
parser.on("-d", "--debug", "enter debug mode") { |v| cmd_opts[:debug] = true } parser.on("-v", "--verbose", "enter verbose mode") { |v| cmd_opts[:verbose] = true } parser.on("--max-id ID", Integer, "retrieve tweets with id smaller (older) than ID") { |v| cmd_opts[:max_id] = v } parser.on("--days MANDATORY", Integer, "set maximum days to retrieve tweets") { |v| cmd_opts[:days] = v } parser.on("--cont", "continue from the previous run (read max_id from cache)") { |v| cmd_opts[:cont] = true cmd_opts[:max_id] = read_lastid_from_cache } begin parser.parse!(ARGV) rescue OptionParser::ParseError $stderr.puts "#{__FILE__}: error #{$!}" exit 1 end def debug_puts(txt, level=0) puts " " * level + txt if (cmd_opts[:debug] || false) end
(3) できあがり
その他、リツイートされたツイートには RT マークを付けるなど細かいところを修正し、最終的にできあがったのが tw2td-20120129.tar.gz です。
[ツッコミを入れる]