動機
ある日突然外国の方から「君が作ったmixi APIを使ってみたら、うまく動かないんだけど。」っていわれました。どうも奥さんが日本人でmixiダイアリーのバックアップを取りたいらしい。が、そもそも俺がPythonで書いたmixi APIはmixiツールバーのものが基本で、mixiツールバー自身はそんな機能を持ってないので「無理だよ」と言ったら、「とても残念だ」という返事が返ってきました。
それで突っぱねておしまいに出来たんだけど、なんかかわいそうだからバックアップできないかなあと思って実装してみました。
作った物
使った物
- Python 2.5
- lxml
概要
mixiへのログイン
まずmixiにログインしないとそもそもmixiダイアリーを参照できないので、ログインします。その部分については西尾さんのエントリをそのまま使わせてもらいました。(西尾さんありがとうございます)
各エントリのURL取得
mixiダイアリーの各月のエントリ一覧はYEAR年MONTH月の場合
http://mixi.jp/list_diary.pl?year=YEAR&month=MONTH
で取得できます。この中で各エントリへのリンクである
http://mixi.jp/view_diary.pl?id=XXXXXXXX&owner_id=XXXXXXX
となっているURLを取得します。このときページ内の他のURLを持ってこないように
view_url_r = re.compile('^view_diary.pl\?id=[0-9]+&owner_id=[0-9]+$') if url.match(u): urllist.append(url)
みたいな感じでURLを絞ってます。(コード参照)
各エントリの内容取得
最初はHTMLParserを使ってたんですが、JavaScriptコード内のタグのスニペットを実際のタグと誤認識してバグる&フィルタをかけるのがめんどくさかったんでlxmlを使うことにしました。
lxmlはXPathが分かればものすごく簡単で、かつとても速いのでかなり気に入りました。使い方は
tree = etree.parse(StringIO(data), etree.HTMLParser()) data = tree.xpath('//div[@class="hoge"]//a/@href') data2 = tree.xpath('//div[@class="piyo"]//p/text()')
みたいな感じで使えます。とりあえず絶対パスと相対パスにさえ気をつけておけばさくっとほしいデータを取得できるはずです。先頭で'//'を使うとどんなノードを渡しても必ずルートノードから参照してしまうので、'.//'とピリオドを忘れないように。(コード参照)
ファイルへの吐き出し
あとは取得した物を適当にファイルにはき出すだけです。今回はファイルにはき出す部分はあくまでサンプルとして実装してみました。実際はMixiExtractorクラスさえあればgetMonthEntryBodyメソッドの返り値を利用していかようにも書けると思います。
なお、getMonthEntryBodyメソッドは
- date (日記のタイムスタンプ) - title (日記のタイトル) - body (日記の本文) - comments (コメント) - cdate (コメントされたタイムスタンプ) - cuser (コメントを書いたユーザ名) - cbody (コメントの内容)
のリストな感じでデータを返してきます。commentsもリストです。
使い方
$ python mixi_downloader.py -u USERNAME -p PASSWORD [-c]
USERNAMEは登録しているメールアドレス、PASSWORDはパスワードです。また-cオプションはコメントの取得の有無を表しています。つけなければコメントは取得しません。
その後
メールをくれた外国人に「こんなんできたよ」と返信したらとても喜んでくれました。
My wife looked pretty happy about it, so thanks again.
こういうメールをもらうと自分の趣味でやってたことで喜んでくれる人がいるんだなあと思ってうれしくなります。面白い時代に生きているなあと改めて実感します。