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で書けばいいっぽい.まぁいいや,あとで 時間があればこっちにあわせるかもしれない.

John92 09-10-23 (金) 5:59

For some special lattices, the complex torus also enjoys some non-trivial complex endomorphisms; for instance if is the Gaussian integers then we have a multiplication by i, or more generally by any Gaussian integer. ,

Laura 09-10-28 (水) 4:46

Nice post on web scrapers, simple and too the point :), For web scrapers i use python for simple things, but for larger projects i have used extractingdata.com http://www.extractingdata.com/web%20scraper.htm which builds custom web scrapers and data extracting programs simple and fast