PhantomJS + Selenium::Remote::Driver でスクレイピングをこころみる
PhantomJS といえば、WebKit を headless でうごかせて便利なやつですが、PhantomJS 1.8 から Ghost Driver がくみこまれるようになりました。
わかる人むけにかくと「JSONWire Protocol をサポートする httpd が phantomjs にくみこまれた」ということです。
GhostDriver は WebDriver Wire Protocol の1実装です。で、そのクライアントライブラリとして Selenium::Remote::Driver が CPAN にあがっていますから、これをつかって簡単に phantomjs とやりとりができます。
Selenium::Remote::Driver という名前のとおり、Selenium もつかえますんで、selenium をつかって、対応しているブラウザでのテストもできるのがいいかんじです。
というわけでためしてみましょう。
準備
brew install phantomjs cpanm Selenium::Remote::Driver
でOK。
自分でコンパイルするのはすごい時間かかるので、バイナリを利用するのが吉です。
参考:
phantomjs、P4のcentosで2時間近くがんばってbuildしている横でmacにbrew installしたらバイナリが3秒で入ったでござる
— hidek (@hidek) January 9, 2013
phantomjs ghost driverをたちあげる
phantomjs ghost driver をたちあげるには、以下のようにするかんじです。
phantomjs --webdriver=9999
ここで 9999 はポート番号です。
ここではシェルからたちあげることを想定していますが、実際は Test::TCP とかでたちあげちゃう方が楽だとおもいます。
Selenium::Remote::Driver でアクセスしてみる
use Selenium::Remote::Driver; my $driver = Selenium::Remote::Driver->new( remote_server_addr => '127.0.0.1', port => 9999, ); my $res = $driver->get('http://mixi.jp'); say $driver->get_title();
こんなかんじで OK です。簡単ですね。
簡単なんだけど、問題があります。なんか文字化けするんです。
????????롦?ͥåȥ????? ?????ӥ? [mixi(?ߥ?????)]
とか。。
なんでかな、っておもいます。
Selenium::Remote::Driver がわるいんじゃないかとうたがってみる。
ちょっと Selenium::Remote::Driver があやしいんじゃないかとうたがってしまいますね。
なんかあやしいので、シンプルな実装をつくってためしてみましょう。
#!/usr/bin/env perl use strict; use warnings; use utf8; use 5.010000; use autodie; use LWP::UserAgent; use JSON::XS; { package JSONWire::Client; use LWP::UserAgent; our $VERSION = '1.0.0'; use Moo; use JSON; has port => ( is => 'ro', required => 1, ); has json => ( is => 'ro', default => sub { JSON->new }, ); has host => ( is => 'ro', required => 1, ); has agent => ( is => 'ro', default => sub { LWP::UserAgent->new( agent => __PACKAGE__ . "/" . $VERSION, ); }, ); sub create_session { my $self = shift; my $res = $self->agent->post( "http://$self->{host}:$self->{port}/session", Content => $self->json->encode( { desiredCapabilities => {} } ) ); if ($res->code ne 303) { JSONWire::Client::Exception::HTTP->throw($res); } my $base = $res->header('Location') // die "Missing location"; return JSONWire::Client::Session->new( base => $base, agent => $self->agent, json => $self->json, ); } package JSONWire::Client::Session; use Moo; has base => ( is => 'ro', required => 1, ); has agent => ( is => 'ro', required => 1, ); has json => ( is => 'ro', required => 1, ); has last_response => ( is => 'rw', ); sub get { my ($self, $path) = @_; $path =~ s!^/+!!; my $res = $self->agent->get($self->base . "/" . $path); $self->last_response($res); unless ($res->is_success) { JSONWire::Client::Exception::HTTP->throw( $res ) } return $self->json->decode($res->content); } sub post { my ($self, $path, $data) = @_; $path =~ s!^/+!!; my $res = $self->agent->post($self->base . "/" . $path, Content => $self->json->encode($data)); $self->last_response($res); unless ($res->is_success) { JSONWire::Client::Exception::HTTP->throw( $res ) } return $self->json->decode($res->content); } package JSONWire::Client::Exception::HTTP; use Moo; has response => ( is => 'ro', ); use overload q{""} => \&stringify; sub throw { my ($class, $response) = @_; die $class->new(response => $response); } sub stringify { my $self = shift; $self->response->status_line; } } my $driver = JSONWire::Client->new( host => '127.0.0.1', port => 9999, ); my $session = $driver->create_session; $session->post('/url', {url => 'http://mixi.jp'}); my $data = $session->get('/title'); say $data->{value};
で、実行結果は。。
¥½¡¼¥·¥ã¥ë¡¦¥Í¥Ã¥È¥ï¡¼¥¥ó¥° ¥µ¡¼¥Ó¥¹ [mixi(¥ß¥¯¥·¥£)]
なんてこった!!
Selenium::Remote::Driver もだめぽなことにきづく
+NOTE: Currently, I don't use Perl for my day job & support for this module is falling behind. If you want to take over 2 + maintenance of this module, please contact me.
とかかいてある!
https://github.com/aivaturi/Selenium-Remote-Driver/commit/82ac94841a7fe1a8d8c0ff59ab5b061c47d20eda
だれかメンテナンスしないのかな?
結論
Selenium::Remote::Driver は日本語のscrapingができない。
あと、Wight 的なのよりこの路線が今後主流かなーとおもったり。
ref. http://blog.64p.org/entry/2012/10/13/144648
あと、phantomjs 1.8 では Ghost Driver では日本語がとおりません! だれか bug report とかしてあげてください。
【追記】
どうも OSX 用のバイナリが腐ってるっぽくて、ひできさん方式で、自前コンパイルすれば問題ないので、みなさん3時間かけてコンパイルしましょう。