HateFS
ちょっとRubyとはてな日記ではてなFileSystemでも作ってみようかと思ったのですが、Ruby(とそのライブラリ)が便利すぎてFSのバイナリをいじるまでに至りませんでした。
はてなのログイン認証にWWW::Mechanize、HTMLの解析にHpricot、ファイルシステム部分にFuseFSを使ってます。とりあえず任意の日付の日記を「diary」ファイルとしてマウントして読むだけのコードを書いてみました。本当はFuseFSを(というかFUSEも)使わずにマウント部分を書いてみたかったんですがRubyであっさり出来すぎたんでやる気失せました。
diaryio.rb
require 'rubygems' require 'mechanize' require 'kconv' class BaseRW attr_accessor :date def initialize(id, pass, date) @id = id @pass = pass @base_url = "http://d.hatena.ne.jp/" + @id + "/" @s_login = "ログイン".toeuc @s_move = "こちら".toutf8 @date = date @agent = set_agent() end private def set_agent agent = WWW::Mechanize.new dialy_page = agent.get(@base_url) login_link = dialy_page.links.text(@s_login) login_page = agent.get(login_link.href) login_form = login_page.forms.first login_form['name'] = @id login_form['password'] = @pass redirect_page = agent.submit(login_form) diary_link = redirect_page.links.text(@s_move) @base_page = agent.get(diary_link.href) return agent end protected def get_day_page day_url = @base_url + @date day_page = @agent.get(day_url) return day_page end end class ReadDairy < BaseRW def initialize(id, pass, date) super(id, pass, date) end def get_page day_page = get_day_page() day_doc = day_page.root page = "" (day_doc/"div.body div.section p").each do |body| next if /timestamp/ =~ "#{body.inner_html}" page += "#{body.inner_html}\n" end if page == nil return nil else return page.toutf8 end end end class WriteDairy < BaseRW def initialize(id, pass, date) super(id, pass, date) end def set_page(lines) edit_link = @base_page.links.text("日記を書く".toeuc) edit_page = @agent.get(edit_link.href) edit_form = edit_page.forms.name("edit").first edit_form["year"] = @date.slice(0..3) edit_form["month"] = @date.slice(4..5) edit_form["day"] = @date.slice(6..7) edit_form["body"] = lines ok_button = edit_form.buttons.name("edit") @agent.submit(edit_form, ok_button) end end
はてな日記の読み書き部分。Mechanizeにより認証がものすごく楽です。
argparse.rb
class ArgParse def initialize(argv) @argv = argv if @argv.size < 4 || @argv.size > 6 puts "usage: ruby hatefs.rb mnt [-r] [-w line] id pass date" exit 0 end set_args() end private def set_args @mount = @argv[0] if /-r/ =~ @argv[1] @cmd = "read" @id = @argv[2] @pass = @argv[3] @date = @argv[4] elsif /-w/ =~ @argv[1] @cmd = "write" @lines = @argv[2] @id = @argv[3] @pass = @argv[4] @date = @argv[5] else @cmd = "read" @id = @argv[1] @pass = @argv[2] @date = @argv[3] end end end
hatefs.rb
require 'rubygems' require 'mechanize' require 'fusefs' require 'kconv' require 'diaryio' require 'argparse' class HateFs def initialize(read, write) @read = read @write = write end def contents(path) ['diary'] end def file?(path) path == '/diary' end def read_file(path) @read.get_page end def write_to(path, str) @write.set_page(str) end end arg = ArgParse.new(ARGV) read = ReadDairy.new(arg.id, arg.pass, arg.date) write = WriteDairy.new(arg.id, arg.pass, arg.date) hatefs = HateFs.new(read, write) FuseFS.set_root(hatefs) FuseFS.mount_under ARGV.shift FuseFS.run
マウント方法
$ ruby hatefs.rb mnt sodex password 20070407
これで以下のように日記がファイルとして参照出来ました。(とりあえず適当に取ってきただけなので汚いですが。。)