【Ruby】Tumblr Clientを使って記事一覧を取得する
RubyでTumblrのAPIを使用するのはTumblr Clientを使用するのが一番簡単みたいです。
記事投稿のサンプルはネットに色々転がってるんですが、全記事を取得するサンプルは見当たらなかったのでメモ代わりに載せておきます。
Tumblr Clientを使用するための準備
とりあえずGemをもらいます。GitHubにも書いてありますが一応。
gem install tumblr_client
コマンドプロンプトなりコンソールなりターミナルから「tumblr」と入力するとirbが起動してCUIでTumblrのデータをいじることが出来ますが、今回はライブラリとして使うのでそのための準備をします。
これもGitHubに書いてあるんですが、ConfigにOauth認証用のキーを突っ込みます。
require "tumblr_client" Tumblr.configure {|config| config.consumer_key = "" config.consumer_secret = "" config.oauth_token = "" config.oauth_token_secret = "" }
見ての通りきちんとOauth認証を経由してAccessTokenを取得する必要があるんですが、その辺はOauth Gemを使うといいよ、とのことです。丸投げかいな。
自分だけが使えればいいのであればAPI Consoleで認証すると「Show keysAPI」でどっちも貰えます。当たり前ですが、Rubyに限らずどんな言語からもこれでアクセス出来るので、貰っておいて損はありません。
実際にメソッドを投げてみる
このライブラリはTumblrのAPIをかなり忠実に…というか、ソースを見ると引数で渡したハッシュをそのままapi.tumblr.com/v2/blog/xxxx/yyyy?にクエリとしてくっつけています。
yyyyにあたる部分がメソッド名になっている、と考えれば大丈夫っぽいです。xxxxは「user」かbase-hostnameになっているんですが、base-hostnameが必要な場合は第一引数になってるみたいですね。
返り値もAPIを叩くと返ってくるjsonをとりあえずハッシュにしてみただけのようです。(一応ステータスコードを見たりしてる節はあるけど)
ま、要はjavascriptで書いてるようなもんだと思えばそれでよさそうです。Tumblrから返ってくるjsonは何らかのインターフェースやクラスにマッピングするのが非常に辛いところがあるので、これぐらいアバウトにやってくれた方が却ってありがたいのかもしれません。
とりあえずこんな感じに使えます。
require "tumblr_client" Tumblr.configure {|config| config.consumer_key = "" config.consumer_secret = "" config.oauth_token = "" config.oauth_token_secret = "" } client = Tumblr::Client.new client.post("outofmem.tumblr.com", :type=>"text", :limit=>20, :offset=>0)
上記の例だとTextの取得になります。postの引数は前述した通り、base-hostnameとpostメソッドで投げられるクエリのハッシュです。
返ってくるjsonは「Textの取得」にある例の「response」以下のjson(ハッシュ)です。なので、実際に投稿したデータを取得するにはこんな風にしなきゃいけません。
r = client.post("outofmem.tumblr.com", :type=>"text", :limit=>20, :offset=>0) r["posts"].each{|x| puts "タイトル:#{x["title"]}" }
取得ではなく投稿に関しても恐らく同じ法則でいけると思います。(試してない)
全件取得するコード
async_task.rb及びAsyncTaskクラスに関しては昨日書いた記事を読んでみてください。
HTTP通信もI/O処理だからなのか、思った以上に高速化できました。
$:.unshift File.dirname(__FILE__) require "async_task.rb" require "tumblr_client" class TumblrReader attr_accessor:limit attr_reader:is_end def initialize(type="text", limit=20) Tumblr.configure {|config| config.consumer_key = "" config.consumer_secret = "" config.oauth_token = "" config.oauth_token_secret = "" } @client = Tumblr::Client.new @domain = "outofmem.tumblr.com" @type = type @limit = limit @offset = 0 @total_posts = 0 @type_info = {@type => {:offset => @offset, :total_posts => @total_posts}} end def change_type(new_type) # 変更前のtypeのoffsetとtotal_postsを保存しておく @type_info[@type][:offset] = @offset @type_info[@type][:total_posts] = @total_posts @type = new_type if !@type_info.key?(@type) then @offset = 0 @total_posts = 0 @type_info[@type] = {:offset => @offset, :total_posts => @total_posts} @is_end = false else @offset = @type_info[@type][:offset] @total_posts = @type_info[@type][:total_posts] @is_end = @total_posts != 0 && @offset >= @total_posts end end def get_posts_async() if @is_end then return Array.new end # 初回時はtotal_postsを取得する必要がある if @total_posts == 0 then r = @client.posts(@domain, :type => @type, :limit => @limit, :offset => 0); @offset += @limit @total_posts = r["total_posts"] @is_end = @offset >= @total_posts return AsyncTask.new(lambda{|x| return x }, r["posts"]).start else return AsyncTask.new(lambda{ if @is_end then return Array.new end offset = @offset @offset += @limit @is_end = @offset >= @total_posts return @client.posts(@domain, :type => @type, :limit => @limit, :offset => offset)["posts"] }).start end end end
こんな感じに呼び出します。
tr = TumblrReader.new tasks = Array.new while(!tr.is_end) do tasks.push(tr.get_posts_async().continue{|t| t.result.each {|x| # TODO:Tumblrのデータでなにかする } }) end tasks.each{|t| t.wait }
まとめ
なーんかコードがあんまり洗練されてない感じがしますが、いっぱい書いていくうちに垢抜けていくでしょう。きっと。