PlaggerとWeb::Scraperでアクセスランキングを出してみる

久々にPlaってみました。アクセスログを集計して結果(上位10件)をRSSで出力するようにしてみました。

処理の流れ(変に遠回りしてる気もしますが)
  1. ログファイルをもとにアクセス数をカウント
  2. アクセス数が多い順にソート
  3. ページにアクセス
  4. Web::Scraperスクレイピングしてtitleとメタタグのdescriptionを取得
  5. エントリーオブジェクトを生成
  6. エントリーオブジェクトをPlagger(Publish::Feed)に渡して出力

そこまでスクリプト書いたんならPlaggerに渡さなくても(XML::Feed使え)...とか言われるかなぁ。
まぁ一応やってみたんで。

以下レシピとスクリプトです。

global:
  timezone: Asia/Tokyo

plugins:
  - module: CustomFeed::Script
  - module: Subscription::Config
    config: 
      feed:   
       - script: /home/akihito/rank.pl

  - module: Publish::Feed
    config: 
      format: RSS
      dir: /home/akihito/
      filename: rank.rss
  • rank.pl
use strict;
use YAML::Syck;
use IO::File;
use Web::Scraper;
use URI;

my $log = '/etc/httpd/logs/access_log';
my $domain = 'http://example.com';

my $f = new IO::File();
$f->open($log);
my %url;
while(my $line = <$f>){
    if( $line =~ /[GET|POST]+\ (\S+)\ HTTP/ ){
        $url{$1} = $url{$1}?$url{$1}+1:1;
    }
}
$f->close;

my @rank;
my $count = 0;
for my $key ( reverse sort {$url{$a} <=> $url{$b}} keys %url){
    last if( $count >= 10 );
    if( $key !~ /\.(jpeg|jpg|gif|png|css|js|ico)$/ ){ 
        my $uri = $domain.$key;
        $count++;
        my $links = scraper {
           process 'title','title[]' => 'TEXT'; 
           process 'meta','description[]' =>
                 sub{
                     return $_->attr_get_i('content')
                       if($_->attr_get_i('name') =~ /description/i && $_->attr_get_i('content'));
                     return; 
                };    
           result qw/title description/
        }->scrape(URI->new($uri));
        push @rank,{ 
                       link     => $uri,
                       title    => $links->{title}->[0],
                       body     => $links->{description}->[0],
                   };
    }
}

my $output = {};
$output->{entry} = \@rank;

print YAML::Syck::Dump $output;