SweetPotato::Plagger このページをアンテナに追加 RSSフィード

2006-11-14

[] CustomFeed::MelonBooks 02:53  CustomFeed::MelonBooks - SweetPotato::Plagger を含むブックマーク はてなブックマーク -  CustomFeed::MelonBooks - SweetPotato::Plagger  CustomFeed::MelonBooks - SweetPotato::Plagger のブックマークコメント

このプラグインはWeb::Scraperを用いて書き直されました。最新版はCodeReposに置いてあります。

メロンブックス通信販売の入荷日別アイテムリストを取得し,アイテム毎にエントリを作成する。同人誌,同人ソフト,同人グッズのリストに対応。

Plagger/Plugin/CustomFeed/MelonBooks.pm

リファクタリングを行った。

package Plagger::Plugin::CustomFeed::MelonBooks;
use strict;
use warnings;
use base qw( Plagger::Plugin );

use HTML::TreeBuilder::XPath;
use Plagger::Entry;
use Plagger::Feed;
use Plagger::Util;
use URI;

sub register {
    my ($self, $context) = @_;
    $context->register_hook(
        $self,
        'subscription.load' => \&load,
    );
}

sub load {
    my ($self, $context) = @_;

    my $day = $self->conf->{day} || Plagger::Date->now()->strftime('%Y/%m/%d');

    my $feed = Plagger::Feed->new;
    $feed->aggregator( sub { $self->aggregate($context, $day); } );
    $context->subscription->add($feed);
}

sub aggregate {
    my($self, $context, $day) = @_;

    my $feed = Plagger::Feed->new;
       $feed->title("MelonBooks $day");
       $feed->link('http://shop.melonbooks.co.jp/tsuhan/system/index.php?RATED=18');

    $day =~ s!/!%2F!g;

    my $list = [];
    for my $genre (
        '%C6%B1%BF%CD%BB%EF',             # Dojinshi
        '%C6%B1%BF%CD%A5%BD%A5%D5%A5%C8', # Dojin Soft
        '%C6%B1%BF%CD%A5%B0%A5%C3%A5%BA', # Dojin Goods
    ) {
        push @$list, $self->parse_list($day, $genre);
    }

    for my $item (@$list) {
        my $entry = Plagger::Entry->new;
           $entry->title($item->{title});
           $entry->link($item->{link});
           $entry->author($item->{circle});
           $entry->tags($item->{genres});
           $entry->body(join '', map { qq!<img src="$_">! } @{$item->{images}});
        $feed->add_entry($entry);
    }

    $context->update->add($feed);
}

sub parse_list {
    my ($self, $arrival, $genre) = @_;

    my $list = [];
    for (my $dispstart = 0;; $dispstart += 10) {
         my $content = Plagger::Util::load_uri(URI->new(
             "http://shop.melonbooks.co.jp/tsuhan/system/list.php"
           . "?RATED=18&DISPACTION=disppage&ARRIVAL=$arrival&DISPSTART=$dispstart&GENRE=$genre"
           . "&DISPEMPTY=&CHGRATE=&DISPSTARTCHG=0&DISPORDER=maker&DISPPAGE=10&DISPSTYLE=desc"
         ));

        last unless $content =~ /<OPTION VALUE="(\d+)" SELECTED >/;
        last unless $dispstart == $1;

        my $tree = HTML::TreeBuilder::XPath->new;
           $tree->parse($content);
        my $nodelist = eval { $tree->findnodes('//body//table[@bordercolor="white"]') };
        if ($@) {
            $self->log( error => $@ );
            next;
        }

        for my $node (@$nodelist) {
            my $item = $genre eq '%C6%B1%BF%CD%BB%EF' # Dojinshi
                     ? $self->parse_dojinshi($node->as_HTML('<>&'))
                     : $self->parse_non_dojinshi($node->as_HTML('<>&'));
            push @$list, $item if $item;
        }
    }

    wantarray ? @$list : $list;
}

sub parse_dojinshi {
    my ($self, $content) = @_;

    $content =~ m{
           <td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?><.*?>(.*?)</.*?>
    }x ? $self->to_hashref($1, $2, $3, [$4]) : undef;
}

sub parse_non_dojinshi {
    my ($self, $content) = @_;

    $content =~ m{
           <td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?><.*?>(.*?)</.*?>
        .*?<td[ ]bgcolor="whitesmoke"[ ]valign="middle"><.*?><.*?>(.*?)</.*?>
    }x ? $self->to_hashref($1, $2, $3, [$4, $5]) : undef;
}

sub to_hashref {
    my ($self, $title, $circle, $id, $genres) = @_;

    my @images = map { "http://shop.melonbooks.co.jp/img/$id$_.gif" } ('', 'a', 'b');
    return {
        title  => $title,
        link   => "http://shop.melonbooks.co.jp/tsuhan/system/detail.php?RATED=18&ITEM_ID_FULL=$id",
        circle => $circle,
        genres => $genres,
        images => \@images,
    };
}

1;

config.melonbooks.yaml

plugins:
  - module: CustomFeed::MelonBooks
    config:
      day: 2006/11/14

dayは %Y/%m/%d 形式で指定する。指定しなかった場合は今日入荷したアイテムのリストを取得する。

スクリーンショット(with Publish::Gmail)

f:id:SweetPotato:20061021160745p:image