Perlの最近のブログ記事

Acme大全2009読み終わった。
印象に残った面白モジュールをいくつかピックアップしてみる。
Acme::Spinner
Acme::Spinners
Acme::Spinnerは以前紹介したくるくる回るハイフンの実装。\r(キャリッジリターン)使っている点も一緒。
Acme::Spinnersはこれのフレームワーク版。こっちはソースを見ると\rじゃなく、\b(バックスペース)で実装しているみたい。


Acme::ReturnValue
モジュールのリターン値が1ではないユニークなモジュール(Perlモジュールのリターン値は習慣で1が多く使われる)を探すモジュール。
早速入れて探してみようと思ったが、既にAcme::ReturnValue findingsにまとまっている。42多いなー。


Acme-PricelessMethods - search.cpan.org
is_machine_on やら is_true_true といった変なメソッドをちゃんと実装したモジュール。

blogが吹っ飛んで夏休みの思ひ出が書けなかったので載せておこう。

acme_2009_book.jpg

Perl本が出ると聞いて、この間、初めてコミケに行ってみた。暑くて死ぬかと思った。

Perlの世界でAcmeという名前がつくモジュールは基本的にネタモジュールだ。
Re: What does the "Acme" category represent? - nntp.perl.orgでも

Acme:: modules are nonsense modules, which though sometimes are technically interesting, may not be intended for serious work.

お仕事じゃつかえねーよ!と書かれている。

最近なら誰得と表現した方がピッタリかも。それにしてもよくもまぁこれだけ調査したなぁと思う。trivia好きにはたまらん本だね。

Perl本購入後は高校のメンバーと合流して、店番やったり、その後飲んでいたりしていた。

-----
おまけ
2p3p.jpg
コミケに行く前に秋葉原の配線屋で買ったアース2p3p変換プラグ。これ、会社でよく見かけるからありふれたものなのかなぁと思ってたんだけど、なかなか珍しい部類に入るのねー。一個800円以上もするとは思わなかったわ...。
逆(3p→2p)ならよく見かけるのにねぇ...。

前にも書きましたが、バイト先でWeb::Scraperを使ってます。

スクレイピング対象数が膨大な場合にちょっと困ったことが起きたので、今日はそれのmemo。
何が起こったかというと、スクレイピング先のサーバの調子が悪くて、500エラーなどを返したときに例外処理を書いていないとコケてしまうのだ。

例えば当ブログの最近の各エントリーページからのタイトル部分を引っ張ってくるとしよう。


#!/usr/local/bin/perl
use strict;
use Web::Scraper;
use URI;
use YAML;
binmode STDOUT => ":utf8";

my @uri = qw(http://hoge.sub.jp/blog/archives/2007/11/post_303.html
http://hoge.sub.jp/blog/archives/2007/11/post_3000.html #桁違い
http://hoge.sub.jp/blog/archives/2007/11/post_302.html);

my $scraper = scraper {
process "h3", "title" => "TEXT";
};

for (@uri){
my $result = $scraper->scrape(URI->new($_));
print Dump($result);
}

実行すると
> perl test.pl
---
title: てくのー
GET http://hoge.sub.jp/blog/archives/2007/11/post_3000.html failed: 404 Not Found at test.pl line 17
2番目のURLは現在では存在しないのでWeb::Scraperがcroak を呼び出す。この為、素のloopで回している上記のコードはループの途中でこけてしまう。


・対策方法その1
一番ラクなのはevalブロックで問題の箇所をくくって例外処理だろう。
evalブロック内でdieやcroak等でコケた場合、特殊変数$@(それにしても$@って、google先生キラーな名前だよなぁ)にエラー内容が入る。下記の場合はWeb::Scraper内のcroakに渡された文字列が入る。


#!/usr/local/bin/perl
use strict;
use Web::Scraper;
use URI;
use YAML;
binmode STDOUT => ":utf8";

my @uri = qw(http://hoge.sub.jp/blog/archives/2007/11/post_303.html
http://hoge.sub.jp/blog/archives/2007/11/post_3000.html
http://hoge.sub.jp/blog/archives/2007/11/post_302.html);

my $scraper = scraper {
process "h3", "title" => "TEXT";
};

for (@uri){
my $result;
eval {$result = $scraper->scrape(URI->new($_))};
#例外処理
if($@){
print "exception! $@\n"
} else {
print Dump($result);
}
}

実行してみる
> perl test2.pl
---
title: てくのー
exception! GET http://hoge.sub.jp/blog/archives/2007/11/post_3000.html failed: 404 Not Found at test2.pl line 18

---
title: 時間つぶしはニコニコ動画に限るよ。
ok。最後まで走った。


・対策方法2
plaggerプラグインのplugins/CustomFeed-Script/muhyojo.plを見て初めて知ったのだが、scrapeに渡すのってURIオブジェクトに限らないのね。
確かにWeb::Scraperのソースを見てみると


sub scrape {
my $self = shift;
my($stuff, $current) = @_;

my($html, $tree);

if (blessed($stuff) && $stuff->isa('URI')) {
require Encode;
require HTTP::Response::Encoding;
my $ua = $self->user_agent;
my $res = $ua->get($stuff);
if ($res->is_success) {
my @encoding = (
$res->encoding,
# could be multiple because HTTP response and META might be different
($res->header('Content-Type') =~ /charset=([\w\-]+)/g),
"latin-1",
);
my $encoding = first { defined $_ && Encode::find_encoding($_) } @encoding;
$html = Encode::decode($encoding, $res->content);
} else {
croak "GET $stuff failed: ", $res->status_line;
}
$current = $stuff->as_string;
} elsif (blessed($stuff) && $stuff->isa('HTML::Element')) {
$tree = $stuff->clone;
} elsif (ref($stuff) && ref($stuff) eq 'SCALAR') {
$html = $$stuff;
} else {
$html = $stuff;
}

  …(略)

と、いった感じでURIオブジェクト以外も受け付けてくれるようだ。ただ、代入しているだけなのでその場合は自分でdecode等の処理をかけないとまずい。
んで、できたのが、↓


#!/usr/local/bin/perl
use strict;
use Web::Scraper;
use URI;
use YAML;
binmode STDOUT => ":utf8";
use Encode;
use DateTime;

my @uri = qw(http://hoge.sub.jp/blog/archives/2007/11/post_303.html
http://hoge.sub.jp/blog/archives/2007/11/post_3000.html
http://hoge.sub.jp/blog/archives/2007/11/post_302.html);

my $scraper = scraper {
process "h3", "title" => "TEXT";
};

for my $url (@uri){
my $response = $scraper->user_agent->get($url);
unless ($response->is_success) {
#ここで例外処理
print "GET $url failed: " . $response->status_line . ' : ' . DateTime->now . "\n";
next;
}

my ($encoding) = $response->header('Content-Type') =~ /charset=([\w\-]+)/g;
my $result = $scraper->scrape( Encode::decode($encoding, $response->content) );
print Dump($result);
}

encodingの取得はWeb::Scraperを参考にした。よくよく考えたら、日付情報加えただけなのであんまlogは変化してない...。これでは$@とカワランのでダメな例ですね(´Д`;)

とりあえず実行してみる。
> perl test3.pl
---
title: てくのー
GET http://hoge.sub.jp/blog/archives/2007/11/post_3000.html failed: 404 Not Found : 2007-11-19T14:24:06
---
title: 時間つぶしはニコニコ動画に限るよ。

個人的にはやっぱ$@の方が楽かなーという印象。URIオブジェクトではなく、GRTした内容をscrapeに投げる場合は色々とごにょごにょしなきゃいけないのが最大のネックかなー。

前回scraper CLIを試してみたら、これはチェックにすげーよさげと書いたけど、なんか使いづらいんだよね。

cpanシェルと同じで履歴効かないし、矢印キーを押したら^[[Aみたいな感じで制御文字が吐き出されちゃう。
cpanシェルはぶっちゃけ、install [モジュール名をコピペ]だからそんな気にしてなかったんだけど、流石にscraper CLIで前回の履歴を使えないのは痛すぎる。

でも前回、参考にしたページには

Term::ReadLine を使用しているのでシェルみたく履歴を呼び出せる。CSS セレクタや XPath をちょこちょこ修正して試すのに便利。

ってあるんだよねぇ。確かにscraperコマンドの本体を見てみたらuse Term::ReadLineをしていた。コケないってことは既に自分の環境にTerm::ReadLineは入っているはず。なのになぜー?

という訳で調べてみたら、Term::ReadLine単体じゃ履歴や補完といった便利な機能は提供してくれないようです。[参考:Term::ReadLine で GNU Readlineを使う。]

Term::ReadLine::Gnuも必要とのことで早速cpanシェルでこれを入れてみる...が見事にこけた。force installでもダメだったのでportsが提供されていないか調べてみたがなさげ...?と思ったらあった![参考:perlshを使いはじめた]

port名は p5-Term-ReadLine-Gnu ではなく p5-ReadLine-Gnuなのか...。危うく諦めるところだった。

portsなら一発でokだった。早速 scraper [URL]とやってみると...矢印キーが普通に効くし、履歴も参照できるようになった!
ついでに、cpanシェルの方も使いやすくなったので、今まで不便な状態でcpanシェルを使っていたのがアホらしくなった。

なんか一回どっかのblogで64k以上のデータを送ったら挙動が怪しかったような...と思って
調べてたら、勘違いでGearman の話だった。

http://naoya.g.hatena.ne.jp/naoya/20070928/1190974874


#GMailのバージョンアップで読み込みがすんごく早くなった。
#BlogLinesをGMailに転送して読んでる身としてはありがたい。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちPerlカテゴリに属しているものが含まれています。

前のカテゴリはJavascriptです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

OpenID対応しています OpenIDについて
Powered by Movable Type 4.261