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

riywo

Software Engineer, DevOps, DBA, Solutions Architect, NFL, working for AWS. All posts are my own, not endorsed by any org.