PHP "Simple HTML DOM Parser"の使い方メモ
概要
卒研のためにWEBサイトから必要な情報だけ抽出したデータセットを作成したときに用いた、PHPでHTMLを簡単にパースできるというPHP Simple HTML DOM Parserの使い方の備忘記録。
参考ページ
抽出対称
amazonのベストセラーのランキングページ2009年の本のベストセラーから
- ISBN-10
- 本のタイトル
- 著者
を取得する。
※ 2010/12/29 時点でのhtmlには対応している。
本のタイトル・著者 抽出スクリプト
<?php // ランキングページの1ページ目のURL(1位~20位) $page_url = "http://www.amazon.co.jp/gp/bestsellers/2009/books/ref=pd_ts_pg_1?ie=UTF8&pg=1"; // ランキングページのHTMLを取得 $page_data = mb_convert_encoding(file_get_contents($page_url),'UTF-8','auto'); // simple_html_dom.phpを読み込む require_once 'simplehtmldom/simple_html_dom.php'; // 取得したhtmlのsimple_html_domオブジェクトを作成 $shd_obj = str_get_html($page_data);
var_dump($shd_obj)
ちなみに $shd_obj を var_dump() してみるとこんな感じobject(simple_html_dom)#1 (18) { ["root"]=> object(simple_html_dom_node)#2 (8) { ["nodetype"]=> int(5) ["tag"]=> string(4) "root" ["attr"]=> array(0) { } ["children"]=> array(2) { [0]=> object(simple_html_dom_node)#4 (8) { ["nodetype"]=> int(6) ["tag"]=> string(7) "unknown" ["attr"]=> array(0) { } ["children"]=> array(0) { } ["nodes"]=> array(0) { } ["parent"]=> object(simple_html_dom_node)#2 (8) { ["nodetype"]=> int(5) ["tag"]=> string(4) "root" ["attr"]=> array(0) { } ["children"]=> array(2) { [0]=> object(simple_html_dom_node)#4 (8) { ["nodetype"]=> int(6) ["tag"]=> string(7) "unknown" ["attr"]=> array(0) { } ["children"]=> array(0) { } ["nodes"]=> array(0) { } ["parent"]=> *RECURSION* ["_"]=> array(2) { [0]=> int(2) [4]=> string(15) "" } ["dom":"simple_html_dom_node":private]=> object(simple_html_dom)#1 (18) { ["root"]=> *RECURSION* ["nodes"]=> array(2922) { [0]=> *RECURSION* [1]=> object(simple_html_dom_node)#3 (8) { ["nodetype"]=> int(3) ["tag"]=> string(4) "text" ["attr"]=> array(0) { } ["children"]=> array(0) { } ["nodes"]=> array(0) { } ["parent"]=> *RECURSION* ["_"]=> array(1) { [4]=> . . .
simple_html_dom_node というオブジェクトがhtmlタグごとに作成され,そのタグがchildren-子ノード(持っているhtmlタグ)の情報、parent-親ノード(所属している一つ上の階層のhtmlタグ)の情報を所持している。
のですべてを var_dump() するととてつもない量になるので注意が必要。
simple_html_dom オブジェクトを作成した後の続きのコード
<?php /* * さっきコードの続き */ // 本情報を格納するための配列を用意 $book_info = array(); foreach ($shd_obj->find("td.zg_productInfo ") as $element) { // <td class="zg_productInfo">要素内のhtmlを取得 $inner_data = $element->innertext; // 本の情報を抽出する $book_detail_obj = $element->find("div.productTitle a"); $book_info['title'][] = $book_detail_obj[0]->innertext; if (isset($book_detail_obj[1]->innertext)) { $book_info['auther'][] = $book_detail_obj[1]->innertext; } else { $book_auther_obj = $element->find("div.productTitle div.byLine"); $book_info['auther'][] = trim($book_auther_obj[0]->innertext); } }
simple_html_dom_node->find() メソッド
simple_html_dom_node->find() メソッドの引数にhtmlタグを指定すると、返り値が配列になり、その指定したhtmlタグが存在するだけ、配列の要素(simple_html_dom_node オブジェクト)を作成する。また、class,id属性や入れ子のhtmlタグを指定すれば絞り込むことができる。上の例のforeach中のfind()メソッドの例では
$element->find("div.productTitle a")
と引数を指定しているので、$element要素がもつ<div>タグのclass属性がproductTitleであり、かつその<div>タグの子要素<a>の情報に絞り込んでいる。
simple_html_dom_node->innertext 属性
simpole_html_dom_node->innertext属性はそのhtmlタグが囲んでいる中身のhtmlを保持している。var_dump($element)
ちなみに$elementを var_dump() するとこんな感じobject(simple_html_dom_node)#766 (8) { ["nodetype"]=> int(1) ["tag"]=> string(2) "td" ["attr"]=> array(1) { ["class"]=> string(14) "zg_productInfo" } ["children"]=> array(8) { [0]=> object(simple_html_dom_node)#768 (8) { ["nodetype"]=> int(1) ["tag"]=> string(3) "div" ["attr"]=> array(1) { ["class"]=> string(12) "productTitle" } ["children"]=> array(2) { [0]=> object(simple_html_dom_node)#769 (8) { ["nodetype"]=> int(1) ["tag"]=> string(1) "a" ["attr"]=> array(1) { ["href"]=> string(117) "http://www.amazon.co.jp/1Q84-BOOK-1-%E6%9D%91%E4%B8%8A-%E6%98%A5%E6%A8%B9/dp/4103534222/ref=pd_ts_b_1?ie=UTF8&s=books" } ["children"]=> array(0) { } ["nodes"]=> array(1) { [0]=> object(simple_html_dom_node)#770 (8) { ["nodetype"]=> int(3) ["tag"]=> string(4) "text" ["attr"]=> array(0) { } ["children"]=> array(0) { } ["nodes"]=> array(0) { } ["parent"]=> object(simple_html_dom_node)#769 (8) { ["nodetype"]=> int(1) ["tag"]=> string(1) "a" ["attr"]=> array(1) { ["href"]=> string(117) "http://www.amazon.co.jp/1Q84-BOOK-1-%E6%9D%91%E4%B8%8A-%E6%98%A5%E6%A8%B9/dp/4103534222/ref=pd_ts_b_1?ie=UTF8&s=books" } ["children"]=> array(0) { } ["nodes"]=> array(1) { [0]=> object(simple_html_dom_node)#770 (8) { ["nodetype"]=> int(3) ["tag"]=> string(4) "text" ["attr"]=> array(0) { } ["children"]=> array(0) { } ["nodes"]=> array(0) { . . .
<div class="productTitle">
ちなみにdiv.productTitleの一つ目の要素を示すとこんな感じのhtml。<div class="productTitle"><a href="http://www.amazon.co.jp/1Q84-BOOK-1-%E6%9D%91%E4%B8%8A-%E6%98%A5%E6%A8%B9/dp/4103534222/ref=pd_ts_b_1?ie=UTF8&s=books">1Q84 BOOK 1</a> <div class="byLine"> <a href="/村上-春樹/e/B000AP7AFI/ref=pd_ts_b_1_1">村上 春樹</a> (著)</div></div>
このようなhtmlになっているので、
- 一つ目の<a>要素内には本のタイトル
$book_info['title'][] = $book_detail_obj[0]->innertext;
- 二つ目の<a>要素内には本の著者
$book_info['auther'][] = $book_detail_obj[1]->innertext;
のようにして取得している。
ちなみに、2つ目の<a>要素がない場合があるため、スクリプトのような処理をしている。
ISBN-10 の取得は正規表現を使った
$page_dataは一番最初スクリプトのfile_get_contentsで取得したものを利用している。<?php $isbn10_get_pattern = '/<span class="crAvgStars" style="white-space:no-wrap;"><span class="asinReviewsSummary" name="(.+)" ref="pd_ts_b_/'; preg_match_all($isbn10_get_pattern, $page_data, $book_ids, PREG_SET_ORDER); $isbn10s = array(); foreach($book_ids as $book_id){ $isbn10s[] = $book_id[1]; }
まとめ
simple_html_domと正規表現を組み合わせて用いることで、より簡単に情報を抽出できる!simple_html_domって簡単だし素晴らしい。