ツイートに含まれるハッシュタグや URL の情報を取得する方法 (日本語ハッシュタグへの対応などの仕様変更に自動で対応できるように)

先日、twitter が日本語のハッシュタグに対応 して、何かと便利になったような気がします。 ただ、残念ながら twitter クライアントや twitter 関係の web サービスではまだ日本語のハッシュタグに対応できていないところもあるようです。 例えば とぅぎゃったー とかもそうですね。 (PHP あるあるのとぅぎゃったーまとめ を見ていて日本語ハッシュタグへの非対応に気づきました。)

Entities 情報を利用してハッシュタグや URL 情報を取得する

さて、日本語ハッシュタグに対応できていないのは、それぞれのサービスが独自にツイート内容からハッシュタグを抽出するようにしているからだと思います。 日本語ハッシュタグも抽出できるようにそれぞれのサービスがハッシュタグ抽出の方法を変更すれば今回は対応できますが、twitter の仕様が変更されればまたそのつど対応していかなければいけません。

そのような方法をとるのではなく、twitter が提供している twitter entities (詳しくは後述) の情報を利用して、ツイート内容に含まれるハッシュタグや URL の情報を取得しましょう! というのがこの記事の内容です。

続きを読む

Twitter のアイコン画像 (プロフィール画像) を取得する Ruby スクリプト

Twitter のユーザー名 (screen_name) を指定して複数人のプロフィール画像をダウンロードする必要があったので、Rubyスクリプトを書きました。 特に面白くもないですが置いておきます。

プロフィール画像を取得するための Twitter API

プロフィール画像を取得するための API として、以下のものが公開されています。

ユーザー認証なし、アクセス回数制限なしで利用できるものだったので、これを利用しています。 この API は、レスポンスコードとして 302 を返し、実際のプロフィール画像URI へのリダイレクトを促すものです。 よって、今回書いたスクリプトでは、まず、この API を使って実際のプロフィール画像URI を取得し、次にその URI にアクセスして画像をダウンロードする、という 2 段階の処理を行っています。

詳しいことは API のドキュメントを参照してください。

禁止事項 (2011-06-05 追記)

詳しいことは API のドキュメントを参照、と書いていてもちゃんと読まない人も居ると思うので禁止事項について書いておきます。 API ドキュメントには以下のように書いています。

This method must not be used as the image source URL presented to users of your application.

すなわち、この API は画像リソースの URL へのリダイレクトをレスポンスとして返してきますが、その動きを利用して画像リソースの URL の代わりとしてこの API の URL をユーザーに提供するようなことはしてはいけません。 その点はご注意ください。

Twitterプロフィール画像を取得する Ruby スクリプト

以下、実際に書いたスクリプトです。

#! ruby_1.9 -E:utf-8
# encoding: utf-8
# (ruby 1.8 を使っている場合は上の 2 行を消してください)

##
# 設定項目

# アイコンを取得する対象となるユーザーの screen_name の配列
screen_names = [ 'nobuoka', 'qp*******' ]
# アイコン画像を格納するディレクトリ名 (存在するものを指定すること)
icon_dir = 'icons'
# 画像の content_type と拡張子の対応関係 (ここにない content_type の画像を受け取ると例外発生)
content_type_table = {
  'image/jpeg' => '.jpg',
  'image/png'  => '.png',
  'image/gif'  => '.gif'
}

## 
# 処理内容

require 'uri'
require 'net/http'
Net::HTTP.version_1_2 # おまじない

##
# 指定した URI の画像を取得してファイルに出力する
# 
# @param uri_str 取得する画像の URI (String)
# @param file_name 取得した画像を保存する際のファイル名 (String / 拡張子とドットを除く)
# @param output_dir 取得した画像を出力する先のディレクトリ. 'icons' など (String)
# @param content_type_table 取得した画像の content_type と拡張子の関係を表すハッシュ
def get_image_by_uri( uri_str, file_name, output_dir, content_type_table )
  uri = URI.parse( uri_str )
  req = Net::HTTP::Get.new( uri.path )
  res = Net::HTTP.new( uri.host, uri.port ).request( req )
  if res.code == '200'
    ext_str = content_type_table[ res.content_type ]
    if ext_str.nil? then raise "unexpected content type: #{res.content_type}" end
    # ファイルに出力する
    File.open( "#{output_dir}/#{file_name}#{ext_str}", 'wb' ) do |f|
      f.flock( File::LOCK_EX )
      f << res.body
      f.flock( File::LOCK_UN )
    end
  else
    # 画像取得に失敗
    if ext_str.nil? then raise "unexpected response code (image server): #{res.code}" end
  end
end

##
# screen_name の配列を渡すと自動的に画像を取得して出力する
# 
# 各 screen_name に関して, Twitter のアイコン画像取得 API [1] を使用し,
# アイコン画像の URI を取得する. 取得した URI を get_image_by_uri メソッドに投げて
# 画像を取得する. 画像取得に失敗した場合は, そのまま次のユーザーの画像取得に移行する.
# [1] http://dev.twitter.com/doc/get/users/profile_image/:screen_name
# 
# @param screen_names 取得する対象となる twitter アカウントの screen_name (String) の配列
# @param icon_dir 取得した画像を出力する先のディレクトリ. 'icons' など (get_image_by_uri の引数として使う)
# @param content_type_table 取得した画像の content_type と拡張子の関係を表すハッシュ (get_image_by_uri の引数として使う)
def get_icon_images_by_twitter_screen_name( screen_names, icon_dir, content_type_table )
  http = Net::HTTP.new( 'api.twitter.com', 80 )
  screen_names.each do |screen_name|
    begin
      req  = Net::HTTP::Get.new( "/1/users/profile_image/#{screen_name}.xml?size=normal" )
      res  = http.request( req )
      if res.code == '302'
        uri = URI.parse( res['location'] )
        get_image_by_uri( res['location'], screen_name, icon_dir, content_type_table )
      else
        # Twitter API からの戻り値失敗
        raise "unexpected response code (twitter API): #{res.code}"
      end
    rescue => err
      $stdout << "取得失敗 : #{screen_name} (#{err})" << "\n"
    else
      $stdout << "取得成功 : #{screen_name}" << "\n"
    end
  end
end

# 処理実行
get_icon_images_by_twitter_screen_name( screen_names, icon_dir, content_type_table )

Ruby で Twitter の OAuth を使うサンプル

Ruby で OAuth 認証を行うための OAuthSimple というライブラリを公開しました。 よろしければご利用ください。
前の記事 において Twitter OAuth 認証の Request Token を取得するサンプルコードを Ruby で書きましたが、さらに Twitter の OAuth 認証を利用するためのライブラリを Ruby で書いてみたので公開しておきます。

OAuth の勉強する時に参考になればと思います。 OAuth の勉強は OAuth Core 1.0 Revision A を読むのが一番わかりやすいと思うんで、それで勉強しつつ具体例をこのライブラリの中身を見る、という感じで。

VCTwitter::OAuth モジュール

下記が今回作成したライブラリです。

VCTwitter::OAuth モジュールの中には

  • VCTwitter::OAuth::Agent クラス
  • VCTwitter::OAuth::ParameterList クラス

が含まれています。

VCTwitter::OAuth::Agent オブジェクトを使用して Request Token や Access Token の取得、さらに Twitter への OAuth を介した GET メソッド、POST メソッドによるアクセスを行う事ができます。 VCTwitter::OAuth::ParameterList オブジェクトは GET メソッドや POST メソッドでアクセスする時にパラメータを VCTwitter::OAuth::Agent オブジェクトに渡すために使用します。 まあ詳しい動きなどは中身を見てもらえれば。

サンプル

VCTwitter::OAuth モジュールを使用して Access Token を取得するサンプルです。 Application Type は Client を想定してます。 (Application Type が Browser である Consumer Key で以下のサンプルを実行すると多分 "callback_url に oob を指定できるのは Client だけ!" みたいなエラーが出ると思います。)

#! /usr/bin/ruby1.9
# -*- coding: utf-8 -*-

STDOUT.set_encoding( Encoding.locale_charmap )

# vc_twitter_oauth.rb を Load path 以外の場所に置いた場合, 
# vc_twitter_oauth.rb へのパスを $LOAD_PATH に追加する必要がある
#$LOAD_PATH.push( "xxx" )

# vc_twitter_oauth.rb の読み込み
# これで VCTwitter::OAuth::ParameterList と VCTwitter::OAuth::Agent を使えるようになる
require "vc_twitter_oauth"

# Consumer Key と Consumer Secret の設定
consumer_key    = "XXXXXXXXXXXXXXXXXXXX"
consumer_secret = "XXXXXXXXXXXXXXXXXXXX"

# とりあえず VCTwitter::OAuth::Agent オブジェクトを取得
agent = VCTwitter::OAuth::Agent.new( consumer_key, consumer_secret )

# Request Token 取得 (引数 "oob" は callback_url なしの指定)
# 返り値として, req_pair には 2 つの要素を持つ Array オブジェクトが代入される.
# 1 つ目の要素が request_token を表す String, 2 つ目が request_token_secret を表す String.
req_pair = agent.obtain_request_token( "oob" )

# ユーザには Twitter の OAuth 認証ページにアクセスさせ, 暗証番号を入力させる
puts "http://twitter.com/oauth/authorize?" + 
      VCTwitter::OAuth::ParameterList.new( { "oauth_token" => req_pair[0] } ).
      to_query_string() + " にアクセスして暗証番号を取得し, 入力してください."
print "暗証番号 : "
verifier = STDIN.gets().chomp()

# 入力してもらった暗証番号で, Access Token を取得
acc_pair = agent.obtain_access_token( verifier )
p "Access token と Access token secret", acc_pair
token = acc_pair[0]
token_secret = acc_pair[1]

# このまま agent を使用して get や post もできるし,
# 取得した token と token secret を保存しておき, 次回からは
# agent = VCTwitter::OAuth::Agent.new( consumer_key, consumer_secret, token, token_secret )
# という風にインスタンス化できる.

# そのまま get を行う
puts agent.get( "twitter.com", "/statuses/mentions.xml" )

# 新たに VCTwitter::OAuth::Agent オブジェクトを生成し, get を行う
other_agent = VCTwitter::OAuth::Agent.new( consumer_key, consumer_secret, token, token_secret )
puts other_agent.get( "twitter.com", "/statuses/mentions.xml" )

exit 0

追記 【2009-12-11 02:22 JST

このモジュール内では Ruby ライブラリ openssl を使用しているのですが、環境によっては openssl がインストールされていない事もあるようです。

Ubuntu 9.10 (Karmic) の場合について、openssl のインストール方法 を書きましたので、openssl がインストールされていない場合は参考にしてください。

Ruby で Twitter OAuth 認証の Request Token を取得するサンプル

最近 OAuth Core 1.0 Revision A を読んで OAuth の勉強をしてるので、Ruby で実際に動くものを作ってみました。 今回は最初なので Request Token を取得するというもの。 OAuth Core 1.0 Revision A の 6.1 節 Obtaining an Unauthorized Request Token の内容に相当します。

Service Provider は Twitter です。

サンプル

というわけで早速サンプル。 Ruby 1.9 で動作することを確認しています。

#! /usr/bin/ruby1.9
# -*- coding: utf-8 -*-

require "openssl"
require "net/https"

module Twitter
class OAuthTest

# OAuth のパラメータをエンコードするメソッド
def encode_oauth( str )
return str.gsub( /[^a-zA-Z\d\-\._\~]/u ) do |s|
d_str = s.unpack("H*")[0].upcase()
e_str = String.new()
while ( d_str[0,2] != "" ) do
e_str << "%" << d_str[0,2]
d_str[0,2] = ""
end
e_str
end
end

# nonce 用にランダムに文字列生成するメソッド
NONCE_STRING_SOURCE = ("a".."z").to_a() + ("A".."Z").to_a() + (0..9).to_a()
def create_nonce_string()
value = String.new()
16.times do value << NONCE_STRING_SOURCE[rand(NONCE_STRING_SOURCE.size)].to_s() end
return value
end

CALLBACK_URI = "http://sample.net"
CONSUMER_KEY = "XXXXXXXXXXXXXXXXXXXX"
CONSUMER_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

def main()

# パラメータの順番には意味がある (signature 生成のため, パラメータ名の若い順に並べている)
params = String.new()
params << "oauth_callback=" << encode_oauth( CALLBACK_URI )
params << "&"
params << "oauth_consumer_key=" << encode_oauth( CONSUMER_KEY )
params << "&"
params << "oauth_nonce=" << create_nonce_string
params << "&"
params << "oauth_signature_method=HMAC-SHA1"
params << "&"
params << "oauth_timestamp=" << ( Time.now() - Time.utc( 1970, 1, 1 ) ).to_i().to_s()
params << "&"
params << "oauth_version=1.0"

# signature 生成
signature_base_string = "POST&" +
encode_oauth("http://twitter.com/oauth/request_token") +
"&" + encode_oauth( params )
signature_digest = OpenSSL::HMAC::digest( OpenSSL::Digest::SHA1.new(),
CONSUMER_SECRET + "&", signature_base_string )
signature = [signature_digest].pack("m").gsub!( /\n/u, "" )

# パラメータに signature 追加
params << "&"
params << "oauth_signature=" << encode_oauth( signature )

# Request Token の取得
http = Net::HTTP.new( "twitter.com" )
header = { "Content-type" => "application/x-www-form-urlencoded" }
res = http.post( "/oauth/request_token", params, header )
if ( res.code == "200" ) then
# 取得成功
puts res.body
else
# 取得失敗
raise Exception.new( "取得失敗" )
end

end

end
end

Twitter::OAuthTest.new().main()

メモ

  • Twitter は Signature method として HMAC-SHA1 のみ利用可能な模様
  • 今回はパラメータの送信に HTTP Post メソッドを使用したが、HTTP Authorization header や GET メソッドを使用可能なのかどうかは未検証
  • Request Token の取得には HTTP Post メソッドを使用するのが推奨 (RECOMMEND) されている (cf. 6.1.1 節)

追記

Twitter OAuth のための Ruby ライブラリ も公開してみましたので、併せて参考にしてください。 [2009-11-15 04:19]

Ruby から Twitter API を使用するサンプル (SSL / Basic 認証)

Twitter の Basic 認証のサポートは既に終了しました。 本記事中で参考になるのは一番最後の 「CA 証明書ファイルの取得方法」 ぐらいだと思います。

Web 上を探すと RubyTwitter API を使用する方法の説明やらサンプルやらが色々ありますが、Basic 認証をするだけで SSL プロトコル (HTTPS 通信) を使っていないものしか見当たりませんでした。 あんまりネットワーク関係のことは詳しくないんですが、パスワードを送っているからには SSL を使った方がいいですよね・・・?

というわけで HTTPS 通信で Ruby から Twitter API を使用するサンプルです。 Ruby 1.9 での動作を確認しています。 また、下記サンプルを動作させるためにはあらかじめ、PEM 形式で保存された Twitter の CA 証明書ファイルを取得する必要があります。 取得方法は後述します。

サンプルコード

Net::HTTP モジュールを使用しています。 詳しいオブジェクトやメソッドの詳細は Ruby リファレンスマニュアルの Net::HTTP の項目 を見てください。

#! /usr/bin/ruby1.9
# -*- coding: utf-8 -*-

require "net/https"

# Twitter のユーザ名
user_name = "XXXXXXXX"
# Twitter のパスワード
password = "XXXXXXXX"
# PEM 形式で保存された Twitter の CA 証明書ファイルのパス
# (あらかじめ Twitter のサーバから取得しておく)
ca_file_path = "./twitter.pem"
# 使用する Twitter API 名 (今回の場合は GET メソッドを使用するものでなければならない)
api_method_name = "/statuses/friends_timeline.xml"
# 取得した XML 文字列を格納するための変数
response_xml = nil


# HTTPS プロトコルを使用し, Basic 認証を使って Twitter API を使用

# Net::HTTP オブジェクト生成
# cf. http://www.ruby-lang.org/ja/man/html/Net_HTTP.html
# cf. http://www.ruby-lang.org/ja/man/html/net_https.html
https = Net::HTTP.new( "twitter.com", "443" )
https.use_ssl = true
https.ca_file = ca_file_path
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
https.verify_depth = 5
# セッション開始
https.start do |h|
# Net::HTTPRequest オブジェクト生成
# cf. http://www.ruby-lang.org/ja/man/html/Net_HTTPRequest.html
req = Net::HTTP::Get.new( api_method_name )
req.basic_auth( user_name, password )
# リクエストを送信し, Net::HTTPResponse オブジェクトを取得
# cf. http://www.ruby-lang.org/ja/man/html/Net_HTTPResponse.html
res = h.request( req )
if ( res.code == "200" ) then
# 取得成功
response_xml = res.body
else
# 取得失敗
raise Exception.new( "取得失敗" )
end
end


# 取得結果の表示
puts response_xml

exit 0

Twitter の CA 証明書ファイルの取得方法

Firefox 3.5 以上 *1 を使用し、Twitter の CA 証明書ファイルを取得する方法を記します。 通常の API を使用する際に使う CA 証明書ファイルは https://api.twitter.com/ から取得し、User Streaming API を使用する際に使う CA 証明書ファイルは https://userstream.twitter.com/ から取得します。

  1. まず、Firefox 3.5 で https://api.twitter.com/ (通常の API 用) または https://userstream.twitter.com/ (User Streaming API 用) に接続する
  2. ブラウザのメニューバーの 「ツール」 → 「ページ情報」 でページ情報を開く
  3. 「セキュリティ」 を選択する
  4. 「証明書を表示」 ボタンを押し、証明書ビューアを開く
  5. 「詳細」 タブを選択
  6. 証明書の階層から 「*.twitter.com」 または 「userstream.twitter.com」 を選択 *2
  7. ウィンドウ下部の 「エクスポート」 ボタンを押し、保存ダイアログを開く
  8. ファイルの種類は 「証明書パスを含む X509 証明書 (PEM)」 を選び、名前を適当につけて保存する

以上です。 保存したファイルが Twitter の CA 証明書ファイルとなります。

*1:Firefox 3.6 でも確認しました。

*2:実際にはどれでも良い