Pythonではてなグラフ数値登録APIを使う稚拙なサンプル

KIRIN THE GOLDのほのかな苦味に満足しながら、なんだか明日も休みのような気分だなぁ、とか思っているbonlifeです。誰か私に木金2日間分の仕事パワーをください。
さてさて、最近Pythonに結構興味が出てきてしまったので、id:kenkitii:20060429:p1 にて公開されていたPythonで書かれたAtomAPIのクライアントとそのサンプルを参考にして、はてなグラフを更新するちっちゃなスクリプトを書いてみました。
まず、AtomClientはAtomClient.pyって名前にしてそのまま使わせてもらうことに。

  • AtomClient.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import random
import datetime, time
import base64, sha
import httplib

class AtomClient(object):
    def __init__(self):
        self.endopoint = None
        self.wsse = None

    def credentials(self, endpoint, user, password):
        nonce = sha.sha(str(time.time() + random.random())).digest()
        now = datetime.datetime.now().isoformat() + "Z"
        digest = sha.sha(nonce + now + password).digest()

        wsse = 'UsernameToken Username="%(u)s", PasswordDigest="%(p)s", Nonce="%(n)s", Created="%(c)s"'
        value = dict(u = user, p = base64.encodestring(digest).strip(),
                     n = base64.encodestring(nonce).strip(), c = now)

        self.endpoint = endpoint
        self.wsse = wsse % value

    def atom_request(self, method, URI, body):
        con = httplib.HTTPConnection(self.endpoint)
        con.request(method, URI, body, {'X-WSSE' : self.wsse, 'Content-Type':'text/xml'})
        r = con.getresponse()

        response = dict(status = r.status,
                       reason = r.reason,
                       data   = r.read())
        con.close()
        return response

続いて、はてなグラフ数値登録API用に HateGra.py って名前で以下のようなクラスを作成。(HatePhoってクラス名を真似てみました。) AtomClientクラスのatom_request()は、text/xml をPOSTする仕様なので、application/x-www-form-urlencoded のデータをPOSTするためにurlencoded_request()を作成。(ってContent-Typeの指定部分以外は、atom_request()と同じ内容なので、継承やらsuperやらを使って何かできたら良かったのですが、よく分からなかったので、ほぼ同じ内容をコピペ…。)

  • HateGra.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from AtomClient import AtomClient
from datetime import datetime, date
import httplib

class HateGra(AtomClient):
    """はてなグラフを更新するクラス (AtomClientを継承)"""
    def urlencoded_request(self, method, URI, body):
        con = httplib.HTTPConnection(self.endpoint)
        con.request(method, URI, body, {'X-WSSE' : self.wsse, 'Content-Type' : 'application/x-www-form-urlencoded'})
        r = con.getresponse()

        response = dict(status = r.status,
                       reason = r.reason,
                       data   = r.read())
        con.close()
        return response

    def register_value(self, graphname, value, date=(date.today()).isoformat()):
        entry = '''graphname=%s&value=%s&date=%s'''
        return { 'response' : self.urlencoded_request('POST', '/api/post', entry % (graphname, value, date)), 
                 'time' : datetime.now(),
                 'setting' : { 'graphname' : graphname, 'value' : value, 'date' : date } }

参考にしたサンプルでは、responseのみreturnで返していたのですが、実行時間と処理に使った値たちも返すようにしてみました。(こういうのをこのクラスでやるのが適切なのかしら、とか思いつつ。) 後、dateは渡さなくてもはてな側でその日の日付を設定してくれるみたいですが、entryの内容を分けるのが面倒だったので、引数に初期値としてdate.today()を渡すことに。
こいつを使う例は以下の通り。('username'、'password'はもちろんはてなのユーザID、パスワードにします。)

  • sample_hategraph_register.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from HateGra import HateGra

def log_print(result):
    if result['response']['status'] == 201:
        print result['time'], result['setting']
    else:
        print result['time'], result['setting'], result['response']

hg = HateGra()
hg.credentials('graph.hatena.ne.jp', 'username', 'password')

log_print(hg.register_value('テスト', 12.3))
log_print(hg.register_value('テスト', 45.6,'2007-03-23'))

引数で値を渡すように書き換えれば、それなりに使えるような気がしないでもない。ちなみに、実行すると標準出力に以下のようなログが出るので、これをリダイレクトして記録したりしたら良いんじゃないかしら、とかとか。(文字列はちゃんと読めるように変換した方が良いですね。)

2007-03-21 22:11:05.567569 {'date': '2007-03-21', 'graphname': '\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88', 'value': 12.3}
2007-03-21 22:11:05.744529 {'date': '2007-03-23', 'graphname': '\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88', 'value': 45.6}

そうそう、はてな数値登録APIの説明を流し読みしただけでチャレンジしてしまったため、XMLを作ってatom_requestでPOSTして 500 Internal Server Error を出しまくっちゃいましたよ。数百回ぐらい…orz はてなの中の人、本当にゴメンナサイ。そのバチがあたたのか、「テスト」って名前のグラフを作ろうとした時、文字コードがShift-JISになっているのに気付かないまま実行してしまい、「?e?X?g」って表示されるグラフが出来ちゃいました。で、それを消すことが出来ずにいる現状…orz 後で中の人に頼んで消してもらおう、そうしよう。

Pythonプログラミング入門

Pythonプログラミング入門

今日、この本を少し立ち読みしてみたのですが、なんだか不思議な本でした。他の本に比べて文法に関する記述が異常にサラッとしていて、なぜかTkinterを使ったGUIアプリケーション開発に結構なページ数割いてましたよ。入門書でこの内容ってどうなのかしら、と思いつつも、GUIアプリケーションの部分が結構気になる今日この頃です。