2014年12月11日木曜日

Pythonを使ってTwitterでOAuthのログインをするためのクラスを作る

TwitterのOAuthでログインできるようにしておくと色々便利なのはAppEngineで経験済みなので,そのためのライブラリを作成してみる.

基本的にはこちらのページを参考にこしらえた.
pythonでoauth認証
事前準備は,
さくらインターネットでPython2.7を使ってTwitterAPIを叩くを参考のこと.
なお,Twitterとの接続に使うのは,python-twitter

まず,
http://syncer.jp/twitter-api-create-application
を参考に,Twitterのアプリを作成しておく.
ただし,アプリ作成の場所が,分かりづらくなったので,直接こちらにアクセスした方がよい.
https://apps.twitter.com/
Twitter社はアプリ作らせる気がないのか?と思うくらい分かりづらい.

このとき,CallBackURLにアプリのCGIのURLを指定しておくことを忘れずに.
後から変えられるけど.

次に,アプリ作成に入る.
まず,sqliteを使うので,oauth.dbというファイルを作っておいて,
$ sqlite3 oauth.db
sqlite> CREATE TABLE oauth (oauth_token text primary key,oauth_token_secret text);
sqlite> CREATE TABLE user (id integer primary key, consumer_key text, consumer_secret text, access_token text, access_token_secret text, screen_name text, image_url text, time datetime);
sqlite> .exit
として,データベースを作成しておく. 次に,TwitterLogin.pyを作成.
ここが今日のハイライト.


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import site
site.addsitedir('/home/username/lib/python')

import os
import cgi
import cgitb
import oauth2 as oauth
import sqlite3
import twitter
import datetime
from Cookie import SimpleCookie
from twitter import TwitterError

request_token_url = 'https://api.twitter.com/oauth/request_token'
access_token_url = 'https://api.twitter.com/oauth/access_token'
authenticate_url = 'https://api.twitter.com/oauth/authorize'

class TwitterLogin:
    def __init__(self, db_name, consumer_key, consumer_secret):
        self.db_name = db_name
        self.consumer_key = consumer_key
        self.consumer_secret = consumer_secret

    def getOAuth(self):
        consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
        client = oauth.Client(consumer)
        # reqest_token    
        resp, content = client.request(request_token_url, 'GET')
        request_token = dict(self.parse_qsl(content))
       
        #call_back="http://torix.sakura.ne.jp/twitter/signin.cgi"
   
        # request_token    
        con = sqlite3.connect(self.db_name)
        con.execute(u'insert into oauth values (?, ?)', (request_token['oauth_token'], request_token['oauth_token_secret']))
        con.commit()
        con.close()

        #
        url = '%s?oauth_token=%s' % (authenticate_url, request_token['oauth_token'])
        print 'Content-type: text/html; charset: utf-8\n\n'
        print
        print '' % url


    def getApi(self):
        access_token, access_token_secret, screen_name, image_url = self.loadAccessToken()
        self.screen_name = screen_name
        self.image_url = image_url
        if not access_token == None:
            # Cookieを使った認証
            api = twitter.Api(consumer_key=self.consumer_key,
                              consumer_secret=self.consumer_secret,
                              access_token_key=access_token,
                              access_token_secret=access_token_secret)
            return api
        elif 'QUERY_STRING' in os.environ:
            # CallBackを使った認証
            query = cgi.parse_qs(os.environ['QUERY_STRING'])
            if len(query) == 0:
                return None
            # oauth_token_secret を取得
            con = sqlite3.connect(self.db_name)
            oauth_token_secret = con.execute(
                u'select oauth_token_secret from oauth where oauth_token = ?'
                , [query['oauth_token'][0]]).fetchone()[0]
            con.close()

            if oauth_token_secret == None:
                return None

            # Access_token と access_token_secret を取得
            consumer = oauth.Consumer(key=self.consumer_key, secret=self.consumer_secret)
            token = oauth.Token(query['oauth_token'][0], query['oauth_verifier'][0])
            client = oauth.Client(consumer, token)
            resp, content = client.request(
                access_token_url, "POST", body="oauth_verifier=%s" % query['oauth_verifier'][0])
            access_token = dict(self.parse_qsl(content))

            # access_tokenの保存
            api = twitter.Api(consumer_key=self.consumer_key,
                        consumer_secret=self.consumer_secret,
                        access_token_key=access_token['oauth_token'],
                        access_token_secret=access_token['oauth_token_secret'])
            try:
                user = api.VerifyCredentials()
                uid = user.GetId()
                self.screen_name = user.screen_name
                self.image_url = user.profile_image_url
                self.saveAccessToken(uid, access_token['oauth_token'], access_token['oauth_token_secret'], self.screen_name, self.image_url)
            except TwitterError:
                return None
            return api
        else:
            return None

    #save access token to db
    def saveAccessToken(self, uid, access_token, access_token_secret, screen_name, image_url):

        con = sqlite3.connect(self.db_name)
        c = con.cursor()
        #print datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        c.execute(u"replace into user (id, consumer_key, consumer_secret, access_token, access_token_secret, screen_name, image_url, time) values (?, ?, ?, ?, ?, ?, ?, datetime(?))", [uid, self.consumer_key, self.consumer_secret, access_token, access_token_secret, screen_name, image_url, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")])
        con.commit()
        c.close()

        ck = SimpleCookie()
        ck.load(os.environ.get("HTTP_COOKIE",""))
        ck["id"] = uid
        ck["token"] = access_token
       
        now_date = datetime.datetime.now()
        expires = now_date
        expires = expires + datetime.timedelta(seconds=+(60*60*24))
        expires = expires.strftime('%a, %d-%b-%Y %H:%M:%S %Z')
           
        ck["id"]["expires"] = expires
        ck["token"]["expires"] = expires
        print ck.output(["id", "expires"])
        print ck.output(["token", "expires"])

    #load data from data base
    def loadAccessToken(self):
        ck = SimpleCookie()
        ck.load(os.environ.get("HTTP_COOKIE",""))
        if ck.has_key("id") and ck.has_key("token"):
            id = int(ck["id"].value)
            token = ck["token"].value
            access_token = None

            con = sqlite3.connect(self.db_name)
            c = con.cursor()
            c.execute(u'select access_token, access_token_secret, screen_name, image_url from user where id=%d'% id)
            for row in c:
                access_token = row[0]
                access_token_secret = row[1]
                self.screen_name = row[2]
                self.image_url = row[3]
            con.close()

            if not access_token == None and access_token == token:
                return access_token, access_token_secret, self.screen_name, self.image_url
            else:
                return None, None, None, None
        else:
            return None, None, None, None



    def parse_qsl(url):
        param = {}
        for i in url.split('&'):
            _p = i.split('=')
            param.update({_p[0]: _p[1]})
        return param

    def parse_qsl(self, url):
        param = {}
        for i in url.split('&'):
            _p = i.split('=')
            param.update({_p[0]: _p[1]})
        return param

getOAuthで,OAuth認証を行うページに飛ばして,callbackで戻ってきたときにgetApiで捕まえる.
それ以降は,UserIDとAccessTokenをCookieに保存することでSession管理をすることにする.
本当は独自のsessionIDを発行した方がいいのかもしれない.

次に,実際にログインするところを作ってみよう. 使い方は以下の通り.
なお,consumer_keyとconsumer_secretはTwitterで登録したアプリのものをつかう.
callback urlがhttp://xxx.xx.xx/twitter/login.cgi
そのURLでアクセスできるcgiを以下のように作成する.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import site
site.addsitedir('/home/username/lib/python')
from TwitterLogin import TwitterLogin

consumer_key = 'consumer_key'
consumer_secret = 'consumer_secret'

if __name__ == '__main__':
    twitter = TwitterLogin('oauth.db', consumer_key, consumer_secret)
    api = twitter.getApi()
    print 'Content-type: text/html; charset: utf-8\n\n'
    if api == None:
        print 'Fail to login'
    else:
        user = api.VerifyCredentials()
        print user.screen_name

これで,認証したアカウントのスクリーンネームが表示されるはず.

APIの使い方は,以下を参照.
https://python-twitter.googlecode.com/hg/doc/twitter.html

色々問題はあるかもしれないけど,とりあえず動いたので,満足.




2014年12月8日月曜日

さくらインターネットでPython2.7を使ってTwitterAPIを叩く

タイトル長いな.
世界の中心で愛を叫ぶみたいになってもうた.

さて,TwitterAPIを使ったツイート収集だけど,最近検索APIで1週間分なら無制限にとれるっぽいことが分かったので,これを使って遊んでみよう計画.

最近Pythonも気になるので,Pythonでさくらサーバ使って遊んでみる.


PythonでTwitterのAPIをたたいてみよう-セットアップ偏
を参考にしてみる.

なお,Twitterとの接続に使うのは,python-twitter

$ setenv PYTHONPATH /home/username/lib/python

$ wget --no-check-certificate github.com/simplegeo/python-oauth2/archive/master.zip
$ unzip master.zip
$ cd  python-oauth2-master/
$ ./setup.py install --home=~

$ cd ../
$ rm master.zip
$ wget --no-check-certificate https://github.com/bear/python-twitter/archive/master.zip
$ unzip master.zip
$ cd  python-twitter-master/
$ ./setup.py install --home=~

$ cd ../
$ rm master.zip
$ wget --no-check-certificate https://github.com/jcgregorio/httplib2/archive/master.zip
$ unzip master.zip
$ cd  httplib2-master/
$ ./setup.py install --home=~

$ cd ../
$ rm master.zip
$ wget --no-check-certificate https://pypi.python.org/packages/source/s/simplejson/simplejson-3.6.5.tar.gz
$ tar zxvf simplejson-3.6.5.tar.gz
$ cd simplejson-3.6.5/
$ ./setup.py install --home=~

これで必要なファイルはダウンロード完了.
ここで適当なアプリを作成しておく.

ConsumerKeyとConsumerSecret,AccessToken, AccessTokenSecretを獲得して,
以下のようなcgiを作成.

#!/usr/bin/env python
# -*- coding: utf-8 -*-


#!/usr/bin/env python
# -*- coding: utf-8 -*-


import site
site.addsitedir('/home/username/lib/python')

import sys
import twitter

print ('Content-type: text/html; charset=UTF-8\n\n')

CONSUMER_KEY = ''                             # Consumer Key
CONSUMER_SECRET = ''         # Consumer Secret
ACCESS_TOKEN = '' # Access Token
ACCESS_TOKEN_SECRET = ''         # Accesss Token Secert

api = twitter.Api(consumer_key=CONSUMER_KEY,
                      consumer_secret=CONSUMER_SECRET,
                      access_token_key=ACCESS_TOKEN,
                      access_token_secret=ACCESS_TOKEN_SECRET)


tlAry = api.GetSearch(term="keyword",count=100)
tweetlist=[]
for s in tlAry:
    if not s.text.startswith('RT @'):
        tweetlist.append(s.text)
        print s.text.encode('utf-8')


これで,keywordを含むツイートを取得可能.
ポイントの一つが,
import site
site.addsitedir('/home/username/lib/python')
の部分.
これを書いておかないとライブラリを読みに行ってくれないので注意.
さくらインターネットでは,ライブラリはローカルに置くしかないので,この作業をやらないと,twitterライブラリがimportできません.




2014年12月2日火曜日

Windows7にCDH5.1.3でHadoop・断念編

というわけで,前回のエントリーでHDInsightでHadoopをと思ったけど,
その後どうやってもEclipseでは起動しない.
どうもライブラリその他の関係でうまくいかないようだ.

色々試した結果,EclipsePluginがHadoop2.x系には対応していないと言う結論に.
結局利用可能なのは,Hadoop0.21系まで.

ひとまずHadoop2.x系のPluginがリリースされるまでは,Hadoop0.21系を利用することに.
こちらのエントリーに書いた方法で概ねインストール可能.
変更点は,
hadoop-env.shが
hadoop/bin/hadoop-env.sh
から
hadoop/conf/hadoop-env.sh
へ移動になったことくらい.

結局2年前のHadoopを使うことになるとは.とほほ.