はてな記事の編集/投稿 with vim&python
仕事中に社外秘でない技術メモを取りたいと思ったとき、はてなにすぐに投稿する環境があれば便利じゃね?と思った。エディタはvim。vimならわざわざ自作せんでもプラグインあるだろー、と探したらhatena.vimなるものがあった。
https://github.com/motemen/hatena-vim
インストールも簡単だしいいじゃん、と思いきや、:HatenaEditをいざ実行するとエラー。プラグインの中を覗いたらcurl + openssl で通信してた。opensslをローカルにインストールだと?だるい。ならいっそpythonで書いてしまえ。
というわけで、以下、20分で作ったpython版myhatena.vim。
まずはpythonモジュール
最低限のテストはしたよw
#encoding=utf-8 import urllib2 import mechanize # easy_install mechanize from common.mys import mylogger, S, U # ↑で紹介したロガーと文字列変換ね from datetime import datetime url = 'https://www.hatena.ne.jp/login' durl = 'http://d.hatena.ne.jp/' class HatenaCrawler: def __init__(self, loginname, password): self.loginname = loginname self.password = password self.br = self._connect() self.enc = 'euc-jp' self.content = {} # ログイン def login(self): self.br.open(url) self.br.select_form(nr=0) self.br['name'] = self.loginname self.br['password'] = self.password response = self.br.submit() # 記事取得 def loadContent(self, date_obj): yyyyMMdd = date_obj.strftime('%Y%m%d') self.content = {} try: response = self.br.open(durl + self.loginname + '/edit?date=' + yyyyMMdd) self.br.select_form(name='edit') try: self.content['timestamp'] = self.br.form['timestamp'] self.content['date'] = datetime.strptime(self.br.form['date'], '%Y%m%d') self.content['rkm'] = self.br.form['rkm'] self.content['day_title'] = self.br.form['title'] body = self.br.form['body'] self.content['body'] = U(body.replace('>', '>').replace('<', '<').replace('"', '"').replace('&', '\&')) except Exception, e: mylogger.info(e) self.content = {} self.content['rkm'] = self.br.form['rkm'] self.content['day_title'] = self.br.form['title'] self.content['date'] = date_obj mylogger.info(self.content) except mechanize._form.ControlNotFoundError, e: mylogger.error(e) return self.content # 投稿 def updateContent(self, date_obj): yyyyMMdd = date_obj.strftime('%Y%m%d') self.br.open(durl + self.loginname + '/edit?date=' + yyyyMMdd) self.br.select_form(name='edit') self.br.form['title'] = self.content['day_title'] self.br.form['body'] = self.content['body'] self.br.submit() def _connect(self): br = mechanize.Browser() #br.set_proxies({'http': 'hogehoge:80', 'https': 'hogehoge:80'}) # proxy経由なら br.set_handle_robots(False) return br if __name__ == '__main__': import unittest class Tests(unittest.TestCase): def setup(self): pass @unittest.skip('') def testInstantiate(self): crawler = HatenaCrawler(ログイン名, パスワード) crawler.login() @unittest.skip('') def testLoadContent(self): crawler = HatenaCrawler(ログイン名, パスワード) crawler.login() print crawler.loadContent(datetime(2011, 9, 8)) unittest.main(verbosity=2)
作りとしては仮想ブラウザでログインして編集画面の情報取得してます。mechanizeモジュール必須ですね。
既知のバグ (直す予定なし) ・loadContent() - preタグの中の「'>'」や「'<'」が「>」、「<」に変換されてしまう。
これ使って、vimscript書いてみました。
if !has('python') " なければスクリプトロードを中断したい endif command! -nargs=* MHatenaLogin :call s:LoginHatena() command! -nargs=* MHatenaLoad :call s:LoadContent( ) command! -nargs=* MHatenaUpdate :call s:PostContent( ) let s:buffer_name = 'hatena_local' python << EOF import vim from datetime import datetime from hatena_vim.hatena import HatenaCrawler crawler = HatenaCrawler(ログイン名, パスワード) EOF " TODO " ログインはapi呼び出し毎にしないとかなぁ " ログイン function! s:LoginHatena() python crawler.login() endfunction " 取得 function! s:LoadContent() let date = input('日付(yyyyMMdd) > ') silent execute 'e ' . s:buffer_name . '_' . date set filetype=hatena silent execute 'set buftype=nofile' python << EOF #encoding=cp932 del vim.current.buffer[0:] s = vim.eval('date') date_obj = datetime.strptime(s, '%Y%m%d') crawler.loadContent(date_obj) if 'body' in crawler.content: for s in crawler.content['body'].split('\n'): vim.current.buffer.append(s.rstrip().encode('cp932')) EOF endfunction " 投稿 function! s:PostContent() python << EOF s = '' for line in vim.current.buffer: s += line + '\n' crawler.content['body'] = s crawler.updateContent(crawler.content['date']) EOF endfunction
終了。vimscript開いて :so % したら3つのコマンド(MHatenaLogin, MHatenaLoad, MHatenaUpdate) 使える。やっつけだが個人ユースならいけるw
windows上で動かしてるんで、vim側で文字列に落とすときはcp932。
ちなみに、vimのシンタックスハイライトは hatena.vim に同梱のものを使わせてもらってます。