LWP::UserAgent + POE::Filter::Line で行ベース処理

#!/usr/bin/env perl
use strict;
use warnings;

use LWP::UserAgent;
use POE::Filter::Line;

my $filter = POE::Filter::Line->new;
my $ua = LWP::UserAgent->new;

## POE::Filter::Line で $chunk を行入力に変換
$ua->get(
    'http://d.hatena.ne.jp/naoya/',
    ':content_cb' => sub {
        my $chunk = shift;
        my $lines = $filter->get([ $chunk ]);

        for (@$lines) {
            print "got: $_\n";
        }
    }
);

POE::Filter は単独で使うことができます。LWP のコールバックと組み合わせると、HTTP 上のドキュメント全体をメモリにため込む必要無く行ベースで処理したいときなどに手軽に書けます。

POE::Filter::Stackable を使うと種類の異なる複数のフィルタを入力に作用させることができます。たとえば POE::Filter::Line と POE::Filter::Grep を POE::Filter::Stackable で組み合わせると、以下のように、ブロック入出力で得られた出力に行単位で grep をかけることができます。

#!/usr/bin/env perl
use strict;
use warnings;

use LWP::UserAgent;
use POE::Filter::Line;
use POE::Filter::Grep;
use POE::Filter::Stackable;

my $ua = LWP::UserAgent->new;

my $filter = POE::Filter::Stackable->new;
$filter->push(
    POE::Filter::Line->new,
    POE::Filter::Grep->new(Code => sub { m/title/ }),
);

## "title" の含まれる行だけが出力される
$ua->get(
    'http://d.hatena.ne.jp/naoya/',
    ':content_cb' => sub {
        my $chunk = shift;
        my $lines = $filter->get([ $chunk ]);

        for (@$lines) {
            print "got: $_\n";
        }
    }
);

つづく...