Movatterモバイル変換


[0]ホーム

URL:


Config::PitとWeb::ScraperとPlaggerで24時間365日のゲーム監視体制

序文

趣味のネットウォッチのために仕方が無く超便利なPerlを覚えようという感じのotsune です。そんなわけでコーディングの深い話はよくわからんので、今回はPerlとCPANを使ってネットウォッチを支援する手法について書きます。

ウォッチしたいWebページを機械的に監視できれば、あとはPlaggerなどの便利ツールを使って「メールを出す」「im.kayac.comでメッセンジャーにアラートを出す」「ピザを注文する」など好きな処理をすることが出来ます。

RSSフィードやAPIなどがあるWebサイトであれば特に苦労はしないのですが、今回取り上げるOgame.jpはウェブブラウザーゲームなので、フィードなど便利な機能はまったく存在しません。

そこでウォッチしたいWebページに対してWeb::Scraperを使ってYAMLを出力する短いスクリプトを書いてしまいます。

メールを出すなどのこまごまとした処理は既存のPlagger等のスクリプトに任せられるので、最小限のコードを書くだけでやりたいことが出来るようになります。

概要

ざっと流れを説明します。まずブラウザーゲームのOgame.jpはユーザー名とパスワードによりログインが必要なサイトなので、WWW::Mechanizeでログインします。

そのログイン時にConfig::Pitを使うことでパスワードをスクリプト内に書かないようにします。

そして、Web::ScraperでHTMLページから監視したい「敵が攻めてくる警告文」の部分を切り抜きします。

最後にYAMLで、Plaggerであつかえるフィードとエントリーの形で出力します。

解説

早速コードを見ながら解説しましょう。(コードはCodeReposにcommitしてあります)

#!/usr/bin/perluse strict;use warnings;use URI;use WWW::Mechanize;use Config::Pit;use Web::Scraper;use DateTime;use YAML;

この辺は定番という感じで。今回使う主なCPANモジュールは、WWW::Mechanize, Config::Pit, Web::Scraperです。

my $uni = shift || 'uni4';# get password#Config::Pit::switch('ogame');my $config = pit_get("$uni.ogame.jp", require => {        "username" => "otsune",        "password" => "your password on ogame.jp"    });

Config::Pitのpit_getを使うことでスクリプトにIDやパスワードをハードコードする必要が無くなります。ぜひ使いましょう。パスワードの設定はppit set uni4.ogame.jpなどと入力して$EDITORで編集することで~/.pit/以下に保存できます。またperl -MConfig::Pit -e'Config::Pit::set("uni4.ogame.jp", data=>{ username=>"dankogai", password=>"kogaidan" })'というワンライナーでも~/.pit/以下に保存できます。

# loginmy $ogame_login = "http://$uni.ogame.jp/game/reg/login2.php";my $uri = URI->new($ogame_login);$uri->query_form(    login => $config->{username},    pass  => $config->{password},    v     => 2,);# accessmy $mech = WWW::Mechanize->new(cookie_jar => {});my $response = $mech->get( $uri );if (!$response->is_success || $response->content =~ /errormessage/){    warn $mech->status();    return;};$mech->follow_link(url_regex => qr{index\.php}i);

URIモジュールでIDやパスワードのクエリー付きURLを組み立てて、WWW::Mechanizeでブラウザーゲームにログインをします。Ogame.jpはログイン後に<meta http-equiv='refresh' ...>ヘッダーでindex.phpにリダイレクトしているので、follow_linkメソッドでページ移動します。

# scrapemy $feed = scraper {    process 'title', 'title' => 'TEXT';    process 'tr.flight', 'entry[]' => scraper {        process 'span.attack', title => 'TEXT',        process '//a[@class="attack"]/following-sibling::a', body => '@title';        process '//div[starts-with(@id, "bxx")]', date => sub {            my $dt = DateTime->now(time_zone=>'local');            $dt->add( seconds=>$_->attr('title') );            return $dt->iso8601();        }    }}->scrape($mech->content, $mech->uri);

Web::Scraperのscraperメソッドで、取得したWebページ(content)から切り抜きたい箇所をXPathかCSSセレクターで指定して読み込みます。(contentを渡してスクレイピングするときは、第二引数に$mech->uriを渡すと、Web::Scraperが相対URLを自動的に絶対URLにしてくれるのでオススメ)

ここでポイントなのが後処理をするPlaggerにあわせて「ひとつのFeedに複数のEntry」という構造で項目名を決めることです。具体的な例では

---link: フィードのURL<http://example.com/hoge/>title: 'フィードタイトル'image: フィードのサムネイル画像URL<http://img.example.com/hoge/logo.png>entry:  - title: 'エントリー1のタイトル'    link: エントリー1のURL<http://example.com/hoge/path/to/entry1-link>    date: エントリー1の日付(2008-12-21T01:23:45Z)    body: 'エントリー1内容'  - title: 'エントリー2のタイトル'    link: エントリー2のURL<http://example.com/hoge/path/to/entry2-link>    date: エントリー2の日付(2008-12-21T06:54:32Z)    body: 'エントリー2内容'

という感じの構造のYAMLを出力します。(何が使えるかはPlaggerのlib/Plagger/Feed.pmlib/Plagger/Entry.pmのアクセッサ名を参照すると良いでしょう)。

Web::Scraperのprocessでは、ダブルクォートを使うときにXPath属性選択省略記号の@などを\でエスケープする必要があります。たとえば'//hoge[@attr="fuga"]'"//hoge[\@attr='fuga']"は同じです。XPath文と一致させておきたいときはシングルクォートを使うと良いでしょう。

また、Web::Scraperでsubでコールバックを使うと、$_processで切り抜かれたHTML::Elementsが渡されます。

敵が到達するまでの残り時間は、divタグのtitleという属性に整数値で書かれているので、subのコールバック内でDateTimeモジュールを使って加算して(具体的には$dt->add( seconds=><数値> )の部分)、日付文字列にして返しています。

$feed->{link}  = $ogame_login;$feed->{image} = 'http://board.ogame.jp/ogame_logo/jp.gif';

ここでは固定されているフィードのリンクとサムネイルイメージを直接指定してます。

# outputbinmode STDOUT, ":utf8";print YAML::Dump $feed;

最後にWeb::Scraperによって$feedに読み込まれたデータをYAMLとして出力します。

おまけ

Plaggerで使うにはplagger/assets/plugins/CustomFeed-Script/以下にogame_check.plという名前などでスクリプトを配置して

plugins:  - module: Subscription::Config    config:      feed:        - url: script:/path/to/plagger/assets/plugins/CustomFeed-Script/ogame_check.pl  - module: CustomFeed::Script

というconfig.yamlで読み込みます。

このスクリプトをPlaggerだけで使うつもりなら、use Plagger;use Plagger::UserAgent;をスクリプトに追記することでWWW::MechanizeはPlagger::UserAgentを使うことも出来ます。(おなじ理由で、DateTimeの代わりにPlagger::Dateを使うこともできます)、あーでもmechfollow_linkとか使ってるとダメか……

最後に

「PerlはCPANを使うためのインターフェース」が持論のオレ的には、やりたいことをサクっと解決できるCPANという仕組みはとてもすばらしいと思っています。

さて、次はmalaの予定だったけど、連絡付いたのでDan Kogaiさんで。

Back


[8]ページ先頭

©2009-2025 Movatter.jp