ホントははてなブックマークから任意文字列を検索して、ヒットしたURLなりなんなりを返すようなperlスクリプト作りたかったんですけど、アイディアも設計も経験もないのに作り始めたので、クソなのができました。
やっぱしプログラムは考えてから作ろう。。。
恥ずかしさで胸いっぱいになっていろいろ勉強することにする!
大失敗
- アイディアとして、ブックマークURLを得た後、そのURLから本文だけ抜き出してgrepみたいなことをするのを考えていた
- ブックマークURLぶっこぬくスクリプト書こー
- よく考えると、全部そんなことしてたらクソ遅くね?
- ローカルにコンテンツ置いとけばいいんじゃね?
- もう一回よく考えると、それオンラインのブックマークの利点完全に消してね?
- 投了しました
設計くらいちゃんとしろという例。
気づいたダメな点
- コードがダメという以前に
- WWW::Mechanizeを内部でもつ意味があったのか
- ブックマークURLを得るためにはタグを予め取得する必要がある
- タグをdecodeしてまたencodeするとかすることになる。
- 最初から壮大なスクリプトを空想していたらダメ。それ妄想ですから。
- おおまかな設計くらい考えてから作る
続々追記予定
言っておくこと
- WWW::Hatena::Scraperを一部参考にしましたありがとうございました。
- WWW::Hatena::Scraperの$cansslまわり正しい?
やってること
- b.hatena.ne.jp/kiririmodeからclassがtag-*になっているリンクをぶっこ抜き(タグのため)
- b.hatena.ne.jp/kiririmode/$tagからclassがbookmarkになっているリンクをぶっこ抜き(これがブックマークURL)
使い方
use strict; use BookmarkFinder; my $bf = BookmarkFinder->new( 'はてなID', 'はてなパスワード' ); my $tags = $bf->fetch_tags; print join "\n", @$tags, "\n"; # タグ一覧 my $urls = $bf->fetch_urls( $tags ); print join "\n", @$urls, "\n"; # ブックマークURI一覧
TODO
- やっぱりデザインパターンとかの勉強する。
- 日本語の扱いがよくわかってないのでこっちも。
package BookmarkFinder; use strict; use base qw(Class::Accessor::Fast); use vars qw($can_ssl); use HTML::Feature qw(feature); use WWW::Mechanize; use Carp; use CGI::Lite; __PACKAGE__->mk_accessors( qw(agent uri_login) ); sub p { print Dumper shift } BEGIN { eval { use Crypt::SSLeay; }; $can_ssl = ! $@; } use constant LOGIN_URL => 'http://www.hatena.ne.jp/login'; use constant BOOKMARK_URL => 'http://b.hatena.ne.jp'; # Constructor sub new { my $self = shift; my ($id, $pass) = @_; $self = bless {}, $self; # substitute http with https my $login = LOGIN_URL; $login =~ s/^http/https/ if $can_ssl; $self->{uri_login} = $login; $self->{conf}->{name} = $id; $self->{conf}->{pass} = $pass; $self->{conf}->{dir} = '.bookmark'; $self->agent( WWW::Mechanize->new( autocheck => 1 ) ); $self->agent->agent_alias( 'Windows Mozilla' ); $self; } # login hatena service sub login { my $self = shift; my ($id, $pass) = @_; $self->agent->get( $self->uri_login ); $self->agent->submit_form( with_fields => { name => $self->{conf}->{name}, password => $self->{conf}->{pass} } ); $self->agent->success() or croak "login failed"; } sub fetch_tags { my ($self, $id) = @_; $id ||= $self->{conf}->{name}; my $url = BOOKMARK_URL . "/$id"; $self->agent->get( $url ); my @tags = map { $_->url() } $self->agent->find_all_links( class_regex => qr/tag-.*/ ); @tags = map { url_decode( $_ ) } map { m[^/.*/(.*)/$]; $1 } @tags; $self->{tags} = \@tags; return wantarray? @tags : \@tags; } sub fetch_urls { my ($self, $tags, $id) = @_; $tags ||= $self->{tags}; $id ||= $self->{conf}->{name}; my @urls; for my $tag (@$tags) { print "processing $tag\n"; $self->agent->get( BOOKMARK_URL . "/$id/" . url_encode( $tag )); push @urls, $self->agent->find_all_links( class_regex => qr/^bookmark$/ ); } my %seen; @urls = grep { ! $seen{$_}++ } map { $_->url() } @urls; $self->{urls} = \@urls; return wantarray? @urls : \@urls; } 1;
あーfetch_urlsの部分消してしまったぁぁあああ!!(バージョン管理もしてなかた)
あとで書き直す。
ローカルに落とす
オンラインブックマークの利点を最大限消すステキ仕様。
HTML::Featureつかったけど、抽出精度がとてもいい!ステキだ。
ローカルに落としたあとはコマンドラインからgrepする!(アイディアがダメだと気づいた時点で力尽きた)
文字コードはたぶんutf-8?
sub store_contents { my ($self, $urls) = @_; my $dir = $self->{conf}->{dir}; for my $url ( @$urls ) { my $filename = $url; $filename =~ s!^https?://!!; $filename =~ s/[\W]/-/g; my $filename = "$dir/$filename.dat"; next if -e $filename; my %feature = feature( $url ); print "writing to $filename\n"; open FILE, '>', $filename or carp "cannot open $filename"; print FILE $feature{text}; close FILE or carp "cannot close $filename"; } }