F#+TwitterizerでStreaming
.NETでTwitterAPIを使うライブラリないかなと思っていたら、Twitterizerというものがあるらしい。Streaming APIへの対応も進んでいる模様。
というわけでさっそく使ってみることにしてみた。
わりとざっくり説明を省くので下記書籍を参照のこと。
Twitter API ポケットリファレンス (POCKET REFERENCE)
- 作者: 山本 裕介
- 出版社/メーカー: 技術評論社
- 発売日: 2011/07/15
- メディア: 単行本(ソフトカバー)
- 購入: 3人 クリック: 247回
- この商品を含むブログ (42件) を見る
インストール
Visual Studioの拡張機能の一つであるNuGet Package Managerを利用。
具体的にはプロジェクトを作成した後にPackage Manager Console上で
PM: Install-Package twitterizer PM: Install-Package twitterizer-streaming
というコマンドをたたけば参照設定までやってくれる。NuGetてふ便利。
この方法だと最新の2.3.3がインストールされる模様。
ちなみに対象のフレームワークは.NET Framework 4じゃないとStreamingのほうをきちんと読み込めないんじゃないかな(要確認)。
あとClient ProfileにはSystem.Webがないのでそっちでは使えない、念のため。
UserStreamを利用してみる
とりあえず、自分のタイムラインをコンソール上にごりごり表示してみよう。
open System open Twitterizer open Twitterizer.Streaming let userAgent = "FsStreamViewer" let token = new OAuthTokens() let settingToken (token:OAuthTokens) = token.set_ConsumerKey("**") token.set_ConsumerSecret("**") token.set_AccessToken("**") token.set_AccessTokenSecret("**") let startView token = settingToken token let opts = new StreamOptions() use stream = new TwitterStream(token, userAgent, opts) let disconnected = ref false let stCreatedCallback = new StatusCreatedCallback (fun stat -> Console.WriteLine stat.Text ) let stStreamStoppedCallback = new StreamStoppedCallback (fun _ -> disconnected := true) stream.StartUserStream(null, stStreamStoppedCallback, stCreatedCallback, null, null, null) |> ignore while !disconnected = false do () [<EntryPoint>] let main _ = startView token 0
OAuthTokensの各種プロパティがF#からだと見えないのでset_Hogehogeメソッドで設定。
2.3.3からTwitterStream.StartUserStreamにデリゲートを渡す方式になったみたい。それ以前のバージョンではイベントを登録する方式だったはず。まぁ、引数7個は面倒です…ということで今回は最低限のものだけ突っ込むことに。それにしてもやけにヌルヌルしてる。
実行してみるとコンソール上に自分のタイムラインが順次表示されていくと思う。
trackを指定する
なんとなくtrackを指定してみることにする。
(* 略 *) let rec addTracks (opts:StreamOptions) = function | x::xs -> opts.Track.Add x addTrack opts xs | [] -> () let startView token trackList = settingToken token let opts = new StreamOptions() addTracks opts trackList (* 略 *) [<EntryPoint>] let main _ = startView token ["test"] 0
addTracksにキーワードのリストを渡してまとめて登録。
実行して自分のタイムライン以外にもtrackで指定した単語を含むツイートが表示されていれば成功。
PublicStreamを表示させたい
こうなるとStreamed Tweetのひとつ、filterを使ってpublicなツイートを取得したくなるよね。ハッシュタグとか。
というわけでStartUserSreamをStartPublicStreamに差し替える…だけで済むなら話は早かったのだが…。
Streaming API turning SSL only on September 29th | Twitter Blogs
要するにhttpではなくhttps使ってねと。
それでですね、Twitterizerさんはまだ対応されていないのです。しかもハードコーディングされているみたいなのでどうしようもない。しかも2.3.3はまだソースコードが公開されていないぽい。
仕方がないのでバージョンがちょっと違うけど
の200行〜を眺めてみる。
短い。これなら自力で同様の関数を作れるのでは?
さっそくやってみましょう。
let startMyPublicStream (stream:TwitterStream) stopped created = let setFieldData name data = let field = stream.GetType().GetField(name, BindingFlags.Instance ||| BindingFlags.NonPublic) field.SetValue(stream, data) let builder = new WebRequestBuilder(new Uri("https://stream.twitter.com/1/statuses/filter.json"), HTTPVerb.POST, stream.Tokens, true, userAgent) let prepareStreamOptions = stream.GetType().GetMethod("PrepareStreamOptions", BindingFlags.Instance ||| BindingFlags.NonPublic) prepareStreamOptions.Invoke(stream, [|builder|]) |> ignore let request = builder.PrepareRequest() setFieldData "streamStoppedCallback" stopped setFieldData "statusCreatedCallback" created setFieldData "stopReceived" false let StreamCallback = stream.GetType().GetMethod("StreamCallback", BindingFlags.Instance ||| BindingFlags.NonPublic) let callback = new AsyncCallback (fun result -> StreamCallback.Invoke(stream, [|result|]) |> ignore) request.BeginGetResponse(callback, request)
スーパーリフレクションタイム。デリゲート登録部分は今回は使うやつ以外はしょってます。
これにあわせてstartViewやmainをちょこちょこ変更して実行。表示されれば問題なし(と思うことにする)。
全ソースコード
open System open System.Net open System.Reflection open Twitterizer open Twitterizer.Streaming let userAgent = "FsSreamViewer" let token = new OAuthTokens() let settingToken (token:OAuthTokens) = token.set_ConsumerKey("**") token.set_ConsumerSecret("**") token.set_AccessToken("**") token.set_AccessTokenSecret("**") let startMyPublicStream (stream:TwitterStream) stopped created = let setFieldData name data = let field = stream.GetType().GetField(name, BindingFlags.Instance ||| BindingFlags.NonPublic) field.SetValue(stream, data) let builder = new WebRequestBuilder(new Uri("https://stream.twitter.com/1/statuses/filter.json"), HTTPVerb.POST, stream.Tokens, true, userAgent) let prepareStreamOptions = stream.GetType().GetMethod("PrepareStreamOptions", BindingFlags.Instance ||| BindingFlags.NonPublic) prepareStreamOptions.Invoke(stream, [|builder|]) |> ignore let request = builder.PrepareRequest() setFieldData "streamStoppedCallback" stopped setFieldData "statusCreatedCallback" created setFieldData "stopReceived" false let StreamCallback = stream.GetType().GetMethod("StreamCallback", BindingFlags.Instance ||| BindingFlags.NonPublic) let callback = new AsyncCallback (fun result -> StreamCallback.Invoke(stream, [|result|]) |> ignore) request.BeginGetResponse(callback, request) let rec addTracks (opts:StreamOptions) = function | x::xs -> opts.Track.Add x addTracks opts xs | [] -> () let startView token streamMode trackList = settingToken token let opts = new StreamOptions() addTracks opts trackList use stream = new TwitterStream(token, userAgent, opts) let disconnected = ref false let stCreatedCallback = new StatusCreatedCallback (fun stat -> Console.WriteLine stat.Text ) let stStreamStoppedCallback = new StreamStoppedCallback (fun _ -> disconnected := true) streamMode stream stStreamStoppedCallback stCreatedCallback |> ignore while !disconnected = false do () (* Streaming APIがSSLのみ対応となったためtwitterizer.Streaming.TwitterStream.StartPublicStream内でエラーが発生する let publicStream (stream:TwitterStream) stopped created = stream.StartPublicStream(stopped, created, null, null) *) (* リフレクション多用による自作StartPublicStream *) let publicStream stream stopped created = startMyPublicStream stream stopped created let userStream (stream:TwitterStream) stopped created = stream.StartUserStream(null, stopped, created, null, null, null, null) [<EntryPoint>] let main _ = startView token publicStream ["test"] 0
結論
早く修正されないかな。
まぁでも、F#F#できたので個人的には満足でふ。
というか寝不足でまた命名規則が怪しいなぁ…