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

2007-02-16

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

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

太洋社コミック発売予定一覧の「発売日順」表を解析し,コミックごとにエントリ化する。

CustomFeed::Manganomoriとやっていることは似ているので,普段信頼している情報源にあわせてお好きな方をどうぞ。

Plagger/Plugin/CustomFeed/TaiyoshaComic.pm

モジュール内で日本語を使用しているので,UTF-8(BOMなし)で保存すること。

package Plagger::Plugin::CustomFeed::TaiyoshaComic;
use utf8;
use strict;
use base qw( Plagger::Plugin );

use Plagger::Date;
use Plagger::Util;
use Switch;
use URI;

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

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

    my $ym = $self->conf->{month} || Plagger::Date->now()->strftime("%y%m");

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

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

    my @urls = map { "http://www.taiyosha.co.jp/comic/comic${ym}_date${_}.html" } (1..2);

    my $feed = Plagger::Feed->new;
    $feed->link($urls[0]);
    $feed->title("大洋社 コミック発売一覧 $ym");

    for my $url (@urls) {
        my $list = $self->parse(Plagger::Util::load_uri(URI->new($url)));

        for my $item (@$list) {
            my $entry = Plagger::Entry->new;
            $entry->title($item->{title});
            $entry->author($item->{author});
            $entry->tags([$item->{publisher}]);
            $entry->body(join ', ', ($item->{author}, $item->{publisher}, $item->{price}));
            $entry->body($entry->body.', '.$item->{shoseki}) if $item->{shoseki};

            if ($item->{day} !~ /^\d+$/) {
                $entry->body($item->{day}.'旬, '.$entry->body);
                $item->{day} = $self->part_to_day($item->{day});
            }
            $entry->date(Plagger::Date->strptime("%y%m%d", $ym.$item->{day}));

            $feed->add_entry($entry);
        }
    }

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

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

    my $list = [];
    while ($content =~ m{
        <TR><TD
        .*?<font.*?>(.*?)/(.*?)</font>
        .*?<font.*?>(.*?)</font>
        .*?<font.*?>(.*?)</font>
        .*?<font.*?>(.*?)</font>
        .*?<font.*?>(.*?)</font>
        .*?<font.*?>(.*?)</font>
    }gsx) {
        push @$list, {
            month => $1, day => $2, publisher => $3, title => $4,
            author => $5, price => $6, shoseki => $7,
        };
    }

    $list;
}

sub part_to_day {
    my ($self, $part) = @_;

    switch ($part) {
        case '上' { return "01"; }
        case '中' { return "11"; }
        case '下' { return "21"; }
    }

    $part;
}

1;

config.taiyosha_comic.yaml

monthには取得したいコミック一覧の年月を %y%m 形式で指定する。指定しない場合は今月のコミック一覧を取得する。

以下の例では出力にPublish::iCalを使用。

plugins:
  - module: CustomFeed::TaiyoshaComic
    config:
      month: 0702
  - module: Publish::iCal
    config:
      dir: .
      filename: taiyosha_comic.ics

関連

トラックバック - http://plagger.g.hatena.ne.jp/SweetPotato/20070216

2006-11-19

[] CustomFeed::Manganomori 21:08  CustomFeed::Manganomori - SweetPotato::Plagger を含むブックマーク はてなブックマーク -  CustomFeed::Manganomori - SweetPotato::Plagger  CustomFeed::Manganomori - SweetPotato::Plagger のブックマークコメント

Web::Scraperを使って書き直した。

まんがの森新刊コミックリストを取得し,単行本ごとにエントリ化する。

Plagger/Plugin/CustomFeed/Manganomori.pm

リファクタリングと無駄省きをした。以下の記事を参照。

「旬」の表記が「(上|中|下)旬」から単純な「(上|中|下)」に変わった模様。それに対応すると同時に,「(上|中|下)旬」に戻られても困るから正規表現で判断するようにした。

モジュール内で日本語を使用しているのでUTF-8(BOMなし)で保存すること。

package Plagger::Plugin::CustomFeed::Manganomori;
use utf8;
use strict;
use base qw( Plagger::Plugin );

use Plagger::Date;
use Plagger::Util;
use Switch;
use URI;

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

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

    my $date = $self->conf->{month}
             ? Plagger::Date->strptime("%Y.%m", $self->conf->{month})
             : Plagger::Date->now();
    my $id = ($date->year - 2003) * 12 + $date->month - 4; # month=2003.5 -> id=1

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

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

    my $content = Plagger::Util::load_uri(URI->new("http://www.manganomori.net/list.asp?listid=$id"));

    my ($year, $month) = ($content =~ m!<font color="#FF0000"><b>(\d{4})\.(\d{2})</b></font>!);
    if (!$year || !$month) {
        Plagger->context->log(error => "List not found in http://www.manganomori.net/list.asp?listid=$id");
        return;
    }

    my $feed = Plagger::Feed->new;
    $feed->link("http://www.manganomori.net/list.asp?listid=$id");
    $feed->title("まんがの森 コミックリスト $year.$month");

    my $list = $self->parse($content);
    for my $item (@$list) {
        my $entry = Plagger::Entry->new;
        $entry->title($item->{title});
        $entry->author($item->{author});
        $entry->tags([$item->{publisher}]);
        $entry->body("$item->{author}, $item->{publisher}, $item->{price}");

        if ($item->{day} !~ /\d+/) {
            $entry->body("$item->{day}, ".$entry->body);
            $item->{day} = $self->part_to_day($item->{day});
        }
        $entry->date(Plagger::Date->strptime("%Y/%m/%d", "$year/$month/$item->{day}"));

        $feed->add_entry($entry);
    }

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

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

    my $list = [];
    my $publisher;
    while ($content =~ m!<tr bgcolor="#(.*?)">(.*?)</tr>!gs) {
        my ($color, $item) = ($1, $2);
        if ($color eq "FF00FF") { # publisher
            $publisher = ($item =~ m!<b>(.*?)</b>!)[0];
        } elsif ($item =~ m{
            <td.*?</td>
            .*?<td.*?>(.*?)</td>
            .*?<td.*?>(.*?)</td>
            .*?<td.*?>(.*?)</td>
            .*?<td.*?>(.*?)</td>
        }sx) { # comic
            push @$list, {
                day => $1, title => $2, author => $3, price => $4,
                publisher => $publisher,
            };
        }
    }

    $list;
}

sub part_to_day {
    my ($self, $part) = @_;

    switch ($part) {
        case /<e4><b8><8a>/ { return "01"; }
        case /<e4><b8><ad>/ { return "11"; }
        case /<e4><b8><8b>/ { return "21"; }
    }

    "01";
}

1;

config.manganomori.comiclist.yaml

plugins:
  - module: CustomFeed::Manganomori
    config:
      month: 2006.11

monthには取得したいコミックリストの年月を %Y.%m 形式で指定する。指定しない場合は今月のコミックリストを取得する。

スクリーンショット1(Publish::iCal + Google Calendar)

f:id:SweetPotato:20061119211804p:image

スクリーンショット2(Publish::iCal + Google Calendar)

f:id:SweetPotato:20061119211753p:image

関連リンク

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