はてなダイアリーライター Version 1.4.1 を試してみた

以前に試したときにはどういうわけだかうまくいかなかってけど,今度はうまくいったので(ちょっとはまったけど),メモ。

はてなダイアリーライター本体はここから(Version 1.4.1)。マニュアルもここ。

まずは試してみる。テスト用の日記ファイルを作って,設定ファイルはなしでやってみたらすんなり成功。ちょっと拍子抜け。

^o^ >perl hw.pl
WARNING: Crypt::SSLeay is not found, use non-encrypted HTTP mode.
Username: takatoh
Password: ********
Login to http://www.hatena.ne.jp/login as takatoh.
Login OK.
Post 2007-07-08.
Post OK.
Logout from http://d.hatena.ne.jp as takatoh.
Logout OK.

けどちょっと待て。Cyrpt::SSLeayが無いから暗号化しないモードを使うといってる。

……それで思い出した。以前うまくいかなかったのはこのあたりだった。

というわけで,このへんのページを参考に改めてチャレンジ。

まずはOpenSSLから。上のリストの2番目のページからインストーラ(最新版 Win32OpenSSL v0.9.8e)をダウンロードしてインストールするだけ。

Crypt::SSLeay のほうは上のリストの3番目のページにある「LWPで、「https://」で始まるSSL使用サイトにアクセスできますか?」を参考にした。ppmコマンドでインストールするんだけど,モジュール名ではなくPPDファイル名を指定する必要があるらしい(GUI版ppmのリストに出てこない)。ActivePerl 5.8.8 を使っているので:

^o^ >ppm install http://theoryx5.uwinnipeg.ca/ppms/Crypt-SSLeay.ppd

後半,dllをインストールするか聞いてくるので yes と答えてインストールする。デフォルトが[no]になってるので注意。

さて,改めて試してみよう。ついでに設定ファイルも書いておく。

id:takatoh
password:********
cookie:cookie.txt
proxy:http://proxy:8080/
client_encoding:Shift_JIS
server_encoding:EUC_JP

これでOKのはず。

^o^ >perl hw.pl
Login to https://www.hatena.ne.jp/login as takatoh.
Login OK.
Post 2007-07-08.
Old cookie. Retry login.
Login to https://www.hatena.ne.jp/login as takatoh.
Login OK.
Old cookie. Retry login.
Login to https://www.hatena.ne.jp/login as takatoh.
Login OK.
ERROR: try_it: Check username/password.

なんでエラーになるんだ!!……orz

えーと。いろいろ試した結果何とか動くようになった。これについてはエントリーを改めて書く。

さきに書いておくと,インストールや設定ファイルは上の通りで大丈夫(たぶん)。問題はcookie.txtだった。--(つづく)

はてなダイアリーライター Version 1.4.1 を試してみた(その2)

id:takatoh:20070708:hw のつづき。Crypt::SSLeayをインストールしたらエラーになった件。

いろいろ試した結果,クッキーファイル(cookie.txt)の有無と関係が有ることがわかった。表にするとこんな感じ。

cookie.txtあり cookie.txtなし
Crypt::SSLeayなし OK OK
Crypt::SSLeayあり OK エラー

Crypt::SSLeayが無い場合にはcookie.txtの有無に関わらずOKなんだけど,これは暗号化されないってことなんで非推奨。Crypt::SSLeayをインストールするとcookie.txtが無い場合にエラーになる。無けりゃ作ってくれるはずなんだけど,ここで失敗しているように見える(最後から2行目)。……ちがうのかな。

-d オプションをつけて実行した結果:

^o^ >perl hw.pl -d
DEBUG: Debug flag on.
Hatena Diary Writer Version 1.4.1
Copyright (C) 2004,2005 by Hiroshi Yuki.
DEBUG: Loading config file (config.txt).
DEBUG: load_config: id:takatoh
DEBUG: load_config: password:********
DEBUG: load_config: cookie:cookie.txt
DEBUG: load_config: proxy:http://proxy:8080/
DEBUG: load_config: client_encoding:Shift_JIS
DEBUG: load_config: server_encoding:EUC_JP
DEBUG: main: files: current dir (.): ./2007-07-08.txt ./touch.txt
DEBUG: login: proxy for http: http://proxy:8080/
DEBUG: login: proxy for https: http://proxy:8080/
Login to https://www.hatena.ne.jp/login as takatoh.
DEBUG: login: 200 OK
DEBUG: login: $r = <HTML></HTML>
Login OK.
DEBUG: login: Making cookie jar.
DEBUG: login: $cookie_jar =
DEBUG: read_title_body: input: ./2007-07-08.txt
DEBUG: Convert from Shift_JIS to EUC_JP.
Post 2007-07-08.
DEBUG: create_it: 2007-07-08.
DEBUG: create_it: 302 Moved
DEBUG: create_it: Location: /takatoh/
DEBUG: create_it: returns 0 (ERROR).
DEBUG: try_it: update_diary_entry: CREATE.
Old cookie. Retry login.
DEBUG: login: proxy for http: http://proxy:8080/
DEBUG: login: proxy for https: http://proxy:8080/
Login to https://www.hatena.ne.jp/login as takatoh.
DEBUG: login: 200 OK
DEBUG: login: $r = <HTML></HTML>
Login OK.
DEBUG: login: Making cookie jar.
DEBUG: login: $cookie_jar =
DEBUG: create_it: 2007-07-08.
DEBUG: create_it: 302 Moved
DEBUG: create_it: Location: /takatoh/
DEBUG: create_it: returns 0 (ERROR).
DEBUG: try_it: update_diary_entry: CREATE.
Old cookie. Retry login.
DEBUG: login: proxy for http: http://proxy:8080/
DEBUG: login: proxy for https: http://proxy:8080/
Login to https://www.hatena.ne.jp/login as takatoh.
DEBUG: login: 200 OK
DEBUG: login: $r = <HTML></HTML>
Login OK.
DEBUG: login: Making cookie jar.
DEBUG: login: $cookie_jar =
ERROR: try_it: Check username/password.

結局,Crypt::SSLeayをインストール/アンインストールしたり,設定ファイルを書き換えてみたりしてるうちにできた(つまりCrypt::SSLeayなしの時にできた)クッキーファイルがあって動くようになったので今回はOKとする。Crypt::SSLeayありの状態でクッキーファイルを作る方法はわからない。

なんだか中途半端だけど時間切れだ。

追記:PCの環境

  • Windows XP
  • ActivePerl 5.8.8
  • Crypt::SSLeay 0.53

追記2:proxyなしの場合

hyukiさんのアドバイスに従ってproxyの無い環境で試してみたら,正しく投稿できた。どうやら次の3つが重なったときにエラーになるらしい。

  • Crypt::SSLeay あり
  • クッキーファイルがない
  • proxyを利用

指定された日の存在する週

cf. どう書く?org – 指定された日の存在する週

こんどは Ruby で。

require 'date'
y, m, d = ARGV.map{|arg| arg.to_i }
date = Date.new(y, m, d)
sunday = (date - date.wday)
(1..5).each do |d|
puts((sunday + d).strftime("%Y-%m-%d %a"))
end

実行。

^o^ >week.rb 2007 7 7
2007-07-02 Mon
2007-07-03 Tue
2007-07-04 Wed
2007-07-05 Thu
2007-07-06 Fri
^o^ >week.rb 2007 1 1
2007-01-01 Mon
2007-01-02 Tue
2007-01-03 Wed
2007-01-04 Thu
2007-01-05 Fri
^o^ >week.rb 2007 12 30
2007-12-31 Mon
2008-01-01 Tue
2008-01-02 Wed
2008-01-03 Thu
2008-01-04 Fri

条件を満たす行を取り除く

条件を満たす行を取り除く
 via http://d.hatena.ne.jp/gan2/20070706/1183708048

‘#’で始まる行を取り除く問題。すげーひさしぶりに Haskell で書いてみる。

module Main where

import System

f :: String -> Bool
f (h:tl) | h == '#' = False
          | otherwise = True

main :: IO ()
main = do fileName <- getArgs
          contents <- readFile (head fileName)
          putStr $ unlines $ filter f $ lines contents

実行。

^o^ >type sample.txt
hello!
# remove this
 # don't remove this
bye!
^o^ >runhaskell filterline.hs sample.txt
hello!
 # don't remove this
bye!

ファイルを1行ずつ処理するやり方を忘れててあせった。

追記:id:jmkさんからもらったアドバイスを追記しておこう。ありがとうございます。

f ('#':_) = False
f _ = True
  • 元のコードでは空行に対応できてない。
  • パターンマッチにはリテラルを使える。

ピラミッドを作る

どう書く?org – ピラミッドを作る

与えられた高さのピラミッドを作る

module Main where

import System

cjust :: Int -> String -> String
cjust w s | w <= length s = s
          | otherwise = margin ++ s ++ margin
  where
    margin = replicate ((w - (length s)) `div` 2) ' '

pyramid :: [String]
pyramid = map (flip replicate '*') [1,3..]

main :: IO ()
main = do h <- getArgs >>= return.read.head
          putStr $ unlines $ map (cjust (h*2-1)) $ take h pyramid

実行。

^o^ >runhaskell pyramid.hs 4
   *
  ***
 *****
*******
^o^ >runhaskell pyramid.hs 5
    *
   ***
  *****
 *******
*********
^o^ >runhaskell pyramid.hs 6
     *
    ***
   *****
  *******
 *********
***********
^o^ >runhaskell pyramid.hs 1
*
^o^ >runhaskell pyramid.hs 0

お,高さ0でもちゃんと動く。

hatenaapigraph が 0.1.2 に

proxy 対応がうまくいってない,と書いたら早速対応してくれた。ありがとうございます。

cf. d:id:takatoh:20070522:http_proxy のコメント欄

バージョンアップして,リポジトリに取り込んでもらった Pragger のプラグインを修正した。設定ファイルで proxy のホスト,ポート,ユーザ,パスワードを指定可能。hatenaapigraph の 0.1.2 が必要なので gem でインストールしましょう。

  • 設定ファイルで proxy が指定されていればそれを使う。
  • 設定ファイルになくても,環境変数 HTTP_PROXY があればそれを使う。ただし値に “http://” が含まれていないこと。含まれているとエラーになる。
  • どちらもなければ proxy は使わない。
## Post data to Hatena Graph -- takatoh
## 
## hatenaapigraph 0.1.2 is required.
## 
## see http://d.hatena.ne.jp/takatoh/20070531/hatena_graph
##
## - module: Publish::hatena_graph
##   config:
##     user_id: your hatena user id
##     password: your password
##     graph_name: the name of graph
##     proxy_host: proxy host name  (optional)
##     proxy_port: proxy port       (optional)
##     proxy_user: proxy user       (optional)
##     proxy_pass: proxy password   (optional)
begin
require 'rubygems'
gem 'hatenaapigraph', '>=0.1.2'
rescue LoadError
end
require 'hatena/api/graph'
def hatena_graph(config, data)
value = data.first.to_f
graph = Hatena::API::Graph.new(config['user_id'], config['password'])
if config['proxy_host']
proxy_host = config['proxy_host']
proxy_port = config['proxy_port']
proxy_user = config['proxy_user']
proxy_pass = config['proxy_pass']
graph.proxy = ::Net::HTTP.Proxy(proxy_host, proxy_port, proxy_user, proxy_pass)
end
graph.post(config['graph_name'], Time.now, value)
end

環境変数 HTTP_PROXY の値には ”http://” を含むのか含まないのか

昨日の続きでもある。

hatenaapigraph 0.1.1 にあわせて HTTP_PROXY=proxy:8080 としたら wget が動かなくなった。Ruby の open-uri もダメ。

^o^ >echo %HTTP_PROXY%
proxy:8080
^o^ >type get_diary.rb
require 'open-uri'
puts open("http://d.hatena.ne.jp/takatoh/"){|f| f.read }
^o^ >ruby get_diary.rb
C:/usr/ruby/lib/ruby/1.8/open-uri.rb:203:in `open_http': Non-HTTP proxy URI: pro
xy:8080 (RuntimeError)
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:626:in `buffer_open'
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:164:in `open_loop'
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:162:in `catch'
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:162:in `open_loop'
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:132:in `open_uri'
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:528:in `open'
from C:/usr/ruby/lib/ruby/1.8/open-uri.rb:30:in `open'
from get_diary.rb:3

どちらも HTTP_PROXY=http://proxy:8080/ なら問題なく使える。

「環境変数 HTTP_PROXY」でググってみたけど,”http://” を含めてるのと含めてないのと両方あるな。いったいどうしろっていうんだ。

せっかく簡潔になった Pragger の puglis::hatena_graph.rb だけど結局メソッドを再定義して対処した。”http://” がついてたら取り除く。

## Post a data to Hatena Graph
## 
## require gem `hatenaapigraph' 0.1.1 or later.
## 
## - module: publish::hatena_graph
##   config:
##     user_id: your-hatena-user-id
##     password: your-password
##     graph_name: the-name-of-graph
begin
require 'rubygems'
rescue LoadError
end
require 'hatena/api/graph'
module Hatena::API
class Graph
private
def http_post(url, params, headers)
req = ::Net::HTTP::Post.new(url.path, headers)
req.form_data = params
req.basic_auth url.user, url.password if url.user
proxy_host, proxy_port = (ENV['HTTP_PROXY'] || '').sub(/^http:\/\//, '').split (/:/)
::Net::HTTP::Proxy(proxy_host, proxy_port.to_i).start(url.host, url.port) {|ht tp|
http.request(req)
}
end
end
end
def hatena_graph(config, data)
value = data.first.to_f
graph = Hatena::API::Graph.new(config['user_id'], config['password'])
graph.post(config['graph_name'], Time.now, value)
end

hatenaaipgraph が 0.1.1

になってるのに,今日,気がついた。HTTP_PROXYサポートと日本語グラフ名のバグ修正なので,こないだ書いた Prager の publish::hatena_graph プラグインも簡潔になる。

## Post a data to Hatena Graph
## 
## require gem `hatenaapigraph' 0.1.1 or later.
## 
## - module: publish::hatena_graph
##   config:
##     user_id: your-hatena-user-id
##     password: your-password
##     graph_name: the-name-of-graph
begin
require 'rubygems'
rescue LoadError
end
require 'hatena/api/graph'
def hatena_graph(config, data)
value = data.first.to_f
graph = Hatena::API::Graph.new(config['user_id'], config['password'])
graph.post(config['graph_name'], Time.now, value)
end

Pragger のリリースも近い?

Praggerがどうやら最初のリリースに向けて具体的に動き出したっぽい。

ちょうどいいので今まで作ったプラグインについてまとめておく。どれもPraggerと同じライセンスでOKです。

load_lirs.rb

LIRS を取得するプラグイン。これでいいのか実は不安。

publish:hatena_graph.rb

はてなグラフにデータをポストするプラグイン。今日のデータしかポストできない。

get_hatena_graph.rb

はてなグラフからデータをダウンロードするプラグイン。目的のグラフのデータだけを抜き出す。これは公開してなかった。

## Get Hatena Graph data
## 
## - module: get_hatena_graph
##   config:
##     user_id: your-hatena-user-id
##     password: your-password
##     graph_name: the-name-of-graph
begin
require 'rubygems'
rescue LoadError
end
require 'mechanize'
require 'uri'
require 'kconv'
require 'csv'
class HatenaGraph
def initialize(id,password)
@id = id
@password = password
@agent = WWW::Mechanize.new
if proxy = ENV['http_proxy']
proxy = URI.parse(proxy)
@agent.set_proxy(proxy.host, proxy.port)
end
@graph = @agent.get("http://graph.hatena.ne.jp/#{id}/")
end
def login
login_link = @graph.links.text("ログイン".toutf8)
login_page = @agent.get(login_link.href)
login_form = login_page.forms.first
login_form['key'] = @id
login_form['password'] = @password
redirect_page = @agent.submit(login_form)
@graph_link = redirect_page.links.text("こちら".toutf8)
@graph_page = @agent.get(@graph_link.href)
end
def fetch_csv
@data_link = @graph_page.links.text("データ".toutf8)
@data_page = @agent.get(@data_link.href)
csv_link = @data_page.links.text("ダウンロード".toutf8)
csv_file = @agent.get(csv_link.href)                    # => WWW::Mechanize::File
tmpfile = Tempfile.open("hatenagraph")
path = tmpfile.path
csv_file.save_as(path)
tmpfile.close
path
end
end
def get_hatena_graph(config, data)
graph = HatenaGraph.new(config['user_id'], config['password'])
graph.login
csvpath = graph.fetch_csv
csv = CSV.open(csvpath, "r").map{|r| r }
graph_names = csv.shift
i = graph_names.index(config['graph_name'].tosjis)
csv.map{|r| r[i].to_f }
end

設定ファイルはこんな感じ。

- module: get_hatena_graph
config:
user_id: takatoh
password: xxxxxxxx
graph_name: "読んだページ数"

argv.rb

小物その1,コマンドラインからデータを取得。

def argv(config,data)
return ARGV.clone
end

average.rb

小物その2,平均。

def average(config, data)
sum = data.inject(0.0){|a,b| a + b.to_f }
return [ sum / data.size ]
end