※注意※
これは専門的なエントリです。
ムダに長いです。しかもtwitter APIわからないと面白くないです。

ですので、いそがしい方は適当に流し読みし、
ブコメには「ui_nyanかねかえせ」とだけ入れておく
たぶんだいたいあってるので非常に便利かと思います。

user streamがやってきた

4月19日からtwitterより新しいAPIである「Chirp user streams(通称user stream)」がテスト公開されてます。
これは自分のタイムラインを見るAPIで、仕様にしたがってコマンドを叩くと
すごい勢いでみんなのツイートがべろべろ流れてきます。

いままでのtwitterのAPIと違うのは、ツイートの反映がほぼリアルタイムな点で、
誰かがツイートするとそれが一瞬で自分のタイムラインに飛び込んできます。

※他にも公開されてるStreaming APIはありますが、user streamだけやたらに早いです

これまでのtwitterって「リロードしてTL読んでリロードしてTL読んで・・・」って感じだったんですが、
user streamsはもうリアルタイムに飛んでくるツイートをガンガン読んでいくようなかんじ。
やばい!超マストなう!

これ使って何かして遊びたいなぁ・・・

と思ってたら面白いものをみつけました

極上ロールなう

夜食のラーメンサラダを買いにセブン某イレブンへ行ったとき、あるPOPが目に入りました。

セブン-イレブン 「3つのヒミツ!極上ロール」発売記念キャンペーン on twitter

3つのヒミツ!極上ロール (gokujo_roll) on Twitter

公式アカウントをFollowして指定されたハッシュタグをつぶやくと賞品ゲット!
というよくある感じの懸賞なんですが、レギュレーションをよく読むと

秘密のハッシュタグを公開後、先 着 順の上位10名に賞品を贈呈する

となってます。

「こんなの明らかにBOT大勝利じゃないか・・・
さらにuser streams使えばコンマ秒でハッシュタグをツイート可能だし、
従来型のBOTを出し抜くことだって・・・」

応募要綱を何度か見返しましたが、「BOTなどを利用しての自動処理はお断りです」みたいなルールはどこにも書いてありませんでした。
※2010/04/27追記 26日午前、応募要綱に「APIなどのプログラムによる投稿の禁止」が追加されたようです。

これはBOT作るしかないですね。

つくった

さっそくC# 2008 の無料版を使ってコードを書きました(ラーメンサラダ噛みながら)
.netはそのままだとJSONを解釈できないのでJson.netを使ってます。

処理の流れですが、chirpstream.twitter.com にリクエスト投げてJSON形式のデータを読み続け、
ターゲット(@gokujo_roll)がハッシュタグをつぶやいたら、ハッシュタグをオウム返しします。
実行後はフトンかぶって寝てるだけでBOTが勝手に懸賞に応募してくれるというわけ。

ただ単にオウム返ししただけでは応募条件を満たさないので、
あらかじめ応募文を20個作って、それをランダムにつぶやくようにしました。
懸賞が2つあるので、応募文のパターンも2種類(20×2で40個)用意しています。
デバッグ込みでだいたい2時間で完成。

ソースはこんな感じ。(重要そうなとこだけ抜粋)

private void Main()
{
    NetworkCredential creds = new NetworkCredential(UserName, Password);
LOOP:
    var wr = (HttpWebRequest)HttpWebRequest.Create(StreamApi);
    
    wr.Method = "POST";
    wr.KeepAlive = true;
    wr.ContentType = "application/x-www-form-urlencoded";
    Byte[] pst = Encoding.ASCII.GetBytes("");
    wr.ContentLength = pst.Length;
    wr.Credentials = creds;

    using (var stream = wr.GetRequestStream())
    {
        stream.Write(pst, 0, pst.Length);
        using (var res = wr.GetResponse())
        using (StreamReader reader = new StreamReader(res.GetResponseStream()))
        {
            try
            {
                while (true)
                {
                    String str = "";
                    while (!reader.EndOfStream)
                    {
                    var s = reader.ReadLine();
                    str = s.Replace("\r","");
                        if (str.Length > 0)
                        {
                            try
                            {
                                JObject json = JObject.Parse(str);
                                if (str.IndexOf("{\"text") > -1)
                                {
                                    setMessage((string)json["user"]["screen_name"] + " > " + (string)json["text"]);
                                    var postuser = (string)json["user"]["screen_name"];

                                    MatchCollection mc = getTwitterHashTags((string)json["text"]);
                                    if (mc.Count > 0 && postuser == targetName)
                                    {
                                        setMessage("【!】ハッシュタグ発見!");
                                        for (int i = 0; i < mc.Count; i++)
                                        {
                                            var tag = mc[i].Value;
                                            setMessage(" →タグ " + tag);
                                           //キャンペーン2のタグに反応する
                                            if (tag.IndexOf("#gokujo_") > -1)
                                            {
                                                var message = getRandomMessage(list_kansou) + " " + tag;
                                                updateTweet(message);
                                            }
                                            else
                                            {
                                                //キャンペーン1のタグに反応する
                                                if (tag.IndexOf("#gokujo2") > -1)
                                                {
                                                    var message = getRandomMessage(list_entry) + " " + tag;
                                                    updateTweet(message);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception e)
                            {
                                setMessage("【!】例外" + e);
                            }
                        }
                    }
                }
            }
            catch (IOException e)
            {
                setMessage("【!】例外" + e);
            }
            finally
            {
                wr.Abort();
            }
        }
    }
    goto LOOP;
}

※setMessageとかupdateTweetとかは勝手に実装してください。

実行画面

※アプリケーション名に力を入れた。

で、どうなった?

どうやら寝てる間にハッシュタグ発表があったようです。さっそくtwitterのログを確認してみましょう。

こんなの圧勝するに決まってるwwwww

2位以下を7秒ほど引き離しての完全勝利ですおめでとうございました。
ツイートのID番号から類推するに、ハッシュタグ発表から0.7秒で反応してたようです。
c h i r p s t r e a m 最 強 伝 説

今回は1アカウントでの挑戦でしたが、アカウントを10個とか用意して同時に実行させておけば、
当選発表を自分のアカウントだけで埋め尽くすこともできたでしょう。

※「当選は1人1回まで」と明記されてたので、複数回やっても1個しか懸賞貰えません

twitter懸賞の問題点

  • 「ハッシュタグをつぶやいた人、先着で○○名様」って懸賞は止めたほうがいい
    • 「何が始まるんです?」→『第三次BOT大戦だ』
    • 応募をツイートじゃなくて専用フォームにして、captchaを要求すれば先着順でもどうにかなる?
  • 「ハッシュタグをつぶやいた人(RTした人)、抽選で○○名様」複数アカウント+BOTで刈り取られる
    • 「当選は1人1回まで」として、当選者に個人情報要求すれば1人に全部景品持っていかれるのだけは避けられる

まとめ

人間は訓練されたBOTには絶対勝てない

参考文献


楽天のロールケーキランキングもよろしく!