Web::Scraper を HTML::TreeBuilder::LibXML で高速に
昨日、HTML::TreeBuilder::LibXML がリリースされました。
Web::Scraper を 16 倍速くする HTML::TreeBuilder::LibXML を書いた
http://search.cpan.org/~tokuhirom/HTML-TreeBuilder-LibXML-0.01_02/
(デベロッパーリリース)
http://search.cpan.org/~tokuhirom/HTML-TreeBuilder-LibXML-0.03/
正式リリースされました。
これまでも、Web::Scraper を XML::LibXML で爆速にする hack!などはあったのですが、 HTML::TreeBuilder::LibXML は Web::Scraper にパッチを当てる必要もなく、使う側で use して replace_original() を呼ぶだけなので入れ替えも楽です。
使い方は、今まで
use URI; use Web::Scraper; my $uri = URI->new("http://example.com/"); my $scraper = scraper { process 'a', 'link[]' => '@href'; }; my $result = $scraper->scrape($uri);
と、していたところを、
use URI; use Web::Scraper; use HTML::TreeBuilder::LibXML; HTML::TreeBuilder::LibXML->replace_original(); my $uri = URI->new("http://example.com/"); my $scraper = scraper { process 'a', 'link[]' => '@href'; }; my $result = $scraper->scrape($uri);
と、2行追加するだけです。
ある程度のデータ量があるページでどれくらい処理速度が違うかベンチマークを取ってみました。
普通に 1000 回とかスクレイピングで回すと DoS攻撃 になってしまうので、
wget -O /tmp/w3.org.html http://www.w3.org/
で、スクレイピング対象をローカルに保存し、
#!/usr/bin/perl use strict; use Benchmark; use Web::Scraper; use URI; use HTML::TreeBuilder::LibXML; my $uri = URI->new("file:///tmp/w3.org.html"); my $scraper = scraper { process 'a', 'title[]' => '@title'; }; timethese(1000, { 'XPath' => sub { my $result = $scraper->scrape($uri); } }); HTML::TreeBuilder::LibXML->replace_original(); timethese(1000, { 'LibXML' => sub { my $result = $scraper->scrape($uri); } });
と、しました。
結果は以下です。10倍以上のスピードアップです。
Benchmark: timing 1000 iterations of XPath... XPath: 268 wallclock secs (109.53 usr + 0.15 sys = 109.68 CPU) @ 9.12/s (n=1000) Benchmark: timing 1000 iterations of LibXML... LibXML: 24 wallclock secs ( 9.80 usr + 0.08 sys = 9.88 CPU) @ 101.21/s (n=1000)