アシアル株式会社主催 開発者向け、一歩先をいくためのテクニカルセミナー

<< PDOでの接続について 質問一覧 チェックボックス 変数の受け渡しに... >>

  • 100P
tidyでHTMLのパースを実現したい

Googleなどで検索すると、HTMLのパースにtidy関数というものが使えると知りました。
http://www.php.net/manual/ja/ref.tidy.php

これを利用してHTMLのパース(例:HTMLの<title>タグ内の文字列を抜き出す、など)を実現したいのですが、そのやり方がPHPドキュメントに記載されておらず、困っております。もしご存知の方がいらっしゃったら、アドバイスお願いします。

この質問への意見の募集は締め切られ、ポイントは既に配分されました。
意見を投稿することはできますが、ポイントを受け取ることはできません。

QtidyでHTMLのパースを実現したい jpnetratings  [01月04日 18時22分] 
┗Re:tidyでHTMLのパースを実現したい kazu_kun  [01月05日 17時52分] 
  ┗Re:tidyでHTMLのパースを実現したい jpnetratings  [01月06日 03時16分] 
    ┗Re:Re:tidyでHTMLのパースを実現したい kazu_kun  [01月09日 11時20分] 
      ┗Re:Re:Re:tidyでHTMLのパースを実現したい jpnetratings  [01月09日 12時56分] 

コメント一覧

並び替え( ツリー順 / 投稿順[降順] / 投稿順[昇順]

Re:tidyでHTMLのパースを実現したい

http://www.php.net/manual/ja/ref.tidy.php
のページのuser cntributed notesの上から4番目(patatraboum at nospam dot fr)がパースしている例と思われ。
とりあえず、コピペしてきて、いろいろいじってみてはいかが?

Re:tidyでHTMLのパースを実現したい

ご返信ありがとうございます。説明が不十分で申し訳ございません。


WebサイトのSEO対策を調べるため、各HTMLをパースして<title>タグや<h1>タグの内容を自動的に取得して出力するツールを構築しております。そこで、tidyで整形してからsimple_xmlやDOMといったxml関数を使ってtitleタグやh1タグの内容を取得しております。

kazu_kunさんにいただいた情報を拝見しました。HTMLタグを再帰的に調べて出力するようです。次のサイトでも同様の方法を採用していました。
http://www.coggeshall.org/oss/tidy/

再帰処理をスクリプトに実装するとコードが複雑になるため、tidyでxpathのように各要素に直接アクセスして情報を取得できるかを調べているところです。もしご存知でしたら、教えていただけますと幸いです。

Re:Re:tidyでHTMLのパースを実現したい

> tidyで整形してからsimple_xmlやDOMといったxml関数を使ってtitleタグやh1タグの内容を取得しております。
私には、これ以上の方法を提示することはできません。

http://www.php.net/manual/ja/ref.tidy.php
は既に何度も見ていて、気づいていると思いますが、xpathのように各要素に直接アクセスはおそらくないです(私には見つけられませんでした)。
自前で、HTMLツリーを再帰的にたどって取得するしかないでしょう。きっと。

幸い、SimpleXMLはXPATHが使用できるようなので、
1.tidyでXHTMLに整形。
2.SimpleXMLで直接ノードを取得。

の方法(すなわち、現在の方法)がベストだとおもいます。

Re:Re:Re:tidyでHTMLのパースを実現したい

> xpathのように各要素に直接アクセスはおそらくないです(私には見つけられませんでした)。

ご説明ありがとうございます。やはり、直接アクセスは無理ですか・・・。
ご指摘の通り、simpleXMLを利用して取得します。なお、参考までにxpathを利用する際の注意点(私が苦労した点)は次の通りです。

1)DOMだとなぜか文字化けするので、simpleXMLを利用した
2)xpathの指定方法(次はmetaのキーワードの場合)
  /x:html/x:head/x:meta[@name='keywords']/attribute::content
3)xhtmlでは名前空間が指定されているので、registerXPathNamespaceを実行し、
  プレフィックス(上記では「x」)を指定する必要がある
4)例えばtitleタグが複数ある場合もあるので、nodeをforeachで出力する
5)文字列に&nbspがあるとsimplexmlが読み込めないため、ereg_replace等で
  削除しておく(tidyのquote-nbspをfalseにしても動作しない場合がある)


少し長いですが、以下に私が作成したスクリプトを記載します。もし改善点などがあれば、ご指摘いただけると幸いです。

  1. <?php
  2. ###=============================================================
  3. ### config
  4. ###=============================================================
  5.  
  6. ### parseすべきタグのxpath(prefixは「x」で指定する)
  7. $tagXpath = array(
  8.   'title'            => "/x:html/x:head/x:title/text()",
  9.   'h1'               => "/x:html/x:body/x:h1/text()",
  10.   'meta-keywords'    => "/x:html/x:head/x:meta[@name='keywords']/attribute::content",
  11.   'meta-description' => "/x:html/x:head/x:meta[@name='description']/attribute::content"
  12. );
  13.  
  14. ### Tidyの設定
  15. $config = array(
  16.   'indent'         => false,
  17.   'output-xhtml'   => true,
  18.   'clean'          => true,
  19.   'quote-nbsp'     => false,
  20. );
  21.  
  22. ### xhtmlの名前空間
  23. $nsXhtml = 'http://www.w3.org/1999/xhtml';
  24.  
  25. ###=============================================================
  26. ### 処理開始
  27. ###=============================================================
  28.  
  29. ### 処理対象のURL
  30. $url = "http://www.yahoo.co.jp/";
  31.  
  32. ### HTML情報の取得&UTF-8に変換
  33. $html = file_get_contents($url);
  34. $codeList = array("Shift_JIS","EUC-JP","SJIS","UTF-8","JIS");
  35. $html = mb_convert_encoding($html,"UTF-8",mb_detect_encoding($html,$codeList));
  36.  
  37. ### Tidyオブジェクトの生成
  38. $tidy = new tidy;
  39. $tidy->parseString($html,$config,'utf8');
  40. $tidy->cleanRepair();
  41. $tidy = ereg_replace("&nbsp;"," ",$tidy);
  42.  
  43. ### simple_xmlのオブジェクトを生成
  44. $xmlObj = new SimpleXMLElement($tidy);
  45. $xmlObj->registerXPathNamespace('x',$nsXhtml);
  46.  
  47. ### 指定されたタグの情報を取得
  48. foreach($tagXpath as $xpathKey => $xpathDetail){
  49.   $resultArray = array();
  50.   print "$xpathKey:\t";
  51.   $nodeArray = $xmlObj->xpath($xpathDetail);
  52.   if(!empty($nodeArray[0])){
  53.     foreach($nodeArray as $oneNodeVal){
  54.       $resultArray[] = chop(ereg_replace("\n"," ",$oneNodeVal));
  55.     }
  56.     print join("<BR>",$resultArray);
  57.   }else{
  58.     print "empty";
  59.   }
  60.   print "\n";
  61. }
  62.  
  63. ### 終了
  64. exit;
  65. ?>
PDOでの接続について 質問一覧 チェックボックス 変数の受け渡しに...