大分すっきりしてきた

  • 僕にはクックブックで例を見ながら、というスタイルがあっているようだ
  • WebDBのPerlのコーナーも参考になる
  • Javaで勉強したことが役に立っていると思う
  • 微妙に違う付近は継承使って、ごまかし(?)た
  • YAMLを使ってメアドとパスワードは別ファイルに書き出すようにした*1
  • コンストラクタの付近とかがもうちょっと改良しないと
  • とにもかくにも初めてPerlで継承とかそっちの付近ができてよかったのでありました
#!/usr/bin/perl

package Hatena::Counter;
use strict;
use warnings;
use WWW::Mechanize;
use WWW::Mechanize::DecodedContent;
use URI;
use Web::Scraper;
use Encode;
use Time::Local;
use Time::localtime;
use File::Spec;
use File::HomeDir;
use Term::Prompt;
use YAML;

sub new() {
    my ($class) = @_;
    bless {
        year      => $_[1],
        month     => $_[2],
        is_recent => $_[3],
    }, $class;
}

sub login() {
    my $self  = shift;
    my $year  = $self->{year};
    my $month = $self->{month};

    my $config   = $self->prepare_config();
    my $name     = $config->{name};
    my $password = $config->{password};

    my $mech = new WWW::Mechanize( autocheck => 1 );
    $mech->get('https://www.hatena.ne.jp/login');

    $mech->submit_form(
        fields => {
            name     => $name,
            password => $password,
        },
    );
    return ($mech);
}

sub get_count() {

    #インターフェイス
}

sub scrape() {
    my $self = shift;
    my $mech = shift;
    scraper {
        process 'div#dailyreport>div.report_table>table.report>tr>td',
          'count[]' => 'TEXT';
        result qw/count/;
    }
    ->scrape( $mech->decoded_content );
}

sub convert_counter() {
    my $self  = shift;
    my $count = shift;
    my $year  = $self->{year};
    my $month = $self->{month};

    my %counter = ();
    foreach ( my $i = 0 ; $i < scalar(@$count) ; $i = $i + 3 ) {
        my @days = split( /\//, @$count[$i] );
        $counter{ timelocal( 0, 0, 0, $days[1], $days[0] - 1, $year ) } =
          @$count[ $i + 2 ];
    }
    return (%counter);
}

sub get_date_and_count() {
    my $self    = shift;
    my $year    = $self->{year};
    my $month   = $self->{month};
    my %counter = @_;
    my $mday;
    my $mon;
    my $wday;
    my $text;
    my $date;

    foreach my $day ( sort keys %counter ) {
        $date = scalar( localtime($day) );
        $mday = $date->mday;
        $mon  = $date->mon + 1;
        $wday = $date->wday;
        $text .= "$mday,$mon,$wday,$counter{$day}\n";
    }
    return ($text);
}

sub prepare_config {
    my $path = File::Spec->catfile( File::HomeDir->my_home, ".hatena_counter" );
    my $config = eval { YAML::LoadFile($path) } || {};

    my $save;
    while ( !$config->{name} || !$config->{password} ) {
        $config->{name}     = prompt( 'x', 'name: ',     '', '' );
        $config->{password} = prompt( 'p', 'password: ', '', '' );
        $save++;
    }

    YAML::DumpFile( $path, $config ) if $save;
    chmod 0600, $path;

    return $config;
}

package Hatena::Counter::Recent;
use base 'Hatena::Counter';

use strict;
use warnings;

use WWW::Mechanize;
use WWW::Mechanize::DecodedContent;
use URI;
use Web::Scraper;
use Encode;
use Time::Local;
use Time::localtime;

sub get_count() {
    my $self  = shift;
    my $year  = $self->{year};
    my $month = $self->{month};

    my $mech = $self->login();

    $mech->get('http://counter.hatena.ne.jp/syou6162/?cid=1');

    my $count = $self->scrape($mech);

    return ($self->convert_counter($count));
}

package Hatena::Counter::Month;
use base 'Hatena::Counter';

use strict;
use warnings;

use WWW::Mechanize;
use WWW::Mechanize::DecodedContent;
use URI;
use Web::Scraper;
use Encode;
use Time::Local;
use Time::localtime;

sub get_limit_day() {
    my $self  = shift;
    my $year  = $self->{year};
    my $month = $self->{month};
    my $tm    = timelocal( 0, 0, 0, 1, $month, $year ) - 60 * 60 * 24;
    return ( localtime($tm)->mday );
}

sub get_count() {
    my $self  = shift;
    my $year  = $self->{year};
    my $month = $self->{month};

    my $mech = $self->login();

    if ( length($month) == 1 ) {
        $month = "0$month";
    }
    my $url =
        'http://counter.hatena.ne.jp/syou6162/report?cid=1&date=' 
      . $year . '-'
      . $month
      . '-01&mode=access&type=monthly';
    $mech->get($url);

    my $count = $self->scrape($mech);

    my %counter = ();
    my $newcount;
    if ( $self->{is_recent} == 0 ) {
        foreach ( my $i = 0 ; $i < get_limit_day() * 3 ; $i = $i + 3 ) {
            @$newcount[$i]       = @$count[$i];
            @$newcount[ $i + 1 ] = @$count[ $i + 1 ];
            @$newcount[ $i + 2 ] = @$count[ $i + 2 ];
        }
    }
    $count = $newcount;
    foreach ( my $i = 0 ; $i < scalar(@$count) ; $i = $i + 3 ) {
        my @days = split( /\//, @$count[$i] );
        $counter{ timelocal( 0, 0, 0, $days[1], $days[0] - 1, $year ) } =
          @$count[ $i + 2 ];
    }
    return (%counter);
}

package main;

my $counter = Hatena::Counter::Recent->new( 2007, 10, 0 );
#コンストラクタ付近がいまいち
my %counter = $counter->get_count();
print $counter->get_date_and_count(%counter);

*1:http://blog.kentarok.org/2007/04/05/232531.htmlを参考にさせてもらいました!