めも帖

「めも帖」代わりにダラダラと書いていったり、めもしたりしているだけです。

GoogleAppEngineでtwitterAPIをOAuth認証で使う(1)

twitter APIBASIC認証を使うのが6月30日までに決まったそうで。お仕事でtwitterAPIを使ったことがありますが、BASIC認証のままでして。これからはOAuth認証だよ、ということなので試してみよう、と思いました。そうおもっただけならいいんですが、なぜかGoogleAppEngineで試してみる結果に...。

アカウントを用意する

テスト用のアカウントを用意しました。外部アプリケーションの設定(http://twitter.com/apps)をします。すると、

  • Consumer key
  • Consumer secret

というのが設定されます。ええと、ここら辺は「ASCII.jp:ゼロから分かる、GAE&Twitter API開発の始め方|Twitter&Google App Engineで始めるWebプログラミング入門」で。
このあたりで、いろいろと種類があるのがわかりにくい。

ライブラリ

ASCII.jp:サンプルコードで分かるGAE&Twitter API開発|Twitter&Google App Engineで始めるWebプログラミング入門」見てインストール。
simple_cookieと、oauthのライブラリを入れました。ちょっと意外だったんですけれど、simplejsonって、djangoに入っていたのか...
pythonって、ライブラリーはどこらへんにまとまっているのかが、よくわからず...。PerlcpanPHPpearと並ぶような整理されたのがわかるといいなあ(あるのかもしれないけれど)

main.py

  • これでlocalhostでも動きます
  • webappというフレームワークを使っています。GoogleAppEngineに標準で使えるフレームワークの一つ
    • 簡単なフレームワークということらしいのです
    • main()にてURLのマッピングをしているのですが、一つ一つマッピングするのは面倒な気がする
    • URLマッピングで、(.*)でマッチしたところが、modeになります
  • 処理の流れは、http://localhost:8080/loginで、ログインと認証処理。その後、http://localhost:8080/に戻ります。すると、自分のタイムラインが表示されます
  • 表示にはwebappのテンプレートエンジンを使っています
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext.webapp import template

import oauth
from simple_cookie import Cookies
from django.utils import simplejson

CONSUMER_KEY       = ''
CONSUMER_SECRET    = ''
COOKIE_EXPIRE_TIME = '300'
TIMELINE_COUNT     = '30'

class MainHandler(webapp.RequestHandler):
	def get(self, mode=""):
		callback_url = "%s/verify" % self.request.host_url
		client = oauth.TwitterClient(CONSUMER_KEY, CONSUMER_SECRET,callback_url)
		cookie = Cookies(self, max_age=COOKIE_EXPIRE_TIME)

		if mode == '':
			param = {'count': TIMELINE_COUNT}
			timeline_url = "http://api.twitter.com/1/statuses/home_timeline.json"
			response = client.make_request(url=timeline_url,token=cookie["user_token"],secret=cookie["user_secret"],additional_params=param)
			results = simplejson.loads(response.content)

			View.layout['content'] = View.view_dir + 'index.html'

			params = {'layout':View.layout, 'datas':results}

			filepath = os.path.join(os.path.dirname(__file__), 'layouts', View.layout_file)
			html = template.render(filepath, params)
			self.response.out.write(html)

		if mode == 'login':
			self.redirect(client.get_authorization_url())

		if mode == 'logout':
			cookie.delete_cookie("user_token")
			cookie.delete_cookie("user_secret")
			cookie.delete_cookie("screen_name")

		if mode == "verify":
			#VerityAuth(self, client, cookie)
			auth_token = self.request.get("oauth_token")
			auth_verifier = self.request.get("oauth_verifier")
			user_info = client.get_user_info(auth_token, auth_verifier=auth_verifier)
			
			cookie["user_token"]  = user_info["token"]
			cookie["user_secret"] = user_info["secret"]
			cookie["screen_name"] = user_info["username"]
			
			self.redirect('/')

class View:
	layout_file = 'layout.html'
	view_dir    = '../views/'
	layout = {
		'title':'New',
		'header':'header.html',
		'footer':'footer.html',
	}

def main():
	application = webapp.WSGIApplication(
				[
					('/(.*)', MainHandler)
				], debug=True)
	wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
	main()
else:
	print 'error'

テンプレート

  • views/index.html
<table class="data">
	{% for data in datas %}
	<tr>
		<td>{{ data.id }}</td>
		<td>{{ data.user.screen_name }}<img src="{{ data.user.profile_image_url }}" /><br />{{ data.text }}</td>
		<td>{{ data.created_at }}</td>
		<td>{{ data.source }}</td>
	</tr>
	{% endfor %}
</table>
  • layouts/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
	<title>{{ layout.title }}</title>
</head>
<body>
{% include layout.header %}	
{% include layout.content %}	
{% include layout.footer %}	
</body>
</html>
  • laytous/footer.html
<div>footer</div>
  • layouts/header.html
<div>header</div>