Simple HTML DOM Parserのクラス1

提供:wiki - PCスキルの小技・忘却防止メモ
移動: 案内, 検索

Simple HTML DOM Parserのクラス1。いろんなサイトをパースするときに必要なものをまとめたクラス

ソース

随分前に作ったヤツなので、覚えていないので、コメントを読みながらガンバル。

確か、やたらソースの長いページをパースするときに困った記憶がある。そのときに予め不要なタグや文字を削除してからDOM化させるために作ったクラス…だったはず。

<?php
 /**
  * my_simple_html_dom.class.php
  * simple_html_domに色々するクラス:simple_html_domを元にアレコレと。
  * ver 1.0 2011/05/31
  */
 class ClassHtmlParseOfDom{
 	
 	var $_source;
 	var $_dom;
 	
 	function __construct(){}
 	
 	function __destruct(){
 		$this->_source = NULL;
 		$this->_dom->clear();
 		unset($this->_dom);
 	}
 	
 	/**
 	 * setContents() - コンテンツのセット
 	 * @param str $contents
 	 */
 	function setContents($contents){
 		$this->_source = $contents;
 	}
 	
 	/**
 	 * fixedEncode() - 文字コードの変換
 	 * @param str $char 文字コード
 	 */
 	function fixedEncode($char){
 		$this->_source = mb_convert_encoding($this->_source, "UTF-8", "auto");
 	}
 	
 	/**
 	 * getContentsToUri() - URIからコンテンツの取得
 	 * @param unknown_type $uri
 	 */
 	function getContentsToUri($uri){
 		if( ($source = @file_get_contents($uri)) === FALSE ){
 			// 取得失敗
 			print_r($http_response_header);
 			return false;
 		}
 		else{
 			return $source;
 		}
 	}
 	
 	/**
 	 * setContentsToDom() - コンテンツをDOM化
 	 * @param str $contents
 	 * @param str $format 削除する対象をCSV(breaktag,breakline,space,empty,entity = 改行タグ、改行、空白・タブ、空要素タグ、HTMLエンティティ(<等))
 	 * @param ary $elements [$target]に[empty]を含めるなら必須。空要素タグ一覧
 	 */
 	function setContentsToDom( $contents, $format=null, $elements=array() ){
 		$this->_source = $contents;
 		$this->fixedContents( $format, $elements);
 		
 		$this->_dom = new simple_html_dom();
 		$this->_dom->load($this->_source);
 	}
 	
 	/**
 	 * deleteBreakTagForContents() - 改行タグを削除
 	 * @param str $contents HTMLソース
 	 */
 	function deleteBreakTagForContents(){
 		$this->_source = preg_replace("/(<wbr>|<wbr \/>|<br>|<br \/>)/iu", "", $this->_source);
 	}
 	
 	/**
 	 * fixedContents() - コンテンツの整形
 	 * @param str $contents HTMLソース
 	 * @param str $target 削除する対象をCSV(breaktag,breakline,space,empty,entity = 改行タグ、改行、空白・タブ、空要素タグ、HTMLエンティティ(<等))
 	 * @param ary $emptyElementTags [$target]に[empty]を含めるなら必須。空要素タグ一覧
 	 * @return str
 	 */
 	function fixedContents( $target=NULL, $emptyElementTags ){
 		if( strstr($target, "breaktag")  ){ $this->deleteBreakTagForContents();            } // 改行タグ(<wbr>と<br>)の削除
 		if( strstr($target, "space")     ){ $this->fixedIncludingSpaceAndTabForContents(); } // 空白やタブの削除・整形
 		if( strstr($target, "breakline") ){ $this->fixedBreakLineForContents();            } // 改行の削除・整形
 		if( strstr($target, "entity")    ){ $this->fixedOneWordToHtmlEntity();             } // HTMLエンティティ(<等)を1文字に変換
 		
 		// 空要素タグの削除
 		if( strstr($target, "empty") ){
 			$this->deleteEmptyElementTagForContents($emptyElementTags);
 		}
 	}
 	
 	/**
 	 * deleteEmptyElementTagForContents() - 空要素のタグ(<img>や<area>など)を削除
 	 * @param str $contents HTMLソース
 	 * @param ary $tags 削除したい空要素タグ
 	 */
 	function deleteEmptyElementTagForContents($tags){
 		foreach( $tags as $tag ){
 			$pattern = '/(<' . $tag . ')( +)([^<>]*>)/iu';
 			$this->_source = preg_replace($pattern, '', $this->_source);
 		}
 	}
 	
 	/**
 	 * fixedIncludingSpaceAndTabForContents() - 空白やタブの削除など
 	 */
 	function fixedIncludingSpaceAndTabForContents(){
 		// 空白類:複数ある半角スペースは一つのスペースに変換、タブは削除
 		$this->_source = str_replace("\t", '', $this->_source);
 		$this->_source = preg_replace('/ +/u', " ", $this->_source);
 	}
 	
 	/**
 	 * fixedBreakLineForContents() - 改行の削除など
 	 */
 	function fixedBreakLineForContents(){
 		$this->_source = str_replace("\n", '', $this->_source);
 		$this->_source = str_replace("\r", '', $this->_source);
 	}
 	
 	/**
 	 * fixedOneWordToHtmlEntity() - HTMLエンティティ( とか)を1文字に変換
 	 */
 	function fixedOneWordToHtmlEntity(){
 		//  など特殊文字とかを全角スペースに変換: など特殊文字とは、「[&][;]の間に英数字とクォーテーションを除いた記号」
 		// 実体参照:「[&]+[英語]+[;]」、コード参照:「[&]+[#]+[数字]+[;]」
 		$this->_source = preg_replace('/&(([a-zA-Z]{2,}[a-zA-Z0-9]*)|(#[0-9]{2,4})|(#x[a-fA-F0-9]{2,4}))?;/', " ", $this->_source);
 	}
 	
 	// ===============================================================================
 	// メソッド:パース
 	/**
 	 * retrieveDataFromDom() - DOMツリーからデータを抜き出す
 	 * @param str $rule 抜き出すルール
 	 * @param int $num  抜き出す順番: 指定があれば戻り値はstr。なければary
 	 * @return obj DOMノード
 	 */
 	function retrieveDataFromDom( $rule, $num=NULL ){
 		if( count($this->_dom->find($rule)) > 0){
 			// 対象の個数が0個超過(1個以上)の場合
 			if( $num !== NULL ){
 				$tags = $this->_dom->find($rule, $num);
 			}
 			else{
 				$tags = $this->_dom->find($rule);
 			}
 		}
 		else{
 			return FALSE;
 		}
 		return $tags;
 	}
 	
 	/**
 	 * getAttributeValue() - コンテンツから指定した属性の値を取得
 	 * @param ary $rules 指定したタグ(=tag)、属性(=atr)、必要な箇所(=need)
 	 * @param int $num  抜き出す順番: 指定があれば戻り値はstr。なければary
 	 * @param str $child 子要素に対応(子要素が不要 = "NoChild")
 	 * @return str or ary
 	 */
 	function getAttributeValue( $rules, $num=NULL, $child=NULL ){
 		// ルールの作成("body *[alt]"みたいな感じ)
 		$rule = "{$rules['tag']}";
 		if( isset($rules['atr']) && $rules['atr'] !== "" ){
 			// 属性が指定されていたらルールに追加
 			$rule .= "[{$rules['atr']}]";
 		}
 		
 		// 必要な値を取得するための引数作成(任意の属性や、plaintextなど)
 		$need = $this->makeMagicAttributes($rules);
 		
 		// 対象の取得
 		$temps = $this->retrieveDataFromDom($rule, $num);
 		
 		// 必要なノードのみに(子要素を削除する)
 		if ($temps !== FALSE && $child === "NoChild"){
 			// 子要素が不要な場合。
 			$temps = $this->dellChildElement($temps);
 		}
 		
 		// 必要な値を取得
 		$arys = $this->getValue($temps, $need);
 		return $arys;
 	}
 	
 	/**
 	 * makeMagicAttributes() - 必要な値を取得するための引数作成(任意の属性や、plaintextなど)
 	 * @param ary $rules 指定したタグ(=tag)、属性(=atr)、必要な箇所(=need)
 	 */
 	function makeMagicAttributes($rules){
 			// 必要な値を取得(任意の属性や、plaintextなど)
 			if( isset($rules['need']) ){
 				$need = $rules['need'];
 			}
 			elseif( !isset($rules['need']) && isset($rules['atr']) ){
 				$need = $rules['atr'];
 			}
 			else{
 				echo "\n戻り値不明\n";
 				exit();
 			}
 		return $need;
 	}
 	
 	/**
 	 * dellChildElement() - 子要素のみ削除
 	 * @param obj $temps DOMノード(?)
 	 * @return ary
 	 */
 	function dellChildElement($temps){
 		// 外側のタグごと取得
 		$all = $this->getValue($temps, "outertext");
 		
 		// 親要素の「outertext」の番号を取得
 		$parent = $this->getParentIndex($all);
 		
 		// 必要な要素のみ取得
 		foreach( $parent as $v ){
 			$arys[] = $temps[$v];
 		}
 		return $arys;
 	}
 	
 	/**
 	 * getParentIndex() - 親要素の「outertext」の番号を取得
 	 * @param ary $arys 親要素・子要素混合。
 	 * @return ary
 	 */
 	function getParentIndex($arys){
 		// 特定の子要素を含まないものだけ取得
 		// 「<li></li>」はいるが、「<li><li></li></li>」は不要
 		$rep = array();
 		for( $i=0; $i<count($arys); $i++ ){
 			if( $i === 0){
 				// 一回目は、比較用($compare)と配列($rep)に入れる。
 				$compare = $arys[$i];
 				$rep[] = $i;
 			}
 			else{
 				$j = count($rep) - 1;
 				if( !strstr( $compare, $arys[$i] ) ){
 					// 一つ前の中に含まれない場合は、新しいもの
 					$compare = $arys[$i];
 					$rep[] = $i;
 				}
 				else{
 					// 一つ前の中に含まれる場合は、比較用($compare)を修正:正規表現用にエスケープする必要アリ
 					$pattern = "/" . changeRegularExpression($arys[$i]) . "/u";
 					$compare = preg_replace($pattern, "", $compare);
 				}
 			}
 		}
 		return $rep;
 	}
 	
 	/**
 	 * getValue() - 必要な値を取得
 	 * @param obj $target
 	 * @param str $val
 	 * @return ary
 	 */
 	function getValue($target, $val){
 		$arys = array();
 		
 		// 指定した属性の値を取得
 		if( is_array($target) ){
 			if( $target !== false ){
 				foreach( $target as $v ){
 					$arys[] = $v->$val;
 				}
 			}
 		}
 		elseif( is_string($target) ){
 			return $target->$val;
 		}
 		return $arys;
 	}
 }
 ?>

関連項目