localdisk

PHP とか Java とか Web とか好きなことを書きます。

そろそろ Simple HTML DOM Parser を使うのはやめたほうがいい

Simple HTML DOM Parser といえば定番のスクレイピングライブラリで、僕も随分お世話になったわけだけど遅いし重いので Goutte 使ったほうがいいという話です。某サイトをスクレイピングするのに比較したら特にメモリ消費に大きな差がでました。

比較したスクリプトGithub においてありますので自由に使ってください。なおプロファイラは @koriym さんが Qiita にポストしたものを使用させていただきました。

プログラム

スクレイピング対象のサイトはこのブログにしました。あざといですね。タイトルのリストを出力するプログラムです。

Simple HTML DOM Parser

<?php

require_once './vendor/autoload.php';
require_once './profiler.php';
$html = \SimpleHtmlDom\str_get_html(file_get_contents('http://localdisk.hatenablog.com/'));
$nodes = $html->find('h1.entry-title');
foreach ($nodes as $node) {
    echo trim($node->text()) . "\n";
}
$html->clear();

Goutte

<?php

require_once './vendor/autoload.php';
require_once './profiler.php';

$client = new \Goutte\Client;
$crawler = $client->request('GET', 'http://localdisk.hatenablog.com/');
$crawler->filter('h1.entry-title')->each(function($node)
{
    echo trim($node->text()) . "\n";
});

結果

処理時間は大差ありませんが*1、メモリ消費にかなりの差が出ているのがわかると思います。プログラムを見てもわかるように使い方に大差ありません。むしろ Goutte のほうが Closure 使えて嬉しいですね。

Simple HTML DOM Parser

便利な日時操作ライブラリ Carbon
Response::xml macro を作ったよ
NHK番組表API for PHP を書いたよ
足りないインフラ力をAnsibleでまかなう
すべてのPOSTリクエストに対してCSRFフィルターを適用する
今年もよろしくお願いします
Laravel でトランザクション
完結済の俺が好きな漫画+
Laravel でWebアプリのインストーラーを作ってみる
Laravel 最速マスター

Memory: 9,014,440 / 10,773,432 bytes
Time: 1756.099939 ms
Declared: 141 classes
Ibcluded: 10 

Goutte

便利な日時操作ライブラリ Carbon
Response::xml macro を作ったよ
NHK番組表API for PHP を書いたよ
足りないインフラ力をAnsibleでまかなう
すべてのPOSTリクエストに対してCSRFフィルターを適用する
今年もよろしくお願いします
Laravel でトランザクション
完結済の俺が好きな漫画+
Laravel でWebアプリのインストーラーを作ってみる
Laravel 最速マスター

Memory: 2,417,136 / 2,437,208 bytes
Time: 1246.071815 ms
Declared: 205 classes
Ibcluded: 95 

考察

なぜこういう結果になるのか? Simple HTML DOM Parser は HTML の解析に正規表現を用いており、Goutte では DOMDocument を使用しています*2。おそらく正規表現よりは DOMDocument のほうが効率がいいんでしょうね。
余談ですが、DOMDocument では、filter メソッドの引数(この場合は h1.entry-title)のような指定では要素が取得できません。これは Simfony/CSSSelector が引数を解析して XPath に変換しているんですね。これは感心させられました。

*1:ややこしいことすると Goutte のほうがかなり速くなる

*2:正確には Symfony/DOMCrawler.