認証に xAuth を使う Web API を Python で呼び出すメモ

requests と標準ライブラリだけを使って書いてみた。 パラメータの指定、特に oauth_signature の作成がシンドイ。 Authorization の指定も。

# -*- coding: utf-8 -*-
from random import getrandbits
from time import time
import hmac
import hashlib 
import urllib
import urlparse
import requests

CONSUMER_KEY = "your consumer_key"
CONSUMER_SECRET = "your consumer_secret"
ACCESS_TOKEN_URL = "access token url"
WEB_API_URL = "web api url"
USERNAME = "your user name"
PASSWORD = "your password"

def escape(s):
    if not isinstance(s, bytes):
        s = s.encode("utf-8")
    return urllib.quote(s, safe="~")

# xAuth に必要なパラメーターを作成
payload = {
    "oauth_consumer_key": CONSUMER_KEY,
    "oauth_signature_method": "HMAC-SHA1",
    "oauth_timestamp": str(int(time())),
    "oauth_nonce": str(getrandbits(64)),
    "oauth_version": "1.0",
    "x_auth_mode": "client_auth",
    "x_auth_username": USERNAME,
    "x_auth_password": PASSWORD,
}
payload["oauth_signature"] = hmac.new(
  "%s&%s" % (CONSUMER_SECRET, ""),
  "&".join([
      "POST",
      escape(ACCESS_TOKEN_URL),
      escape("&".join(["%s=%s" % (escape(x), escape(payload[x]))
          for x in sorted(payload)]))
  ]),
  hashlib.sha1).digest().encode("base64").strip()

# xAuth のアクセストークンを取得
r = requests.post(ACCESS_TOKEN_URL, params=payload)
print r.text
token = urlparse.parse_qs(r.text)
oauth_token = token["oauth_token"][0]
oauth_token_secret = token["oauth_token_secret"][0]

# Web API を呼び出すためのパラメータを作成
payload = {
    "oauth_consumer_key": CONSUMER_KEY,
    "oauth_signature_method": "HMAC-SHA1",
    "oauth_timestamp": str(int(time())),
    "oauth_nonce": str(getrandbits(64)),
    "oauth_version": "1.0",
    "oauth_token": oauth_token,
}
payload["oauth_signature"] = hmac.new(
    "%s&%s" % (CONSUMER_SECRET, oauth_token_secret),
    "&".join([
      "GET",
      escape(WEB_API_URL),
      escape("&".join(["%s=%s" % (escape(x), escape(payload[x]))
          for x in sorted(payload)]))
    ]),
    hashlib.sha1).digest().encode("base64").strip()

# Web API 呼び出し
headers = {
    "Authorization": "OAuth %s" % escape(",".join(
        ['%s="%s"' % (escape(x), escape(payload[x])) for x in payload]))
}
r = requests.get(WEB_API_URL, params=payload, headers=headers)
print r.text