RubyでTwitterにツイートをキメてみる

[Ruby][Twitter][API]RubyでTwitterにツイートをキメてみる

前回までのあらすじ

  1. http://d.hatena.ne.jp/kk_Ataka/20101121/1290271210:title
  2. http://d.hatena.ne.jp/kk_Ataka/20101130/1291125511:title
  3. http://d.hatena.ne.jp/kk_Ataka/20101207/1291733295:title

ターミナルからOAuth認証をキメて、タイムラインを見られるようになりました。最後にターミナルからツイートが出来れば一応Twitterの見る・書くがライブラリ無しでできたことになります。

ツイートする方法

  1. signatureを作成する。必要な値は以下のとおり。
    1. oauth_consumer_key
    2. oauth_nonce
    3. oauth_signature
    4. oauth_signature_method
    5. oauth_timestamp
    6. oauth_token
    7. oauth_version
    8. status New!

statusっていうのがツイートの本文ですね。signature作成するのにエスケープします。作成後のheaderはこんな感じ。[1]statusには「確認確認」って入ってます。

{
    "oauth_nonce"=>"3c8293f9c5a0295148d428a26edb9f46", 
    "oauth_timestamp"=>"1295784908", 
    "oauth_signature_method"=>"HMAC-SHA1", 
    "oauth_consumer_key"=>"XXXXXXXXXXXXXXXXXXXXXX", 
    "oauth_token"=>"99999999-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY", 
    "oauth_signature"=>"UKt1BmJ+UWNWrSmBuAyJ40iiCNY=", 
    "status"=>"%E7%A2%BA%E8%AA%8D%E7%A2%BA%E8%AA%8D", 
    "oauth_version"=>"1.0"
}

signature作成後

  • signatureを作成したら、headerからstatusを消します
  • 残ったheaderをアルファベット順に並べ、xxx=yyy,vvv=zzz……の形で連結します。連結後はこんな感じ
oauth_consumer_key=XXXXXXXXXXXXXXXXXXXXXX,oauth_nonce=341d852d61cdc3c22e3e847b0ab69d20,oauth_signature=MR5WEJ1qHuE49ozgRYduNJ%2BBiCs%3D,oauth_signature_method=HMAC-SHA1,oauth_timestamp=1295785315,oauth_token=99999999-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY,oauth_version=1.0
  • 連結した上記の値をAuthorizationヘッダに入れる。入れた後はこんな感じ。
"Authorization"=>"OAuth oauth_consumer_key=XXXXXXXXXXXXXXXXXXXXXX,oauth_nonce=341d852d61cdc3c22e3e847b0ab69d20,oauth_signature=MR5WEJ1qHuE49ozgRYduNJ%2BBiCs%3D,oauth_signature_method=HMAC-SHA1,oauth_timestamp=1295785315,oauth_token=99999999-YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY,oauth_version=1.0"

結果

以上で、Twitterにツイートが完了しました! おっぱいきたーー

[f:id:kk_Ataka:20110123215838j:image]

ソース

ソースはこんな感じです。

# -*- encoding: UTF-8 -*-

require 'openssl'
require 'uri'
require 'net/http'
require 'nkf'
require 'time'

# 署名
def sigunature(method, 
        consumer_secret, 
        oauth_token_secret, 
        url, 
        oauth_header=nil)
    # sigunature_keyの作成
    # リクエストトークン時は"CONSUMER_SECRET&"(アンドが入っている)
    # アクセストークン時は"CONSUMER_SECRET&OAUTH_TOKEN_SECRET"として使用
    sigunature_key = consumer_secret + "&"
    if !oauth_token_secret.nil? then
        sigunature_key += oauth_token_secret
    end

    param = sort_and_concat(oauth_header)

    # メソッド + URL + パラメータ
    value = method + "&" + escape(url) + "&" + escape(param)
    # hmac_sha1
    sha1 = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, sigunature_key, value)
    # base64
    base64 = [sha1].pack('m').gsub(/\n/, '')
    return base64
end

# 文字列のエスケープ(: / = %をエスケープする。. _ -はそのまま)
def escape(value)
    URI.escape(value, Regexp.new("[^a-zA-Z0-9._-]"))
end

# oauth_headerの情報をアルファベット順に並べ替え & で結合
def sort_and_concat(oauth_header)
    oauth_header_array = oauth_header.sort
    param = ""
    oauth_header_array.each do |params|
        for i in 1..params.length
            param += params[i-1]
            if i % params.length  == 0
                param += "&"
            else
                param += "="
            end
        end
    end
    param = param.slice(0, param.length-1)
end

# -------------------------------------------------------------

update_url = "http://twitter.com/statuses/update.json"

url = update_url
# コマンドプロンプトはutf8変換
text = escape(ARGV[0])
# text = escape(NKF.nkf('-w', ARGV[0]))
proxy = ARGV[1]

# Twitterで登録したらもらえる
consumer_key = "XXXXXXXXXXXXXXXXXXX"
consumer_secret = "YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"
# Twitterからもらえるリクエストトークン(最初は使わない)
oauth_token = "11111111-ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
oauth_token_secret = "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV"

# oauthパラメータたち(決め打ちのもの)
oauth_header = {
    # Consumer Key
    "oauth_consumer_key" => consumer_key,
    # 一意な値
    "oauth_nonce" => OpenSSL::Digest::Digest.hexdigest('MD5', "#{Time.now.to_f}#{rand}"), 
    # 署名方式(HMAC-SHA1)
    "oauth_signature_method" => "HMAC-SHA1",
    # リクエスト生成時のタイムスタンプのミリ秒
    "oauth_timestamp" => Time.now.to_i.to_s, 
    # バージョン(1.0)
    "oauth_version" => "1.0",

    # アクセストークン
    "oauth_token" => oauth_token
}

# headerにツイート追加
oauth_header["status"] = text

# 署名生成
oauth_header["oauth_signature"] = sigunature("POST",
                    consumer_secret,
                    oauth_token_secret,
                    url,
                    oauth_header)

# headerからツイート削除
oauth_header.delete("status")
# 署名エンコード
oauth_header["oauth_signature"] = escape(oauth_header["oauth_signature"])
param = sort_and_concat(oauth_header)

param = param.gsub('&', ',')

header = {
    "Authorization" => "OAuth " + param
}

# POST
uri = URI.parse(update_url)
proxy_class = Net::HTTP::Proxy(proxy, 8080)
http = proxy_class.new(uri.host)
http.start do |http|
    res = http.post(uri.path, "status=#{text}", header)

    if res.code == "200" then
        print "#{res.code} tweet: #{ARGV[0]}\n"
    else
        print "ERROR: #{res.code}\n #{res.body}\n"
    end
end

関連記事(この記事の初版より古い記事はリンクがグレーで表示されます)

  1. 2010/12/07 [Ruby] [Twitter] [API] RubyでTwitterのタイムラインを取得してみる
  2. 2010/11/30 [Ruby] [Twitter] [API] RubyでTwitterのOAuth認証をしてみる その2
  3. 2010/11/21 [Ruby] [Twitter] [API] RubyでTwitterのOAuth認証をしてみる
  4. 2011/12/27 [Evernote] [Ruby] [API] EvernoteのAPIをRubyから叩きたい
  5. 2011/03/08 [Ruby] [API] RubyではてなのWSSE認証をしてはてブにブクマをポストする
  6. 2011/03/02 [Ruby] [API] Read it LaterをRubyで取得する
  7. 2012/05/21 [SlideShare] [Heroku] [Ruby] [API] SlideShareのAPIを叩いてスライドをDLするRubyスクリプトをHerokuにデプロイした
  8. 2011/12/26 [Ruby] [Haml] [Sinatra] SinatraでHaml入門
  9. 2011/12/21 [Ruby] Ruby実行時のオプションをよろしく解析してくれるoptparseを使ってみる
  10. 2011/12/15 [Ruby] [Solaris] [Redmine] RedmineとApacheを連携させるPassengerをインストールできなかった
  11. 2011/12/07 [Ruby] ZenTestでRSpecを自動実行できるようにした
  12. 2011/12/05 [Ruby] [Redmine] RedmineでプラグインインストールしたらTemplateErrorが出た
  13. 2011/12/04 [Ruby] [Mac] [Unix] 複数のRuby環境の管理・切替ができるrvmをインストールした
  14. 2011/11/30 [Ruby] [Heroku] rvm環境でRuby実行時にReadlineエラーが起きた時の対処法
  15. 2011/11/29 [Ruby] pikでインストールしたRubyでbundle exec rubyしたらエラーになった 解決編