Hatena::Groupcside

Cside::StudyMemo このページをアンテナに追加 RSSフィード

メインブログに書くまでもない自分用メモを垂れ流す

カテゴリー
 | 

2012-02-10

[]Web::QueryのHTMLの解析にXML::LibXMLを使うと速くなる話

3年前に話題になった、Web::ScraperでXML::LibXMLを使うと爆速になる話(ttp://d.hatena.ne.jp/tokuhirom/20090324/1237904392)のWeb::Query版。


パーサをXML::LibXMLに取り替える機能がWeb::Scraper本家に加わる以前、

use HTML::TreeBuilder::LibXML;
HTML::TreeBuilder::LibXML->replace_original();

の2行を追加すればWeb::Scraperのコードに変更を加えずしてパーサをXML::LibXMLに取り替えることができ、HTMLの解析が爆速になる(速くなるのはXML::LibXMLがXSで書かれているから)という話だったけど、あれと同じことがWeb::Queryでもできるか試してみた。

HTML::TreeBuilder::LibXMLをWeb::Queryに使うにはHTML::TreeBuilder::LibXMLにいくらか実装を書き足す必要があったので、そこを書きたしたうえで、パーサの速度を測ってみた。(HTML::TreeBuilder::LibXMLのほうのテストがまだ全部通ってないのだけど、通ったら変更部分のコード上げます。すんません)

use HTML::TreeBuilder::LibXML
use Path::Class qw(file);
use Benchmark qw(cmpthese);
use Filt;

# ローカルに保存しておいた http://b.hatena.ne.jp/Cside/favorite のHTMLを取り出す
my $html = file("$Bin/test/favorite.html")->slurp;

# パース部分のコード:
# https://github.com/Cside/Filt/blob/master/lib/Filt/Model/Feed.pm
sub parse { Filt::Model::Feed->get($_[0]) }

cmpthese(10, {
    no_libxml => sub {
       parse($html);
    },
    use_libxml => sub {
        # パーサを入れ替える
        HTML::TreeBuilder::LibXML->replace_original();

        parse($html);
    },
});

結果

           s/iter  no_libxml use_libxml
no_libxml    11.1         --       -95%
use_libxml  0.542      1953%         --

19倍速くなった。


HTML::TreeBuilder::LibXMLのテストが全部通ったらpull reqする予定。


高速化っていうけど、そもそもHTMLの解析がボトルネックになっていたか?

はてなからHTMLをスクレイピングしてきてパースしてRSSに出力するサービス(http://hbt.cside.me/)をこないだ作ったのだけど、とにかくレスポンス遅かった。

で、何に時間を食ってるのかプロフィアリングして内訳を見てみたら

はてなからのレスポンス待ち3.0 sec
HTMLのパース2.5 sec
RSS形式で出力0.5 sec

という感じで、HTMLのパースにかかる時間が結構無視できない長さになっていた。

Webアプリケーションのボトルネックなんて大体I/O待ちでしょ、と予測していたけど、そうでもないようだった。計測やっぱり重要。

 |