Λάδι Βιώσας

http://profile.hatena.ne.jp/kenkitii/

はてなの質問に答えてみる

idで指定したはてなダイアリーの記事一覧を表形式で取得したい
http://q.hatena.ne.jp/1220786470

こんな感じ↓のスクリプトになりました。

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

import random
import datetime, time, sys
import base64, sha
import httplib
from optparse import OptionParser
from BeautifulSoup import BeautifulSoup

class AtomClient:
    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

class DiaryList(AtomClient):
    def __init__(self, id, password):
        self.id = id
        self.current_page = 0
        self.credentials('d.hatena.ne.jp', id, password)

    def get_feed(self, start, end):
        results = []
        entries = self.next_page()
        while entries:
            for e in entries:
                now = e.published.contents[0][:10].replace("-", "")
                if now < start: return results
                if now <= end: results.append(e)
            entries = self.next_page()

        return results

    def next_page(self):
        uri = '/%s/atom/blog?page=%i' % (self.id, self.current_page)
        self.current_page += 1
        response = self.atom_request('GET', uri, "")
        entries = BeautifulSoup(response['data']).findAll('entry')
        return entries

def str2date(s):
    try:
         return datetime.datetime.strptime(s, "%Y%m%d")
    except ValueError:
        print "date data did not match format: %Y%m%d"
        sys.exit()

def main():
    usage = "usage: %prog id password [options]"
    parser = OptionParser(usage)
    parser.add_option("-s", "--start", dest="start", help='start date', metavar="DATE")
    parser.add_option("-e", "--end", dest="end", help='end date', metavar="DATE")
    (options, args) = parser.parse_args()
    if len(args) != 2:
        parser.error("invalid arguments")

    end = datetime.datetime.now().strftime("%Y%m%d")
    if options.end: end = options.end
    start = (str2date(end) - datetime.timedelta(30)).strftime("%Y%m%d")
    if options.start: start = options.start
    if str2date(start) >= str2date(end):
        parser.error("invalid dates")

    d = DiaryList(args[0], args[1])
    entries = d.get_feed(start, end)
    for e in entries[::-1]:
        date = e.published.contents[0][:10].replace("-", "")
        title = e.title.contents[0]
        link = e.find("link", {"rel": "alternate"})['href']
        print "%s,%s" % (link, title)

if __name__ == "__main__":
    main()

インストール方法

python 2.5以上をインストールします。上記のスクリプトは、BeautifulSoupというxmlパーサーを利用しているので、ここからダウンロードして、上記のスクリプトを保存した場所と同じフォルダに置いておきます。

使い方

はてなダイアリーAtomPubを使ってる都合上、はてなIDとパスワードが必要になります。日付は、20080911のようなフォーマットで指定します。日付を指定しない場合、最新1ヶ月分の日記のタイトルを取得します。

C:\python2.5>python diarylist.py -h
Usage: diarylist.py id password [options]

Options:
  -h, --help            show this help message and exit
  -s DATE, --start=DATE
                        start date
  -e DATE, --end=DATE   end date

使用例

C:\python2.5>python diarylist.py kenkitii ****** -s 20060101 -e 20060301
http://d.hatena.ne.jp/kenkitii/20060105/p1,[Web]YouTube
http://d.hatena.ne.jp/kenkitii/20060110/p1,[web]楽天祭り
http://d.hatena.ne.jp/kenkitii/20060111/p1,[etc][Google]宮崎駿
http://d.hatena.ne.jp/kenkitii/20060113/p1,[XBOX][360]Project Gotham Racing 3
http://d.hatena.ne.jp/kenkitii/20060117/p1,[news]Livedoor
http://d.hatena.ne.jp/kenkitii/20060119/p1,[etc]e-typingの腕試しチェック
http://d.hatena.ne.jp/kenkitii/20060121/p1,[column]勉強しなくていいよ、という人
http://d.hatena.ne.jp/kenkitii/20060121/p2,[book][python]Python入門
http://d.hatena.ne.jp/kenkitii/20060123/p1,[etc]なんか
http://d.hatena.ne.jp/kenkitii/20060126/p1,[Game][http://pcweb.mycom.co.jp/news/2006/01/26/008.html:title]
http://d.hatena.ne.jp/kenkitii/20060126/p2,[hatena]最近ハテナが妙に重いんだけど
http://d.hatena.ne.jp/kenkitii/20060204/p2,ぼくはまちちゃん! 
http://d.hatena.ne.jp/kenkitii/20060207/p1,[book]コレ買った
http://d.hatena.ne.jp/kenkitii/20060207/p2,[book]えー
http://d.hatena.ne.jp/kenkitii/20060208/p1,[book]富士通成果主義の崩壊
http://d.hatena.ne.jp/kenkitii/20060210/p2,[column]日本語の曖昧さ
http://d.hatena.ne.jp/kenkitii/20060215/p1,スタックオーバーフロー
http://d.hatena.ne.jp/kenkitii/20060216/p1,[python]はまりごと
http://d.hatena.ne.jp/kenkitii/20060217/p1,[etc]突っ込み先
http://d.hatena.ne.jp/kenkitii/20060223/p1,[python]運用管理ツール
http://d.hatena.ne.jp/kenkitii/20060227/p1,[Python]MeCabとPythonで遊んでみたメモ
http://d.hatena.ne.jp/kenkitii/20060301/p1,[Python]MeCabとPythonで遊んでみたメモ2