TwitterをHTMLから取得してPlaggerで使おう

前回,Plagger を使って Twitter のフィードから Tumblr へ流しましたが,僕がせっかく 書き上げるとすぐに Twitter は遅延してしまいました.あほですね.たまにちゃんと 動いているのですが,どうもフィードの更新が遅いです.Fav をした直後に見ると, ブラウザから WEB ページで見るとちゃんと新しい Fav も追加されているのに, フィードを見ると追加されていないことがありました.

いずれにせよ,Twitter の API は不安定きわまりないので,せっかくですから HTML を解析してこちらでフィードを作ってしまうことにしましょう. Plagger にもフィードを吐かないところ用に Plagger::Plugin::CustomFeed という分類が あります.こいつに従っていきましょう.メインのモジュールは Web::Scraper です.

Plagger::Plugin::CustomFeed::Twitter

目的としては,TwitterAPI で取得できるフィードを HTML から自作してしまうことです. が,完全にまねるのはめんどくさかったので,最小限にしました.まぁ必要とあらば ソースをいじればできるので.

Web::Scraper はとっても便利です.UserAgent とか作らなくてもさくっと GET してくれるし,class とか id とか結構ふってあるサイトだったら, それを指定するだけですぐに要素が取って来れます.しかも配列に格納してくれるので あとの処理も簡単・・・,のはずが$res->{entry}をどうやってforeachに渡したらいいのか 分からず数時間悩みましたw結論としてはforeach (@{$res->{entry}})としてあげると うまく渡せました.さすが Perl,わけがわかりません w

というわけで,ソース.いつもどおり github に置いてあります.

lib/Plagger/Plugin/CustomFeed/Twitter.pm

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

use URI;
use Web::Scraper;

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

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

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

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

    my $uri = new URI($self->conf->{uri}[0]);
    $context->log(info => $self->conf->{uri}[0]);
    my $entry = scraper {
        process 'span.entry-content', post => 'TEXT';
        process 'a.entry-date', url => '@href';
        process 'span.published', date => '@title';
        process 'div>strong>a', id => 'TEXT';
    };
    my $res = scraper {
        process 'td.status-body', 'entry[]' => $entry;
    }->scrape($uri);

# print $res->{entry}[0]->{post};

    my $feed = Plagger::Feed->new;
    $feed->type('twitter');

    foreach my $line (@{$res->{entry}}){
        $context->log(debug => $line->{post});
        my $entry = Plagger::Entry->new;
        my $post = $line->{id}. ": ". $line->{post};

        my $dt = eval { Plagger::Date->parse_dwim($line->{date}) };
        $entry->date($dt) if $dt;
        $entry->body($post);
        $entry->author($line->{id});
        $entry->title($post);
        $entry->link($line->{url});

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

1;

使い方

前回の YAML ファイルの Subscription::Config の部分をそっくりそのまま CustomFeed::Twitter に変えれば使えるはずです.

plugins:
  - module: CustomFeed::Twitter
    config:
      uri:
        - http://twitter.com/riywo/favorites

試してませんが,多分 Fav じゃなくても普通のページでも使えるんじゃないかな. というわけで,これで API が動かなくても WEB が生きてれば使える!

参考にしたのは下のページ.こちらの CustomFeed::Twitter は Net::Twitter を 使ってるので結局 API 経由ですね.

ちなみに,仕上げる直前くらいで,CustomFeed::Script の存在を知りました. これなら Scraping の部分だけ assets で書けばいいっぽい.まぁいいや,あとで 時間があればこっちにあわせるかもしれない.