Pusher + Google App EngineでリアルタイムWeb
「WebSocketで目指せ“リアルタイムWeb”!」(http://www.atmarkit.co.jp/fcoding/articles/websocket/02/websocket02b.html)
これ読んで面白そうだと思ったので、とりあえずTwitterのpublic timelineを表示していくWebサイトを作ってみるよ。
Pusherに登録
http://pusherapp.com/
さくっと登録しましょう。
Dashboard→Api accessでapi_id, key, secretが入手できる。
コーディング
サーバーとしてGAEを使用する。Pusherのアーキテクチャとかは上の記事を読んでください。
HTML
<!DOCTYPE html> <head> <title>Pusher Test</title> <link href="/css/main.css" media="screen" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script> <script type="text/javascript" src="http://js.pusherapp.com/1.6/pusher.js" ></script> <script type="text/javascript" src="/js/main.js" ></script> <body> <div id="container"> </div> </body> </head>
function generate(data){ var tweet = '<div class="tweet"><img src="' + data.profile_image_url + '" width="50px" height="50px" alt="photo"/>' + '<a href="http://twitter.com/' + data.screen_name +'">' + data.screen_name + '</a></div>'; tweet = $(tweet).css({ 'background' : 'white', 'border' : '2px solid #999', 'padding' : '5px', 'margin-bottom' : '1px', '-webkit-border-radius' : '10px', '-moz-border-radius' : '10px' }); var text = '<div class="text">' + data.text + '</div>' text = $(text).css({ 'display' : 'inline', 'margin-left' : '10px' }); tweet.append(text); $('#container').prepend(tweet); if ($('.tweet').length >= 15) { $('.tweet:last').remove(); } } $(document).ready(function(){ var pusher = new Pusher('key'); pusher.subscribe('test_channel'); pusher.bind('note-update', function(data) { generate(data); }); });
Python(GAE)
pusherのライブラリとしてpusherとかgea-pusherがあるよ。
今回はpusherを使用。
# -*- coding: utf-8 -*- from google.appengine.ext import webapp from google.appengine.ext import db from google.appengine.ext.webapp import template from google.appengine.ext.webapp.util import run_wsgi_app import tweepy from pusher import Pusher, Channel import os class Tweet(db.Model): id = db.IntegerProperty(required = True) class Main(webapp.RequestHandler): def get(self): path = os.path.join(os.path.dirname(__file__), 'main.html') self.response.out.write(template.render(path, {})) class Trigger(webapp.RequestHandler): def get(self): # 送信済みTweetのid tweeted = [tweet.id for tweet in Tweet.all().fetch(limit = 1000)] app_id = 'app_id' key = 'key' secret = 'secret' pusher = Pusher(app_id, key, secret) name = 'test_channel' channel = Channel(name, pusher) event = 'note-update' public_tweets = tweepy.api.public_timeline() for tweet in public_tweets: if tweet.id not in tweeted: data = {'text' : tweet.text, 'screen_name' : tweet.user.screen_name, 'profile_image_url' : tweet.user.profile_image_url } channel.trigger(event, data) t = Tweet(id = tweet.id) t.put() application = webapp.WSGIApplication([('/twitter', Main), ('/trigger', Trigger)], debug = True) def main(): run_wsgi_app(application) if __name__ == "__main__": main()
デモ:http://ninoseki-lab.appspot.com/twitter
(更新は1分毎)
追記:今(11/15 22:40)ちょっと調子悪いです