PHP Simple HTML DOM Parser

スクレイピング(ウェブサイトから情報を抽出するコンピュータソフトウェア技術)ができるライブラリ

参考(引用)URL

PHP プログラミング解説 > PHP Simple HTML DOM Parser
http://so-zou.jp/web-app/tech/programming/php/library/simplehtmldom/

ライブラリのダウンロード元

http://sourceforge.net/projects/simplehtmldom/files/

ダウンロードしたライブラリの読み込ませる方法

<?php
// simple_html_dom.phpを読み込む
require_once('simple_html_dom.php');	//←ココ

simple_html_domオブジェクトを生成

ヘルパー関数のstr_get_html()またはfile_get_html()から、simple_html_domオブジェクトを生成

<?php
// 文字列から
$html = str_get_html( '<html><body>Hello!</body></html>' );
// URLから
$html = file_get_html( 'http://example.com/' );
// HTMLファイルから
$html = file_get_html( 'test.htm' );

ヘルパー関数

<?php
object str_get_html( string $content )		//文字列から、DOMオブジェクトを生成
object file_get_html( string $filename )	//ファイルまたはURLから、DOMオブジェクトを生成

find()メソッドで、条件に一致する要素を取得

find()メソッドとは、
CSSセレクタで要素を探索する。indexを指定した場合にはn番目のオブジェクトが返され、さもなくばオブジェクトの配列が返される。

<?php
// すべてのa要素を検索し、要素の配列を取得する
$ret = $html->find( 'a' );

// 1番目に発見されたa要素を取得する。見つからない場合はnullが返される
$ret = $html->find( 'a', 0 );

// ... PHP 5.4以降ならば、次のようにも記述できる
$ret = $html->find( 'a' )[ 0 ];
<?php
// id属性のある、すべての要素を取得する
$ret = $html->find( '[id]' );

// id属性のある、すべてのdiv要素を取得する
$ret = $html->find( 'div[id]' );

// id属性がfooである、すべてのdiv要素を取得する
$ret = $html->find( 'div[id=foo]' );
属性の選択に使用できる演算子

[ attribute ] 指定の属性をもつ要素
[ attribute=value ] = 指定された値である 指定の属性をもつ要素
[ attribute!=value ] != 指定された値である 指定の属性をもたない要素
[ attribute^=value ] ^= 指定された値から始まる値である 指定の属性をもつ要素
[ attribute$=value ] $= 指定された値で終わる値である 指定の属性をもつ要素
[ attribute*=value ] *= 指定された値を含む値である 指定の属性をもつ要素

実行例
<?php
$html = str_get_html( '<a><b>Hello!</b></a>' );
echo $html->find( 'b', 0 ); // <b>Hello!</b> と出力される

高度な方法

CSSのIDセレクタやクラスセレクタの構文でも、要素を取得できます。

<?php
// id属性がfooのすべての要素を取得する
$ret = $html->find( '#foo' );

// class属性がfooのすべての要素を取得する
$ret = $html->find( '.foo' );

またカンマで区切ることで、複数の条件を指定できます。

<?php
// すべてのa要素とimg要素を取得する
$ret = $html->find( 'a, img' );

// title属性のある、すべてのa要素とimg要素を取得する
$ret = $html->find( 'a[title], img[title]' );
IDセレクタ

要素のID属性が完全一致する場合のみ適用されるように、スタイルを定義
#id_value { style properties }

意味としては、次のように属性セレクタで記述しても同じ
[id=id_value] { style properties }

よってこれを応用すれば、ID属性に対して完全一致以外でもスタイルを適用させられます
[id*=id_value] {}
[id^=id_value] {} ...

クラスセレクタ

要素のclass属性が指定のクラス名を含む場合にのみ適用されるように、定義できます。
.classname { style properties }

クラスセレクタの意味は、属性セレクタでは
[class~=classname] { style properties }
と表せます。

子孫セレクタ

CSSの子孫セレクタ(ある要素の子孫にあたる要素のみの構文 区切り文字は (スペース))でも、要素を取得

<?php
// ul要素の中にあるすべてのli要素を取得する
$es = $html->find( 'ul li' );

// ネストされたdiv要素を取得する
$es = $html->find( 'div div div' );

さらに属性の指定とも組み合わせられます。

<?php
// class属性がhelloであるtable要素の中にある、すべてのtd要素を取得する
$es = $html->find( 'table.hello td' );

// table要素の中にある、align=centerの属性をもつすべてのtd要素を取得する
$es = $html->find( 'table td[align=center]' );

ネストされたセレクタ

<?php
// ul要素の中にあるすべてのli要素を取得する
foreach( $html->find( 'ul' ) as $ul )
{
  foreach( $ul->find( 'li' ) as $li )
  {
    // $li に結果が格納される
  }
}
<?php
// 最初のul要素の中の 最初のli要素を取得する
$e = $html->find( 'ul', 0 )->find( 'li', 0 );

// PHP 5.4以降ならば、次のようにも記述できる
$e = $html->find( 'ul' )[ 0 ]->find( 'li' )[ 0 ];

テキストとコメント

<?php
// すべてのテキストブロックを取得する
$es = $html->find( 'text' );

// すべてのコメント ( <!-- ... --> ) を取得する
$es = $html->find( 'comment' );

HTML要素へのアクセス

<?php
// 要素からタグを除外したテキストの取得
echo $html->plaintext;

// 要素の外側に、他の要素を設定する
$e->outertext = '<div class="wrap">'.$e->outertext.'<div>';

// 空文字を設定し、要素を削除する
$e->outertext = '';

// 要素を後へ追加する
$e->outertext = $e->outertext.'<div>foo<div>';

// 要素を前に挿入する
$e->outertext = '<div>foo<div>'.$e->outertext;

HTML要素の属性

<?php
// 属性を取得する (属性が非値ならば、論理値が返される)
$value = $e->href;

// 属性を設定する (属性が非値ならば、論理値を設定する)
$e->href = 'my link';

// 属性を削除し、値をNULLとする
$e->href = null;

// 属性が存在するか?
if( isset( $e->href ) )
{
    echo 'href exist!';
}

エラー

Fatal error: Allowed memory size

原因:メモリ不足
対策:以下のように書けば良い

<?php
$html = file_get_html(...); 
// do something... 
$html->clear(); 	//←ココ重要
unset($html); 		//←ココ重要
「セグメンテーション違反です」「zend_mm_heap corrupted」

原因:メモリ不足。Simple HTML DOM Parserでは読み込みサイズの上限を独自に設定している。
対策:simple_html_dom.phpの設定を書き換える
simple_html_dom.phpのMAX_FILE_SIZEという部分。
最初は600KBが上限と設定されているようで、ここを増やすことで解決