やる夫と Python で学ぶ Twitter の OAuth


OAuth 調べてみたら難しくて理解出来なかったので,
Python で標準ライブラリだけで 1 から書いてみました.

     /      \
   /  _ノ  ヽ、_  \
  / o゚((●)) ((●))゚o \  twitter の OAuth 難しいお…
  |     (__人__)'    |
  \     `⌒´     /

       ____
     /⌒  ⌒\
   /( ●)  (●)\
  /::::::⌒(__人__)⌒::::: \   だからやる夫でやるお!
  |     |r┬-|     |
  \      `ー'´     /


Python のサンプルコードを付けていますが,
上から順に読めるようにおもいっきり手続き型で書いています.
コメントで実際の処理の説明を書いています.

Consumer Key と Consumer Secret の入手

        / ̄ ̄\    
      /    u  \      .____    
      |::::::      u |   ./      \  OAuth 出来るようにしたいので
     . |:::::::::::     |  / ⌒   ⌒  \ アクセストークンください
       |:::::::::::u:    |/  (●) (●)   \ 
     .  |::::::::::::::  u  } |    (__人__)     |  
     .  ヽ::::::::::::::    } \   ` ⌒´     _/  
        ヽ::::::::::  ノ   |           \ 
        /:::::::::::: く    | |         |  | 
-―――――|:::::::::::::::: \-―┴┴―――――┴┴――   
         |:::::::::::::::|ヽ、二⌒)   それじゃあ,この画面で登録してくださいね

          ____
       / \  /\ キリッ
.     / (ー)  (ー)\    こんなの簡単だお
    /   ⌒(__人__)⌒ \
    |      |r┬-|    |
     \     `ー'´   /
    ノ            \
  /´               ヽ
 |    l              \
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))



           ___   ━┓
         / ―  \  ┏┛
        /  (●)  \ヽ ・
       /   (⌒  (●) / あれ?? ここに登録しても Consumer Key と Consumer Secret しか
       /      ̄ヽ__) / 手にはいらないお?
.    /´     ___/ 
    |        \
    |        |


というわけで,
http://dev.twitter.com/apps/new
にアクセスして登録すると Consumer Key と Consumer Secret が手に入ります.

リクエストトークンの取得

        / ̄ ̄\    
      /    u  \      .____    
      |::::::      u |   ./      \  Consumer Key と Consumer Secret を手に入れたので
     . |:::::::::::     |  / ⌒   ⌒  \ アクセストークンください
       |:::::::::::u:    |/  (●) (●)   \ 
     .  |::::::::::::::  u  } |    (__人__)     |  
     .  ヽ::::::::::::::    } \   ` ⌒´     _/  
        ヽ::::::::::  ノ   |           \ 
        /:::::::::::: く    | |         |  | 
-―――――|:::::::::::::::: \-―┴┴―――――┴┴――   
         |:::::::::::::::|ヽ、二⌒)   それは,別の窓口(URL)で申請して下さい




      / ̄ ̄ ̄\
    / ─    ─ \ 日本の役所かお!?
   /  (○)  (○)  \ 
   |    (__人__)    |
   \    ` ⌒´.    / 
   /              \




       / ̄ ̄ ̄ \  ホジホジ
     / ―   ― \
    /   (●)  (●)  \ アクセストークン下さい
    |     (__人__)      |
    \   mj |⌒´     /
       〈__ノ
      ノ   ノ




   / ̄ ̄\ 
 /   _ノ  \ 
 |    ( ●)(●) アクセストークンの取得にはリクエストトークンが必要ですので
. |     (__人__) こちらの形式で認証してください
  |     ` ⌒´ノ  
.  |         } 
.  ヽ        } 
   ヽ     ノ        \ 
   /    く  \        \ 
   |     \   \         \ 
    |    |ヽ、二⌒)、          \ 


           ___
       /      \
      /ノ  \   u. \ (ちょ、なんだか面倒臭くなってきてるお)
    / (●)  (●)    \ 
     |   (__人__)    u.   |
     \ u.` ⌒´       /
    ノ            \
  /´               ヽ


というわけで,リクエストトークンの取得です.
Python で書いてみます

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

import time, random, urllib, cgi, hmac, hashlib

consumer_key = 'さっきの画面に出てきたやつ'
consumer_secret = 'さっきの画面に出てきたやつ'

# Request Token は GET で取得
method = 'GET'

# Request Token 取得の URL
request_token_url = 'http://twitter.com/oauth/request_token'

# 必須パラメータを準備
params = {
        "oauth_consumer_key": consumer_key, # WEB で登録した oauth consumer key
        "oauth_signature_method": "HMAC-SHA1", # 暗号のアルゴリズム
        "oauth_timestamp": str(int(time.time())), # unixtime 
        "oauth_nonce": str(random.getrandbits(64)), # ランダム文字列
        "oauth_version": "1.0" # バージョン番号
        }
# パラメータをソートし,URIエンコードした key=value の形にして & で繋げます
params_str = '&'.join(['%s=%s' % (urllib.quote(key, ''),urllib.quote(params[key], ''))
                           for key in sorted(params)])

# メソッド,URIエンコードした URL,上で作ったパラメータ文字列を & で繋げます 
message = '%s&%s&%s' % (method,urllib.quote(request_token_url,''), urllib.quote(params_str,''))

# consumer_secret を元にキーを作成します 
key = "%s&%s" % (consumer_secret, '')

# キーを元に message で hmac を作成します
signature = hmac.new(key, message, hashlib.sha1)

# そのダイジェストを base64 でエンコードし,余計な空白を取り除きます
digest_base64 = signature.digest().encode("base64").strip()

# 作成したダイジェストをパラメータに追加します
params['oauth_signature'] = digest_base64

# 作成したパラメータを GET のパラメータとして追加します
_url = request_token_url+ '?' + urllib.urlencode(params)

# その URL にアクセスし, ResponseBody を読み込みます
result = urllib.urlopen(_url).read()

# パースします
data = cgi.parse_qs(result)

# 取得できました!!
print data
#{'oauth_token_secret': ['xxx'], 'oauth_token': ['xxxx'], 'oauth_callback_confirmed': ['true']}
# oauth_token がリクエストトークン


注意点としては,ここで取得出来た oauth_token,oauth_token_secret は一時的なものだという事です.
この後に出てくるアクセストークンの取得を行なった後は無効になりますので注意してください.

OAuth Verifier の取得

        / ̄ ̄\    
      /    u  \      .____    
      |::::::      u |   ./      \  OAuth Token と OAuth Token Secret を手に入れたので
     . |:::::::::::     |  / ⌒   ⌒  \ アクセストークンください
       |:::::::::::u:    |/  (●) (●)   \ 
     .  |::::::::::::::  u  } |    (__人__)     |  
     .  ヽ::::::::::::::    } \   ` ⌒´     _/  
        ヽ::::::::::  ノ   |           \ 
        /:::::::::::: く    | |         |  | 
-―――――|:::::::::::::::: \-―┴┴―――――┴┴――   
         |:::::::::::::::|ヽ、二⌒)   こちらはリクエストトークンの窓口(URL)ですので,それは別の窓口(URL)で申請して下さい



      / ̄ ̄ ̄\
    / ─    ─ \ またかお!?
   /  (○)  (○)  \ 
   |    (__人__)    |
   \    ` ⌒´.    / 
   /              \




       / ̄ ̄ ̄ \  ホジホジ
     / ―   ― \
    /   (●)  (●)  \ アクセストークン下さい
    |     (__人__)      |
    \   mj |⌒´     /
       〈__ノ
      ノ   ノ



   / ̄ ̄\ 
 /   _ノ  \ 
 |    ( ●)(●) アクセストークンの取得にはユーザに認証してもらって 
. |     (__人__) OAuth Verifier を取得してもらう必要があります
  |     ` ⌒´ノ  
.  |         } 
.  ヽ        } 
   ヽ     ノ        \ 
   /    く  \        \ 
   |     \   \         \ 
    |    |ヽ、二⌒)、          \ 


           ___
       /      \
      /ノ  \   u. \ (ちょ、まだ貰えないのかお)
    / (●)  (●)    \ 
     |   (__人__)    u.   |
     \ u.` ⌒´       /
    ノ            \
  /´               ヽ

というわけで,OAuth Verifier の取得ですが,今回はクライアントとして使いたいので,
単純に先程取得した oauth_token をパラメータに付けてアクセスするだけです.

# さっき取得したデータから oauth_token を取得してひっつける
print 'http://twitter.com/oauth/authorize?oauth_token='+data['oauth_token'][0]


これで表示されたアドレスにブラウザでアクセスし,アプリケーションからの使用を許可すると
画面に OAuth Verifier が表示されます.

アクセストークンの取得

       べ,別の窓口(URL)になります…
         |/         γ ⌒⌒ヽ
   / ̄ ̄\           ( ( ヽ ) ノ
 /_ノ     \     (⌒) 三  ノ 从 ゝ
 ( ●)( ●)  ヽ   三/ | ニ  ____     (⌒)  
. | (__人__) u  }   |  |   /\  / ) し   / |  ミ 
  | ` ⌒´    ノ   !   、 /(○ )::(○ )⌒\/ | ミ
.  |         }    \./:::::::(_人_)::::::::  i'   |  OAuth Verifier 手に入れたから
.  ヽ        }      |     )ww)     |  |      いい加減アクセストークン教えてくれお!
   ヽ     ノ   ヘ   \    `ー"      ノ
   /    く 、_/っ/      \ .    .   \
   |     \--一''           \
    |    |ヽ、二⌒)、          \



       ____
     /ノ   ヽ、_\  一体どういうことだお!!!!
   /( ○)}liil{(○)\  どんだけ手続踏ませるんだお!!!!
  /    (__人__)   \ アクセストークン手に入れるだけで
  |   ヽ |!!il|!|!l| /   |  日本の役所以上にたらいまわしじゃないかお!!
  \    |ェェェェ|     / 





       / ̄ ̄ ̄ \  ホジホジ
     / ―   ― \
    /   (●)  (●)  \ って怒ってもしょうがないのは役所で慣れてるお
    |     (__人__)      |
    \   mj |⌒´     /
       〈__ノ
      ノ   ノ




     |┃    
 ガラッ. |┃  
     |┃  ノ//   ./ ̄ ̄ ̄ \
     |┃三    /  \   / \   OAuth Verifier 手に入れたから
     |┃     /  (●)  (●)  \  アクセストークンくれお
     |┃     |    (__人__)     |
     |┃三   \    ` ⌒´    /
     |┃三   / ̄ ̄ ̄ ̄ ̄ ̄ ̄ \





   / ̄ ̄\      |┃┃
 /   _ノ  \  三 .|┃┃
 |    ( ●)(●)   ..|┃┃
. |     (__人__)  . |┃┃
  |     ` ⌒´ノ   |┃┃
.  |         }  三 |┃┃
.  ヽ        }    |┃┃ピシャッ!
   ヽ     ノ三   ..|┃┃
   /    く  \   .|┃┃
   |     \   三  |┃┃
    |    |ヽ、二⌒) |┃┃






  |┃    ガラッ    ____
  |┃ 三      /u     \
  |┃        /   \, 、/  \   
  |┃ .      /  ( ●)  (● ) \
  |┃ 三   |   '" (__人__)"' u | < 閉めないでくれおっ!
  |┃       \    ` ⌒ ´    /
  |┃        /ゝ    "`   ィ `ヽ.
  |┃ 三   /              \
,⊆ニ´⌒ ̄ ̄"  y           r、  ヽ
⊂二、 ,ノ──-‐'´|              | l"  |
  |┠ '       |              l/'⌒ヾ
  |┃三        |              |ヾ___ソ



         ___ 
       /      \
      /  ::\:::/::::u.\      ./ ̄ ̄\
    /   <●>::::::<●> \   /      .ヽ
     |      (__人__)u.   |  .|      :::::::l
      \    u.` ⌒´   /   |     ::::::::::l
      /⌒ヽ   ー‐   ィヽ    |    :::::::::::::l 
      /   ■  ■  .冊  冊.   { u :::::::::::::::::l  ではこちらへアクセスしてください…
    /, ./  ∨  ヽ (.サ.)(.サ.)  {  ::::::::::::::::/    
    |  .l六-0l六-0l } ソ { } ソ {ヽ  ゝ ::::::::::::/
    ゝ つ=.l==l(.ポ.).(と⌒.ノ   > :::::::::ヽ 
   ̄ ̄ ゙ヽ_ソノノ--ィ ゝ-ヘゝゝノ゙  ̄/ :::::::::::::::::i ̄



       ____ 
     /⌒  ⌒\  
   /( ●)  (●)\  
  /::::::⌒(__人__)⌒:::::\  (お!! やっとアクセストークン貰えそうだお!!!)
  |     |r┬-|     | 
  \      `ー'´     / 


と,いうわけでやっとアクセストークンの取得です.

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

import time, random, urllib, urllib2, cgi, hmac, hashlib

consumer_key = '最初に使ったやつ'
consumer_secret = '最初に使ったやつ'

oauth_token = 'リクエストトークン取得の時に取得した OAuth Token'
oauth_token_secret = 'リクエストトークン取得の時に取得した OAuth Token Secret'
oauth_verifier = 'ブラウザに表示された OAuth Verifier'

# Access Token は GET で取得
method = 'GET'

# Access Token 取得の URL
access_token_url = 'http://twitter.com/oauth/access_token'


# 必須パラメータを準備
params = {
        "oauth_consumer_key": consumer_key, # WEB で登録した oauth consumer key
        "oauth_signature_method": "HMAC-SHA1", # 暗号のアルゴリズム
        "oauth_timestamp": str(int(time.time())), # unixtime 
        "oauth_nonce": str(random.getrandbits(64)), # ランダム文字列
        "oauth_version": "1.0" # バージョン番号
        }
# パラメータに先程取得した値を追加
params['oauth_token'] = oauth_token
params['oauth_verifier'] = oauth_verifier

# パラメータをソートし,URIエンコードした key=value の形にして & で繋げます
params_str = '&'.join(['%s=%s' % (urllib.quote(key, ''),urllib.quote(params[key], ''))
                           for key in sorted(params)])

# メソッド,URIエンコードした URL,上で作ったパラメータ文字列を & で繋げます 
message = '%s&%s&%s' % (method,urllib.quote(access_token_url,''), urllib.quote(params_str,''))

# consumer_secret と oauth_token_secret を元にキーを作成します 
key = "%s&%s" % (consumer_secret, oauth_token_secret)

# キーを元に message で hmac を作成します
signature = hmac.new(key, message, hashlib.sha1)

# そのダイジェストを base64 でエンコードし,余計な空白を取り除きます
digest_base64 = signature.digest().encode("base64").strip()

# 作成したダイジェストをパラメータに追加します
params['oauth_signature'] = digest_base64

# ヘッダに Authorization:OAuth を追加します
opener = urllib2.build_opener()
opener.addheaders = [('Authorization','OAuth')]

# 作成したパラメータを GET のパラメータとして追加します
_url = access_token_url + '?' + urllib.urlencode(params)


# その URL にアクセスし, ResponseBody を読み込みます
result = opener.open(_url).read()

# パースします
data = cgi.parse_qs(result)

# 取得できました!!
print data
#{'oauth_token_secret': ['xxxx'], 'user_id': ['xxxx'], 'oauth_token': ['xxxx'], 'screen_name': ['yaruo']}
# oauth_token がアクセストークン


成功すると,アクセストークンの他にもユーザ名などもわかります.
リクエストトークンのところでも説明しましたが,
ここで出た oauth_token と oauth_token_secret を保存しわすれると,
もう一度リクエストトークンの取得からになるので注意してください.

つまり,このプログラムを連続で実行すると 2 度目以降はエラーになります.

アクセストークンを使って実際に Twitter にアクセスしてみる

       ____ 
     /⌒  ⌒\  いっぱい苦労したけど
   /( ●)  (●)\  アクセストークン手に入れたお!!
  /::::::⌒(__人__)⌒:::::\  苦労が報われるお!!
  |     |r┬-|     | 
  \      `ー'´     / 



       ____
     /⌒  ⌒\
   /( >)  (<)\ さっそくアクセストークン使って
  /::::::⌒(__人__)⌒:::::\ Twitter に「おっぱい」って書き込むお!!
  |    /| | | | |      |
  \  (、`ー―'´,    /


では,実際にアクセスしてみましょう.
今回は twitter に発言をするサンプルです.

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

import time, random, urllib, urllib2, cgi, hmac, hashlib, commands

# 発言内容
text = u'おっぱい'

consumer_key = '最初に使ったやつ'
consumer_secret = '最初に使ったやつ'

oauth_token = 'アクセストークン取得の時に取得した OAuth Token'
oauth_token_secret = 'アクセストークン取得の時に取得した OAuth Token Secret'

# 発言の URL
update_url = 'http://twitter.com/statuses/update.json'

# 必須パラメータを準備
params = {
        "oauth_consumer_key": consumer_key, # WEB で登録した oauth consumer key
        "oauth_signature_method": "HMAC-SHA1", # 暗号のアルゴリズム
        "oauth_timestamp": str(int(time.time())), # unixtime 
        "oauth_nonce": str(random.getrandbits(64)), # ランダム文字列
        "oauth_version": "1.0" # バージョン番号
        }

# パラメータに必要な値を追加
params['oauth_token'] = oauth_token
params['status'] = text

# パラメータの値が unicode だったらエンコードします
for k,v in params.items():
    if isinstance(v, unicode):
        params[k] = v.encode('utf8')
            
# パラメータをソートし,URIエンコードした key=value の形にして & で繋げます
params_str = '&'.join(['%s=%s' % (urllib.quote(key, ''),urllib.quote(params[key], '~'))
                           for key in sorted(params)])

# メソッド,URIエンコードした URL,上で作ったパラメータ文字列を & で繋げます 
message = '%s&%s&%s' % ('POST',urllib.quote(update_url,''), urllib.quote(params_str,''))

# consumer_secret と oauth_token_secret を元にキーを作成します 
key = "%s&%s" % (consumer_secret, oauth_token_secret)

# キーを元に message で hmac を作成します
signature = hmac.new(key, message, hashlib.sha1)

# そのダイジェストを base64 でエンコードし,余計な空白を取り除きます
digest_base64 = signature.digest().encode("base64").strip()

# 作成したダイジェストをパラメータに追加します
params['oauth_signature'] = digest_base64

# ヘッダには API に必要なパラメータは含めないので消します
del params['status']

# パラメータをソートし,URIエンコードした key=value の形にして , で繋げます 
header_params_str = ",".join(["%s=%s" % (urllib.quote(k,''), urllib.quote(params[k],'~'))
                       for k in sorted(params)])
print header_params_str
# ヘッダに Authorization:OAuth + 上で作成した文字列を追加します
opener = urllib2.build_opener()
opener.addheaders = [('Authorization','OAuth %s' % header_params_str)]

# あとは普通に API を呼び出します
result = opener.open(update_url,urllib.urlencode(
    {'status':text.encode('utf-8')})).read()

おっぱい

      ._
       \ヽ, ,、
        `''|/ノ
         .|
     _   |
     \`ヽ、|
      \, V
         `L,,_
         |ヽ、)  ,、
        /    ヽYノ
       /    r''ヽ、.|
      |     `ー-ヽ|ヮ
      |       `|
      |.        |
      ヽ、      |
        ヽ____ノ      
        /_ノ ' ヽ_\
      /(≡)   (≡)\
     /::::::⌒(__人__)⌒::::: \      
     |     |r┬-|     |      
     \      `ー'´     /
     /          \
     (  |          |  )
     \|    э    |/
       (    ,,,,    ,ノ
       \  、(U)ノ ノ
         \/  /            ┼ヽ  -|r‐、. レ |
         /  /\            d⌒) ./| _ノ  __ノ 
      ⊂⌒__)__)

結論 : めんどくさすぎるので,ライブラリ使いましょう