はてなダイアリーから自分の日記をバックアップする方法

はてなに何か問題が起きて、自分の書いた日記が全部消えたら困るよなあ、バックアップしとかないとなあ、と思いながら、なかなか実行できてませんでした。
が、ついに一念発起してやりました。といっても はてなダイアリーAtomPub の通りに取得してくるだけですが、他に同じことしたい人がいるかもしれないのでスクリプトを公開しておきます。
atomutil gem が必要です。

gem install atomutil

遺憾ながら atomutil は Ruby 1.9 でそのままでは動かないので、以下のように適当に修正しました。

--- atomutil-0.0.9/lib/atomutil.rb.bak  2010-11-09 02:43:38.540000000 +0900
+++ atomutil-0.0.9/lib/atomutil.rb      2010-11-09 02:43:41.270000000 +0900
@@ -760,7 +760,7 @@
         |[\xf0-\xf7][\x80-\xbf]{3}
         |[\xf8-\xfb][\x80-\xbf]{4}
         |[\xfc-\xfd][\x80-\xbf]{5}
-        )*$/xs
+        )*$/x
         copy = "<div xmlns=\"http://www.w3.org/1999/xhtml\">#{value}</div>"
         is_valid = true
         begin

あとは以下を起動する。はてな ID とパスワードを聞かれるので答える。

require "atomutil"

print "hatena id: "
$stdout.flush
hatena_id = $stdin.gets.chomp

print "hatena password: "
$stdout.flush
begin
  system "stty -echo"
  hatena_passwd = $stdin.gets.chomp
ensure
  system "stty echo"
end
puts

auth = Atompub::Auth::Wsse.new :username => hatena_id, :password => hatena_passwd
client = Atompub::Client.new :auth => auth
service = client.get_service "http://d.hatena.ne.jp/#{ hatena_id }/atom"
col_uri = service.workspace.collections[1].href
idx = 1
loop do
  list = client.get_feed col_uri + "?page=#{ idx }"
  noentry = true
  REXML::XPath.each(list.elem, "//link[@rel='edit']") do |link|
    entry_uri = link.attributes["href"]
    puts "fetching: " + entry_uri
    if %r(d\.hatena\.ne\.jp/[^/]+/atom/blog/(\d{8})/) =~ entry_uri
      noentry = false
      dir, file = $1, $'
      entry = client.get_entry entry_uri
      title = entry.elem.elements["//title"].text
      text = entry.elem.elements["//hatena:syntax"].text
      Dir.mkdir(dir) unless File.directory?(dir)
      open("#{ dir }/#{ file }", "wb") do |f|
        f.puts "*#{ title }"
        f.write(text)
      end
    end
  end
  break if noentry
  idx += 1
end

実行すると、"日付/エントリ名" というファイルがいっぱいできるはず。それぞれのファイルに、はてな記法で書かれた日記が記録されていると思います。
どうせならローカルのファイル群とはてなダイアリーを相互に同期できるツールにしたい気もする。でも開発続いてなさそうな atomutil の上でそこまで作りこむのもなあ。まあ単にやる気ないだけだけど。