せっかく業務ロジックを切り出したので、仕事が始まる前に
一つ機能を追加してみよう。
と思ったのはいいんですが、、てこずりました。Perlが変数に参照を
入れたり入れなかったりするので、その記法を調べながら、
Scraperの仕様を調べながら、、と。
相互読者登録に至らなかったら、読者登録を削除する
(読者登録数が1,000だという噂)感じです。
ファイルは1つしか追加していません(追加機能分のBizAdjustReader.pmだけ)。
一つのメソッドが同じ行数くらいでまとまっているので、
そんなにひどくはないと思うんですが、最後はごり押しに
なってしまいました。
あと、一回きちんとライブラリの仕様書を読んだほうがいいですね。。
共通化できる部分をまとめて切り出し。
【Biz.pm】
#! /usr/bin/perl -w
package Biz;
# コンストラクタ
sub new {
my $class = shift;
my ( $account, $pass, $mech, $base ) = @_ ;
my $self = {
account => $account,
pass => $pass,
mech => $mech,
base_uri => $base };
return bless $self, $class;
}
# ログイン(共通処理)
sub login {
my $self = shift;
my $m = $self->{mech};
# ログインページにアクセスする。
my $response = $m->get( $self->{base_uri} );
die $m->response->status_line unless $m->success;
# フォームを選択し、ログインフィールドに入力する。
$m->form_name('srvLoginForm');
$m->set_fields(
'amebaId' => $self->{account},
'password' => $self->{pass}, );
# サブミットする(ログイン)。
$response = $m->click_button( 'input' => $m->current_form()->find_input(undef, 'image'),
'x' => 57, # 画像の場合はクリックしたx,y座標が必要なことがある。
'y' => 18 );
$m->success or die "failed to login",$m->response->status_line;
}
# ページ内のリンクからアメーバIDを抜き出す
# $_[0] :アメーバIDを含むURLを判定する正規表現
# $_[1] :URLからアメーバIDを抜き出す正規表現
sub get_ameba_id_from_links{
my $self = shift;
my $m = $self->{mech};
# ページの全てのリンクを取得する。
my $ameba_id = "";
my @ameba_ids = ();
my @links = $m->links();
foreach my $link (@links){
# URLにアメーバIDを含むものを抜き出す。
if( $link->url =~ /$_[0]/ ){
# URLからアメーバIDを抜き出す。
#(e.g.)http://profile.ameba.jp/mori-no-kuma-san1972/
my $temp_id = "";
($temp_id = $link->url) =~ s|$_[1]||;
# 後ろのスラッシュを除去する
($ameba_id = $temp_id) =~ s|¥/||;
push( @ameba_ids, $ameba_id );
}
}
return @ameba_ids;
}
# 配列の中に特定の値があるかどうか判定する。
sub in_array() {
my $self = shift;
my ($val,$array_ref) = @_;
foreach my $elem (@$array_ref) {
if($val=~m/^[0-9]+$/){
if($val == $elem) { return 1; }
}else{
if($val eq $elem) { return 1; }
}
}
return 0;
}
# 実際のspiderの処理
sub do_biz {}
1;
ごりごりお仕事を書きます。泥臭いです。。
【BizAdjustReader.pm】
#! /usr/bin/perl -w
package BizAdjustReader;
# Bizクラスを継承する。
use base 'Biz';
sub do_biz {
my $self = shift;
my $m = $self->{mech};
$self->login;
# 自分のブログ読者のアメーバIDの配列を取得する。
my @readers = ();
@readers = $self->get_readerlist;
#print "$_¥n" foreach(@readers);
# 自分が読者登録した人一覧の最大ページ数を取得する。
my $favorite_max_page = $self->get_favoritelist_page_num;
# 片思いの場合はお気に入りから削除する。
$self->adjust_reader( ¥@readers, $favorite_max_page );
}
# 自分のブログの読者のアメーバIDを取得する。
sub get_readerlist {
my $self = shift;
my $m = $self->{mech};
# readerlistのページ数を取得する。
#(e.g.)<input type="hidden" name="maxPage" value="3" />
my $url = "http://blog.ameba.jp/ucs/reader/readerlist.do?pageID=1";
my $response = $m->get($url);
$m->success or die "failed to get readerlist URL", $m->response->status_line;
my $reader_max_page = $m->value( "maxPage" );
print "Max page of my blogs readerlist is $reader_max_page¥n";
# 読者になってくれた人のアメーバIDを取得する。
#(e.g.)http://blog.ameba.jp/ucs/reader/readerlist.do?pageID=1
my @readers = ();
for (my $i = 1; $i <= $reader_max_page; $i++) {
$url = "http://blog.ameba.jp/ucs/reader/readerlist.do?pageID=$i";
$response = $m->get( $url );
$m->success or die "failed to get readerlist pageID = $i", $m->response->status_line;
push( @readers, $self->get_ameba_id_from_links("http¥:¥/¥/profile.ameba.jp¥/", "http¥:¥/¥/profile.ameba.jp¥/") );
}
return @readers;
}
# 自分が読者登録した一覧の最大ページ数を取得する
sub get_favoritelist_page_num {
my $self = shift;
my $m = $self->{mech};
# favoritelistのページ数を取得する。
#(e.g.)<input type="hidden" name="maxPage" value="13" />
my $url = "http://blog.ameba.jp/ucs/blgfavorite/favoritelist.do?pageID=1";
my $response = $m->get( $url );
$m->success or die "failed to get favoritelist URL", $m->response->status_line;
my $favorite_max_page = $m->value( "maxPage" );
print "Max page of my favoritelist is $favorite_max_page¥n";
return $favorite_max_page;
}
# 相互読者登録してくれない人をお気に入りから削除する
sub adjust_reader {
use Web::Scraper;
use YAML;
my $self = shift;
my $m = $self->{mech};
my ( $readers, $max_page_num ) = @_;
my $url = "";
my $response = "";
my $scraper = scraper {
# 削除チェックボックスへのXPath
process '/html/body/div[4]/div[2]/div/div[3]/div/form/table/tbody/tr/td[4]/input[2]',
'check_box[]' => { value => '@value',
name => '@name', };
# ブログリンクへのXPath(アカウントを正規表現で取り出す)。
process '/html/body/div[4]/div[2]/div/div[3]/div/form/table/tbody/tr/td/a',
'accounts[]' => ['@href', sub { s|http¥:¥/¥/ameblo.jp¥/||; s|¥/||; } ];
};
# 自分が読者登録した人の一覧の最後ページから処理する。
for (my $i = $max_page_num ; $i > 0 ; $i--){
$url = "http://blog.ameba.jp/ucs/blgfavorite/favoritelist.do?pageID=$i";
$response = $m->get( $url );
$m->success or die "failed to get favoritelist pageID = $i", $m->response->status_line;
my $result = $scraper->scrape($m->content, $m->uri);
my $check_boxes = $result->{check_box};
my $accounts = $result->{accounts};
my $delete = 0;
$m->form_name('favoriteListForm');
# 1ページ内の読者数分だけ処理をする。
for (my $ii = 0 ; $ii <= $#{$accounts} ; $ii++){
if( $self->in_array( $$accounts[$ii], $readers ) ){
print "Alive target : $$accounts[$ii] ¥n";
}else{
print "Delete target : $$accounts[$ii] ¥n";
# 削除チェックボックスをチェックする。
$m->tick( $$check_boxes[$ii]->{name}, $$check_boxes[$ii]->{value} );
$delete = 1;
}
}
# チェックボックスをチェックした場合は削除ボタンを押す。
if( $delete ){
$response = $m->submit_form( button => 'delete_confirm_mode' );
$m->success or die "failed to delete favoritelist", $m->response->status_line;
# 削除確認画面の削除ボタンを押す。
$m->form_name('favoriteListForm');
$response = $m->submit_form();
$m->success or die "failed to confirm of delete favoritelist", $m->response->status_line;
}
} #for end
} #sub end
1;