忍者ブログ
[PR]
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。



2024/11/23 04:19 |
PHP5.3.5 tidyでHTMLをパース

PHPでHTMLのパースって、実はいまいち使い勝手のいいものがないんですよね。

DOMはいったんDOMElementにしてしまうと元のHTMLに戻すのが何故か大変、SimpleXMLはアバウトなHTMLを読み込んでくれない、XMLパーサは使い方がやたらややこしい、と一長一短というか一短一短です。
そもそも何れもXML用であってHTML用ではないので当たり前かもしれませんが。

HTMLの誤りを修正するためのツールとしてTidyというものが存在しますが、どういうわけかPHPから利用することが可能です。
で、これがHTMLのパーサとしてもわりと優秀です。
さすがにDOMDocument::getElementById()ほどの便利メソッドはありませんが、比較的簡単にHTMLを掘っていくことが可能です。
とりあえず作成。
 

<?php
	//HTMLを取得
		$html = file_get_contents('http://yuubiseiharukana.blog.shinobi.jp/Entry/501/');
	
	//Tidy
		$tidyConfig = array('indent' => true, 'output-xhtml' => true, 'wrap' => 200);
		$tidy = new tidy();
		$tidy->parseString($html, $tidyConfig, 'utf8');
	
	//<body>を取得
		$tidyBody = $tidy->body();
	
	//本文を取得
		//CSS上のパス:html body div#whole div#contents div#main div div.entry_table div.entry_text
		$tidyText = $tidyBody->child[1]->child[4]->child[1]->child[1]->child[0]->child[1];
		print($tidyText);
Tidyのコンフィグはここらへんに一覧がありますが、いまいちなんなのかよくわかりません。
よくわからないのでサンプルのまま使用しています。

あとはTidyオブジェクトに対してHTMLタグの入れ子の順番を指定するだけで、非常に簡単に本文を取得できます。
とはいえ、例では番号を直接指定しているのですが実はあまりよくない方法です。
何故ってchild[1]やchild[4]は、単にノード内の要素を上から順に数えた値なので、タグをひとつ追加されるだけでずれてしまうのです。

本当はXPathやCSSパスで指定するのが安全なのですが、残念ながらそのような機能はないようです。
ということで子ノードを順に取得してひとつひとつ確認していくしかありませんが、ところが何故かTidyはforeachcount()が使えません。

従ってたとえば子ノードのうち特定のタグを取得したい場合は以下のように書く必要があります。
<?php
	//Countable、Traversable
		count($tidyBody);	//必ず1になる
		foreach($tidyBody as $key=>$val){
			//$tidyBody[0]のプロパティのループになってしまう
		}
	
	//<div id="whole">を取得
		$loop = 0;
		while(1){
			$tmp = $tidyBody->child[$loop];
			$loop++;
			
			if(!$tmp){break;}
			if($tmp->id !== TIDY_TAG_DIV){continue;}
			if($tmp->attribute['id'] !== 'whole'){continue;}
			
			$tidyWhole = $tmp;
			break;
		}
		
	//<div id="contents">を拾う
		$loop = 0;
		while(1){
			$tmp = $tidyWhole->child[$loop];
			$loop++;
			
			if(!$tmp){break;}
			if($tmp->id !== TIDY_TAG_DIV){continue;}
			if($tmp->attribute['id'] !== 'contents'){continue;}
			
			$tidyContents = $tmp;
			break;
		}
ちょっとどうなんだって気がする。
あとUndefined propertyのNoticeが出るのも微妙。

というかTidyでXHTML化してSimpleXMLに突っ込んだ方が早くない?という気がしてきた。

 

PR


2011/06/24 23:15 | Comments(0) | TrackBack() | PHP

トラックバック

トラックバックURL:

コメント

コメントを投稿する






Vodafone絵文字 i-mode絵文字 Ezweb絵文字 (絵文字)



<<今週の実績 2011/06/25 | HOME | Dojo1.6.1 dojo Dojo道場06 dojox.charting.Chart2DでXML形式から読み込み>>
忍者ブログ[PR]