つれずれなるままに… このページをアンテナに追加 RSSフィード Twitter

自身をYuichirouと名乗る謎の男が文字通り「つれれなるままに」書くよくわからん日記。

検索サイトから来た方、こんなページでゴメンナサイ。下にあるフォームに検索ワードを入れて検索すると、情報が得られるかも。

なお、タイトルに打ち間違いはありません。

1000 | 01 | 02 | 03 | 04 |
1504 | 01 | 02 | 03 |
2003 | 10 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 |

2008年2月16日

[]b:id:manameのブックマークをwatchするPerlスクリプト 15:45 b:id:manameのブックマークをwatchするPerlスクリプトを含むブックマーク

まなめさんが秒数まで全く同じタイミングに2つブクマしてくれたおかげで、プログラム中のバグがわかりました(苦笑)。

これが完成版です。

ソース

#!/usr/bin/perl
use strict;
use warnings;
use Encode;
use File::stat;
use HTTP::Date;
use LWP::UserAgent;
use Compress::Zlib;
use XML::RSS;
use HTML::Entities qw(encode_entities);

# 初期設定
my $url = shift || "http://b.hatena.ne.jp/maname/rss";
my $output = shift || "public_html/maname.rss";

# HTTPヘッダを作成
my %header = ("Accept-Encoding" => "gzip");
if (-f $output) {
    # すでに出力があったら
    # その更新時刻を If-Modified-Since に設定
    my $stats = stat($output);
    $header{"If-Modified-Since"} = time2str($stats->mtime);
}

# アクセス
my $ua = new LWP::UserAgent;
my $response = $ua->get($url, %header);

# とりあえず結果の状態を表示させてみる
print $response->status_line . "\n";
# 更新がなかったら終了
exit if ($response->code == 304);
# それ以外で失敗の場合はエラー
die "Cannot get content from $url." unless ($response->is_success);

# 本体を取得
my $data = $response->content;
# 圧縮されていたら解凍
if (my $encoding = $response->content_encoding) {
    $data = Compress::Zlib::memGunzip($data);
}

# RSSとしてパース
my $rss = new XML::RSS();
$rss->parse($data);
# 過去の内容と融合
if (-f $output) {
    my $old_rss = new XML::RSS();
    $old_rss->parsefile($output);

    # 新旧それぞれのitemを、時刻をキーにしてハッシュにまとめる
    # 同じ時刻のitemは、新しいデータで上書きされる
    my %list;
    for (@{$old_rss->{items}}, @{$rss->{items}}) {
        $list{$_->{link}} = $_;
    }

    # $rssのitemリストをリセットし、ハッシュのデータを
    # 時刻が新しい(キーの値が大きい)方から順に入れ直す
    $rss->{items} = [];
    for (sort { $b->{dc}->{date} cmp $a->{dc}->{date} } values %list) {
        $rss->add_item(%{$_});
    }
}

# 出力ファイルをロード
open FH, ">:utf8", $output;

# 冒頭部を出力
print FH <<"EOD";
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF
\txmlns="http://purl.org/rss/1.0/"
\txmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
\txmlns:dc="http://purl.org/dc/elements/1.1/"
\txmlns:content="http://purl.org/rss/1.0/modules/content/"
\txmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" 
\txmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/"
\txml:lang="ja">
EOD

# channel部を出力
print FH "<channel rdf:about=\"" . $url . "\">\n";
for (qw{title link description}) {
    print FH "\t<$_>" . $rss->channel($_) . "</$_>\n";
}
print FH "\t\n";

print FH "\t<items>\n\t<rdf:Seq>\n";
for (@{$rss->{'items'}}) {
    print FH "\t\t<rdf:li rdf:resource=\"$_->{link}\"/>\n";
}
print FH "\t</rdf:Seq>\n\t</items>\n";
print FH "</channel>\n";

# item部を出力
for my $item (@{$rss->{'items'}}) {
    # 開始タグほか
    print FH "<item rdf:about=\"" . $item->{link} . "\">\n";
    for (qw{title link description}) {
        print FH "\t<$_>" . encode_entities($item->{$_} || "", '<>"&');
        print FH "</$_>\n";
    }

    # content
    print FH "\t<content:encoded>";
    print FH encode_entities($item->{content}->{encoded}, '<>"&');
    print FH "</content:encoded>\n";

    # dc
    for (qw{date creator}) {
        print FH "\t<dc:$_>" . encode_entities($item->{dc}->{$_}, '<>"&');
        print FH "</dc:$_>\n";
    }
    print FH "\t\n";
    # タグが使われていたら
    if (defined($item->{dc}->{subject})) {
        for ($item->{dc}->{subject}) {
            print FH "\t<dc:subject>" . encode_entities($_, '<>"&');
            print FH "</dc:subject>\n\t\n";
        }
        print FH "\t\n";
        print FH "\t<taxo:topics>\n\t  <rdf:Bag>\n\t  \n";
        for (@{$item->{taxo}}) {
            print FH "\t  <rdf:li resource=\"" . $_ . "\" />\n\t  \n";
        }
        print FH "\t  </rdf:Bag>\n\t</taxo:topics>\n";
    }

    # 終了タグ
    print FH "\t\n</item>\n";
}

# 出力終わり
print FH "</rdf:RDF>\n";
close FH;

# Last-Modified をファイルの更新時刻として保存
utime(time, $response->last_modified, $output);

# 終了
exit;

[]まなめはうすニュースヘッドラインRSS出力プログラム 15:50 まなめはうすニュースヘッドラインRSS出力プログラムを含むブックマーク

これ自体はRSSファイルを作ります。まなめはうす-ニュースヘッドライン-よりデータが濃いです。

出力例:http://www.ja2yka.org/~mitsu/maname_house.rss

ソース

#!/usr/bin/perl
use strict;
use warnings;
use Encode;
use encoding 'euc-jp';
use File::stat;
use HTTP::Date;
use LWP::UserAgent;
use HTML::TreeBuilder;
use XML::RSS;
use HTML::Entities qw(encode_entities);

# 初期設定
my $url = shift || "http://homepage1.nifty.com/maname/";
my $output = shift || "/home/mitsu/public_html/maname_house.rdf";

# HTTPヘッダを作成
my %header;
if (-f $output) {
    # 出力ファイルがあったら
    # その更新時刻を If-Modified-Since に設定
    my $stats = stat($output);
    $header{"If-Modified-Since"} = time2str($stats->mtime);
}

# アクセス
my $ua = new LWP::UserAgent;
my $response = $ua->get($url, %header);

# とりあえず結果の状態を表示させてみる
print $response->status_line . "\n";
# 更新がなかったら終了
exit if ($response->code == 304);
# それ以外で失敗の場合はエラー
die "Cannot get content from $url." unless ($response->is_success);

# 本体を取得
my $data = decode("utf8", $response->content);
# HTMLを解析
my $tree = HTML::TreeBuilder->new_from_content($data);

# RSSの準備
my $rss = new XML::RSS();
$rss->channel(title => 'まなめはうす -ニュースヘッドライン-',
              link  => 'http://homepage1.nifty.com/maname/',
              description => '良いニュースで、良い人生を。');

# 各ニュースブロックについて
for my $news ($tree->look_down(_tag  => 'div', class => 'news')) {
    # 中の要素を取得
    my @child = $news->content_list();
    my $i = 0; # カウンタ

    my %item;
    while (defined $child[$i]) {
        # 見出しを取得
        my $title;
        if (ref $child[$i] && $child[$i]->{_tag} eq "span") {
            if ($child[$i]->{class} eq "b2") {
                $title = "☆☆☆"; # 赤星→3つ星
            } elsif ($child[$i]->{class} eq "b5") {
                $title = "★★"; # ビッグ→2つ星
            }
            $title .= $child[++$i];
        } elsif (!ref $child[$i] && $child[$i] =~ /(.*)$/) {
            $title = $1;
        } else {
            last;
        }
        # リンクを取得
        $i += 2;
        my $link;
        if (ref $child[$i] && $child[$i]->{_tag} eq 'a') {
            $link = $child[$i]->{href};
        } else {
            last;
        }
        # 併記の場合はとりあえず保存
        $rss->add_item(%item) if (%item);
        # 項目として確定
        %item = ( title => $title, link => $link );
        # 併記されているかチェックのため戻る
        $i += 2;
    }
    next unless (defined $child[$i]);

    # ソース情報を取得
    my $description = "";
    my $content = "";
    if ($child[$i] eq "(情報元:") {
        while (defined $child[$i]) {
            if (!ref $child[$i]) {
                $description .= $child[$i];
                $content .= $child[$i];
            } elsif ($child[$i]->{_tag} eq "a") {
                $description .= $child[$i]->as_text();
                $content .= $child[$i]->as_HTML('<>&"');
            } else {
                last;
            }
            $i++;
        }
    }
    # コメントを取得
    if (ref $child[$i] && $child[$i]->{class} eq "newsc") {
        $description .= $child[$i]->as_text();
        $content .= $child[$i]->as_HTML('<>&"');
    }
    # 保存
    $rss->add_item( %item,
                    description => $description,
                    content => { encoded => $content } );
}

# ツリーを破棄
$tree = $tree->delete;

# 出力ファイルをロード
open FH, ">:utf8", $output;

# 冒頭部を出力
print FH <<"EOD";
<?xml version="1.0" encoding="utf-8" ?>
<rdf:RDF
\txmlns="http://purl.org/rss/1.0/"
\txmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
\txmlns:dc="http://purl.org/dc/elements/1.1/"
\txmlns:content="http://purl.org/rss/1.0/modules/content/"
\txml:lang="ja">
EOD

# channel部を出力
print FH "<channel rdf:about=\"" . $url . "\">\n";
for (qw{title link description}) {
    print FH "\t<$_>" . $rss->channel($_) . "</$_>\n";
}
print FH "\t\n";

print FH "\t<items>\n\t<rdf:Seq>\n";
for (@{$rss->{'items'}}) {
    print FH "\t\t<rdf:li rdf:resource=\"";
    print FH encode_entities($_->{link}, '<>"&') . "\"/>\n";
}
print FH "\t</rdf:Seq>\n\t</items>\n";
print FH "</channel>\n";

# item部を出力
for my $item (@{$rss->{'items'}}) {
    # 開始タグほか
    print FH "<item rdf:about=\"";
    print FH encode_entities($item->{link}, '<>"&') . "\">\n";
    for (qw{title link description}) {
        next unless (defined $item->{$_});
        print FH "\t<$_>" . encode_entities($item->{$_} || "", '<>"&');
        print FH "</$_>\n";
    }

    # content
    if ($item->{content}) {
        print FH "\t<content:encoded><![CDATA[";
        print FH $item->{content}->{encoded};
        print FH "]]></content:encoded>\n";
    }

    # 終了タグ
    print FH "</item>\n";
}

# 出力終わり
print FH "</rdf:RDF>\n";
close FH;

# Last-Modified をファイルの更新時刻として保存
utime(time, $response->last_modified, $output);

# 終了
exit;
トラックバック - http://d.hatena.ne.jp/Yuichirou/20080216