ishiducaの日記 このページをアンテナに追加 RSSフィード

2009-12-07

[][XML::RSS]RSSfeed(1.0)をiCalendarフォーマットに直す 20:16 [XML::RSS]RSSfeed(1.0)をiCalendarフォーマットに直す - ishiducaの日記 を含むブックマーク はてなブックマーク - [XML::RSS]RSSfeed(1.0)をiCalendarフォーマットに直す - ishiducaの日記 [XML::RSS]RSSfeed(1.0)をiCalendarフォーマットに直す - ishiducaの日記 のブックマークコメント

調子に乗ってやってみたけど、日付のいじり方がダサイ...orz

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use XML::RSS;
use LWP::Simple;
use Data::ICal;
use Data::ICal::Entry::Event;
use Date::ICal;
use Encode;

my $enc_utf8 = find_encoding('utf-8');
# DMM 通販DVD 新着予約情報のRSS
my $url = 'http://www.dmm.com/mono/dvd/-/list/=/reserve=only/sort=date/rss=create/_jloff=1/';
my $rss  = XML::RSS->new();
my $calendar = Data::ICal->new();

$rss->parse(get $url);

foreach my $items (@{$rss->{'items'}}) {
    my $vevent = Data::ICal::Entry::Event->new();
    my $vevent_description =
        join ": ", $items->{'link'}, $items->{'description'};
    my ($date_of_rss,$offset);
    if ($items->{'dc'}->{'date'} =~ /\+/) {
        ($date_of_rss, $offset)= split /\+/, $items->{'dc'}->{'date'};
        $offset = "+$offset";
    } elsif ($items->{'dc'}->{'date'} =~ /-/) {
        ($date_of_rss, $offset)= split /-/, $items->{'dc'}->{'date'};
        $offset = "-$offset";
    } else {
        $date_of_rss = $items->{'dc'}->{'date'};
        $offset = "";
    }
    $date_of_rss =~ s/-//g;
    $date_of_rss =~ s/://g;
    $offset      =~ s/://g;
    my $date = Date::ICal->new(
        ical   => $date_of_rss,
        offset => "$offset"
    );
    $vevent->add_properties(
        summary     => $items->{'title'},
        description => $vevent_description,
        dtstart     => $date->ical,
    );
    $calendar->add_entry($vevent);
}

print $enc_utf8->encode($calendar->as_string);
exit 0;

[]続・Getchu.comの発売日カレンダーをスクレイピングしてiCalGoogle Calendarに発売日を反映させる 08:00 続・Getchu.comの発売日カレンダーをスクレイピングしてiCalやGoogle Calendarに発売日を反映させる - ishiducaの日記 を含むブックマーク はてなブックマーク - 続・Getchu.comの発売日カレンダーをスクレイピングしてiCalやGoogle Calendarに発売日を反映させる - ishiducaの日記 続・Getchu.comの発売日カレンダーをスクレイピングしてiCalやGoogle Calendarに発売日を反映させる - ishiducaの日記 のブックマークコメント

前回の記事のコードを手直し。もう少しモジュールを使ってみた。

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
use LWP::Simple;
use Data::ICal;
use Data::ICal::Entry::Event;
use Date::ICal;
use Date::ICal::Duration;

my $enc_utf8 = find_encoding('utf-8');

my $home = 'http://www.getchu.com/';
my $url  = "${home}php/calendar.phtml?genre=anime_dvd&"
         . "age=18&search_month=later&imageon=1"
         . "&maxhits=100";

(my $reg =<<'REG') =~ tr/\n//d;
<A HREF="\.\.\/([^"]+)" class="greenb">(.+?)</A>
.+?
(\d{4}\/\d{2}\/\d{2})
.+?<A href="[^"]+" class="blue" target="_blank" >(.+?)</A>
REG
;

my $html = get($url);
my $calendar = Data::ICal->new();

while ($html =~ /$reg/gs) {
    $calendar->add_entry(&vevent($home, $1, $2, $3, $4));
}

if ($ENV{'GATEWAY_INTERFACE'}) {
    require CGI;
    print CGI::header('text/calendar; charset=utf-8');
}
print $enc_utf8->encode($calendar->as_string);

exit 0;

sub vevent {
    my($home, $link_to_page, $title, $date, $brand) = @_;
    my($year, $month, $day) = split /\//, $date;
    ($month, $day) = map{ $_ =~ s/^0([1-9])$/$1/; $_ }($month,$day);
    my $vevent  = Data::ICal::Entry::Event->new();
    my $d =  Date::ICal->new(
        day  => $day, month => $month, year => $year,
    );
    $vevent->add_properties(
        summary     => "$title [$brand]",
        description =>"${home}$link_to_page",
        dtstart     => $d->ical,
    );
    $d->add( duration => 'P1D' );
    $vevent->add_properties(
        dtend => $d->ical
    );
    return $vevent;
}

出力結果

BEGIN:VCALENDAR
PRODID:Data::ICal 0.16
VERSION:2.0
BEGIN:VEVENT
DESCRIPTION:http://www.getchu.com/soft.phtml?id=668299
DTEND:20091211T150000Z
DTSTART:20091210T150000Z
SUMMARY:相関遊戯2 後編  [バニラ]
END:VEVENT
(中略)
BEGIN:VEVENT
DESCRIPTION:http://www.getchu.com/soft.phtml?id=672379
DTEND:20100226T150000Z
DTSTART:20100225T150000Z
SUMMARY:いっしょにエッチ  [ピンクパイナップル]
END:VEVENT
END:VCALENDAR

MaciCalでは読み込み成功しました。ただし、サーバーからの呼び出しはテストしてません。

FabioManxioFabioManxio2012/02/23 13:23Frankly I think that's absloutley good stuff.

dkjsfifhidkjsfifhi2012/02/25 02:54SkUhow <a href="http://uqescbjrysks.com/">uqescbjrysks</a>

rzypdyrzypdy2012/03/01 01:37kIAmjU <a href="http://bxmpeomxzvdz.com/">bxmpeomxzvdz</a>

lntpchbpmjlntpchbpmj2012/03/13 16:05YQsMCq , [url=http://dxmgqlihresr.com/]dxmgqlihresr[/url], [link=http://iyczwvecsibn.com/]iyczwvecsibn[/link], http://ygozhwathgeh.com/

トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20091207

2009-12-05

[][Date::Simple]Getchu.comの発売日カレンダーをスクレイピングしてiCalGoogle Calendarに発売日を反映させる 00:14 [Date::Simple]Getchu.comの発売日カレンダーをスクレイピングしてiCalやGoogle Calendarに発売日を反映させる - ishiducaの日記 を含むブックマーク はてなブックマーク - [Date::Simple]Getchu.comの発売日カレンダーをスクレイピングしてiCalやGoogle Calendarに発売日を反映させる - ishiducaの日記 [Date::Simple]Getchu.comの発売日カレンダーをスクレイピングしてiCalやGoogle Calendarに発売日を反映させる - ishiducaの日記 のブックマークコメント

はじめに書いておきますが、下記のGetchu.comは18禁サイトなので、18歳未満とか高校生は、真似しないでくださいね。

Getchu.comカレンダーコンテンツからタイトルの発売日を取得して、MaciCalGoogle Calendarに反映させるCGIスクリプト。(このスクリプトはDVDアニメの発売日カレンダーを吐くスクリプト)

ics.cgi

#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Encode;
use LWP::Simple;
use Date::Simple;

my $enc_utf8 = find_encoding('utf-8');

my $home = 'http://www.getchu.com/';
my $search_month = 'later';
if (@ARGV) {
    $ARGV[0] =~ /^20\d{2}\/\d{2}$/ or die "Usage: perl $0 [YYYY/MM]";
    $search_month = $ARGV[0];
}

my $url  = "${home}php/calendar.phtml?genre=anime_dvd&age=18&search_month=${search_month}&imageon=1&maxhits=100";

(my $reg =<<'REG') =~ tr/\n//d;
<A HREF="\.\.\/([^"]+)" class="greenb">(.+?)</A>
.+?
(\d{4}\/\d{2}\/\d{2})
.+?<A href="[^"]+" class="blue" target="_blank" >(.+?)</A>
REG
;

my $ics =<<'ICS';
BEGIN:VCALENDAR
PRODID:icspl//Perl
VERSION:2.0
X-WR-CALNAME:Getchu.com - Anime DVD Calendar(OVER18)
X-WR-CALDESC:iCalender of Anime DVD Calendar(OVER18) form Getchu.com
X-WR-TIMEZONE:Asia/Tokyo
%%VEVENT%%
END:VCALENDAR
ICS
;

my $html = get($url);
my $vevents = '';
while ($html =~ /$reg/gs) {
    $vevents .= &get_vevent($home, $1, $2, $3, $4);
}
$ics =~ s/%%VEVENT%%/$vevents/;
$ics =~ s/\n/\r\n/g;
if ($ENV{'GATEWAY_INTERFACE'}){
    require CGI;
    print CGI::header('text/calendar; charset=utf-8');
}
print $enc_utf8->encode($ics);
exit 0;

sub get_vevent {
    my($home, $link_to_page, $title, $date, $brand) = @_;
    $date =~ s/\//-/g;
    my $this_date = Date::Simple->new($date);
    my $next_date = $this_day->next;
    ($date,$next_date) = map{ $_ =~ s/-//g; $_ }($date,$next_date);

my $vevent =<<"EVE";
BEGIN:VEVENT
UID:${home}$link_to_page
DESCRIPTION:${home}$link_to_page
DTSTART:$date
DTEND:$next_date
SUMMARY:${title} [$brand]
END:VEVENT
EVE
;

    return $vevent;
}

ターミナル上からリダイレクトを使ってファイル出力する場合は

$ perl ics.cgi > dvd_anime.ics

の様にします。

MaciCalGoogleのGoogleCalendarもiCalendarのフォーマットに対応しているので、検索条件のリクエストを投げて返ってきた結果(HTML)をスクレイピングして、iCalendarフォーマットで書き出すだけです。が、iCalendarの「終日」を表現するには『翌日』を出さなくてはいけないので、手っ取り早く Date::Simpleモジュールを使います。

あと、ほかの注意点は

  • 文字コードをutf-8にする
  • MIMEタイプはtext/calendar。CGIで明示する場合はContent-type:text/calendar; charset=utf-8とするのが無難
  • 改行コードは「CR+LF

などがありますが、下記の参照文献を見た方がいいでしょう。

iCalendar関係の参照文献

トラックバック - http://perl.g.hatena.ne.jp/ishiduca/20091205