Calendar
Sun Mon Tue Wed Thu Fri Sat
1234567
891011121314
15161718192021
22232425262728
293031    
<< January 2012 >>
Profile
MySpace oniTunesStore onAmazonMP3
Selected Entries
Recent Comments
Categories
Archives
Links
Others
Recommend
ご冗談でしょう、ファインマンさん〈上〉
ご冗談でしょう、ファインマンさん〈上〉 (JUGEMレビュー »)
リチャード P. ファインマン, Richard P. Feynman, 大貫 昌子



????????

浅学非才の身を恐れず、思いつきを書く日記
単純作業を置換した場合のソフトウェアの価値
ユーザー企業だと、30代くらいから上はソフトウェアの価値を
測れません(無能レベルに達している)。

自分の場合は経験があるのは2社ですが。。

あと、大学卒で入ってきても卒論がなかったりコピペで
済ませてきた人はPCを全然使えないです、ていうか
分数の割り算できないです。
(これからどうなるかは不明)。

今の時代だからもっと普通に使いこなせるのかと思ったら、
意外にそうでもないんですよね。一番重要なのは「使える」
よりも「使う方法を調べられる」ほうですが。

なんかすごそう、で給料もらえたらいいんですが、大抵の
場合は営業推しでなめられる場合が多いです。

それで単純作業を置換した場合は、バイトを雇った体で
見積もりも説得力を増すかなと思ってやってみます。

今回のspiderは冬休みに作ったので、実質投資0円でも
いいんですが、、まぁ72時間使ったとして大体▲3万円で
いいです。

■やってること
1. 4アクセス/分 -- ランダムに。
2. ぺたぺた返し500件/日 -- ゆっくりランダムに。
3. 読者登録申請250件/日

■1ヶ月の見積もり
バイトは沖縄の時給600円レベルで計算
1. 24h稼働してるので。
  24h * 30day * 600 =  ¥432,000
2. 休日もcronで稼働+人がやると4h/dayくらいですね。
    #15秒に一回換算、だけど休みなしで動くからな。。
  4h * 30day * 600 = ¥72,000
3. これは面倒くさい。人手でやったら1件/minuteかな。
  (250/60)h * 30day * 600 = ¥75,000

■合計
1. + 2. + 3. =  ¥579,000

なんか、、想像よりスゲー結果になった。
初期投資は消し飛びますね。

あれですね、売上げにつながってはいないのと、全額従業員に
払うと自分を雇っている意味がなくなるので、50%もらうと
しましょうか。

¥289,500 -- あれ?

しかもこれ以外にメインの仕事が8h/dayはあるわけで。
搾取されてますねー、社畜ですねー。
| 2012.01.07 Saturday * 16:25 | 開 発 | comments(0) | trackbacks(0) |
Perlの文字列型
手元に「はじめてのPerl」はあるんですが、いまいち書いてない。

Perlで型っていうとリファレンスとデリファレンス関係が
圧倒的に多いですね。

それはそれとして、intだとか何だとかは勝手に解釈して
くれるらしい。のですが、spiderを動かしてみて警告が
出るんですよね。

PHPにあるin_arrayを模したメソッドで、コピったもの。
こういう所も書かなきゃいけないのがつらい所。。

アカウントの比較に用いているので、想定は文字列なんですが、
アカウントが数字だけの人も見ているとあります。

【before】
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;
}

【after】
sub in_array() {
 my $self = shift;
 my ($val,$array_ref) = @_;
 foreach my $elem (@$array_ref) {
   # 最後に' 'を入れて文字列型にキャスト
   if( "$val " eq "$elem " ) { return 1; }
 }
 return 0;
}

ええ、JavaScriptと同じ手法で逃げました。。
| 2012.01.05 Thursday * 19:13 | 開 発 | comments(0) | trackbacks(0) |
両思いになれないなら削除しちゃうんだからね!!
せっかく業務ロジックを切り出したので、仕事が始まる前に
一つ機能を追加してみよう。

と思ったのはいいんですが、、てこずりました。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;
| 2012.01.03 Tuesday * 01:09 | 開 発 | comments(0) | trackbacks(0) |
最近読んだ本
そっちの世界の人には「当たり前」なんだろうけど、世間一般では受け入れられていない(ように感じられる)ことに、実在と現象の違いがある。

なぁということを福岡伸一の最新の単行本を読んで、再度思い直した。キーボード打つ事で考えをまとめてみようか。

読んでみて、たぶん、実在と現象を区別して認識しているだろうなと思われる人。

宮沢賢治
柳澤圭子
養老孟司
竹内薫
福岡伸一
岩田健太郎

最初に現象について言及していたのは、竹内薫だった。モノからコトへ、という表現だったと記憶しているが、最初読んだときは何言ってるかさっぱりわからん、だった。たぶんこの人は深い内省をしていると思うんだが、表現が下手だと思う。

次に出会ったのが、完全にダウナーだったときに読んだ柳澤圭子だった。この人自身も、訳わからんつらすぎる病を煩って一旦は完璧に落ちたと思う。

ここら辺から段々、世界を「現象」として見ることができるようになってきた。

福岡伸一、岩田健太郎あたりで完全に覚醒した。

そのあと、宮沢賢治が「わたくしといふ現象は」と詩に書いているのを再発見して、完全に打ちのめされた。子供のころは「なんとなく格好いい表現」くらいにしか思ってなかったのに。もっと前から、世界を「現象」として見つめて芸術に昇華させている人がいるなんて。

しかも彼は地質学者、自然科学者でもあるじゃないか。到底越えられないと思った。

養老孟司については、並行してずっと読んでたんだが、ここ数年でなんだ、同じことを言ってるんだということがわかってきた。

福岡伸一は養老孟司と非常に話が合うに違いない。書いている事が一緒だから。

例えば目の前の赤いリンゴを、普通は物として捉えると思う。だけど、これがリンゴという現象だ、と表現したら、普通の人はバカ言ってんじゃないよ、と言うと思う(言いますよね!?)。

それってどっちが当たり前なんだろうか。社交性がなくてサンプルを取れないからあまりわからない。
| 2011.12.29 Thursday * 16:19 | 雑 記 | comments(0) | trackbacks(0) |
Perlでオブジェクト指向とファクトリーメソッドもどきをしてみる
spiderと言ってもメインの処理は、ログイン->データ漁るなので、バッチ処理みたいなもんですよね。

なので「データ漁る」所を切り出せば見通しが良くなるし、処理を共通化できるだろうと。

簡単な例を調べながら書いていたら、意外にあっさり動いたので。。

ファイルとしては次の4つで済みます。

main.pl メインスレッド(今まではここにごちゃごちゃ書いてた)。
Biz.pm    業務ロジックの親クラス
BizRegist.pm 業務ロジック(読者登録)
BizGenreRegist.pm 業務ロジック(ジャンル別読者登録)

メインスレッドで「データ漁り」は$obj->do_biz();の部分だけです。
【main.pl】
use strict;
# 既成のライブラリの読み込み
use URI;
use HTTP::Cookies;
use LWP 5.64;
use WWW::Mechanize;
use Encode;
use Data::Dumper;
use HTTP::Cookies::Microsoft;
use Win32::TieRegistry(Delimiter => "/");
use utf8;
use encoding 'cp932';
binmode(STDERR, ':raw :encoding(cp932)');
$Data::Dumper::Indent = 1;
# 自作のライブラリの読み込み
use Biz;
use BizRegistReader;
use BizRegistGenreReader;

# 共通の初期設定(INIファイルに追い出したい)。
my $obj;
my $order = shift;
my $account = "your account";
my $pass = "your pass";
my $base = "http://www.ameba.jp/";
my $user_agent = 'Mozilla/4.0 (compatible; MSIE 9.0; 適当に書いてください';

my $mech = WWW::Mechanize->new(
 agent => $user_agent,
 autocheck => 1,
 cookie_jar => {}, );
$mech->cookie_jar();

# 業務処理クラスのインスタンスを生成する(ファクトリーに追い出したい)。
if($order eq 'regist'){
 $obj = BizRegistReader->new( $account, $pass, $mech, $base );
}elsif($order eq 'regist_genre'){
 $obj = BizRegistGenreReader->new( $account, $pass, $mech, $base );
}

# それぞれのビジネスロジックを実行する。
$obj->do_biz();
exit;

データ漁りの親分(ログインなど共通処理はまとめてしまう)
【Biz.pm】
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,   
  'y'     => 18 );

 $m->success or die "failed to login",$m->response->status_line;
}

# 実際のspiderの処理
sub do_biz {}
1;

【BizRegistReader.pm】
package BizRegistReader;

# Bizクラスを継承する。
use base 'Biz';

sub do_biz {
 my $self = shift;
 my $m = $self->{mech};
 
 $self->login;
 
 # 読者登録のspiderの仕事をシコシコ書く。
 print "BizRegistReader";
}
1;

【BizRegistGenreReader.pm】
package BizRegistGenreReader;

# Bizクラスを継承する。
use base 'Biz';

sub do_biz {
 my $self = shift;
 my $m = $self->{mech};
 
 $self->login;
 
 # ジャンル別読者登録のspiderの仕事をシコシコ書く。
 print "BizRegistGenreReader";
}
1;

■親分のdo_bizをオーバーロード?オーバーライド?して、個々の「データ漁り」を書いていけばOKになります。

■新しく何かやりたくなったら(ぺたぺたしたいとか)、Biz*.pmを追加して行けば良いので、メインスレッドはこれ以上ごちゃごちゃにならないです。

■呼び出し方
perl main.pl regist でBizRegistReader->do_bizを実行します。
perl main.pl regist_genre でBizRegistGenreReader->do_bizを実行します。
| 2011.12.29 Thursday * 15:02 | 開 発 | comments(0) | trackbacks(0) |


| 1/104Pages | >>