web-dev-qa-db-ja.com

PHPのDOMDocument

ドキュメントをクロールして解析するために、DOMに関するドキュメントと例を読み始めました。

たとえば、以下に示すドキュメントの一部があります。

    <div id="showContent">
    <table>
    <tr>
        <td>
         Crap
        </td>
    </tr>
<tr>
          <td width="172" valign="top"><a href="link"><img height="91" border="0" width="172" class="" src="img"></a></td>
          <td width="10">&nbsp;</td>
          <td valign="top"><table cellspacing="0" cellpadding="0" border="0">
              <tbody><tr>
                <td height="30"><a class="px11" href="link">title</a><a><br>
                    <span class="px10"></span>
                </a></td>
              </tr>
              <tr>
                <td><img height="1" width="580" src="crap"></td>
              </tr>
              <tr>
                <td align="right">
                    <a href="link"><img height="16" border="0" width="65" src="/buy"></a>
                </td>
              </tr>
              <tr>
                <td valign="top" class="px10">
                    <p style="width: 500px;">description.</p>
                </td>
              </tr>
          </tbody></table></td>
        </tr>
    <tr>
        <td>
Crap
        </td>
    </tr>
    <tr>
        <td>
         Crap
        </td>
    </tr>
    </table>
    </div>

次のコードを使用して、すべてのtrタグを取得し、それらの中にがらくたや情報があるかどうかを分析しようとしています。

$dom = new DOMDocument();
@$dom->loadHTML($html);

$xpath = new DOMXPath($dom);


$tags = $xpath->query('.//div[@id="showContent"]');
foreach ($tags as $tag) {
    $string="";
    $string=trim($tag->nodeValue);
    if(strlen($string)>3) {
        echo $string;
        echo '<br>';
    }
}

ただし、タグなしで文字列が削除されただけです。次に例を示します。

Crap

Crap
Title
Description

しかし、私は取得したいと思います:

<tr>
   <td>Crap</td>
</tr>
<tr>
   <a href="link">title</a>
</tr>

HTMLノード(タグ)を保持する方法は?

25
Saikios

DOMを使用する場合は、概念を理解する必要があります。 DOMDocumentを含むDOMドキュメント内のすべてがノードです。

DOMDocumentは、ノードの階層ツリー構造です。ルートノードから始まります。そのルートノードは子ノードを持つことができ、これらすべての子ノードは独自に子ノードを持つことができます。基本的に、DOMDocument内のすべては、要素、属性、テキストコンテンツなど、ある種のノードタイプです。

_          HTML                               Legend: 
         /    \                              UPPERCASE = DOMElement
       HEAD  BODY                            lowercase = DOMAttr
      /          \                           "Quoted"  = DOMText
    TITLE        DIV - class - "header"
     |             \
"The Title"        H1
                    |
           "Welcome to Nodeville"
_

上の図は、いくつかのノードを持つDOMDocumentを示しています。 2つの子(HEADとBODY)を持つルート要素(HTML)があります。接続線は軸と呼ばれます。軸をTITLE要素までたどると、DOMTextリーフが1つあることがわかります。これは、見過ごされがちなことを示しているため、重要です。

_<title>The Title</title>
_

1つではなく、2つのノードです。 DOMTextの子を持つDOMElement。同様に、これ

_<div class="header">
_

は実際には3つのノードです。DOMTextを保持するDOMAttrを持つDOMElementです。これらはすべてDOMNodeからプロパティとメソッドを継承するため、 DOMNodeクラス。 に精通することが不可欠です。

実際には、これは、フェッチしたDIVがドキュメント内の他のすべてのノードにリンクされていることを意味します。いつでもルート要素または葉まで行くことができます。それはすべてそこにあります。必要な情報については、ドキュメントをクエリまたはトラバースするだけです。

childNodesDIVを繰り返すか、getElementByTagName()またはXPathを使用するかは、あなた次第です。生のHTMLではなく、そのHTMLドキュメント全体を表すノードを使用していることを理解する必要があります。

ドキュメントから特定の情報を抽出する際にサポートが必要な場合は、ドキュメントから取得する情報を明確にする必要があります。たとえば、テーブルからすべてのリンクをフェッチする方法を尋ねると、次のように答えることができます。

_$div = $dom->getElementById('showContent');
foreach ($div->getElementsByTagName('a') as $link) 
{
    echo $dom->saveXML($link);
}
_

ただし、より具体的でない限り、どのノードが関連しているのかを推測することしかできません。

DOMの操作方法に関する例とコードスニペットがさらに必要な場合は、関連する質問に対する以前の回答を参照してください。

これで、DOMで使用する可能性のある基本から中程度のユースケースごとにスニペットが作成されるはずです。

66
Gordon

パーサーを作成するには、 htmlDOM を使用できます。

Phpで書かれた非常にシンプルで使いやすいDOMパーサーです。これを使用すると、divタグの内容を簡単に取得できます。

たとえば、属性divが値idであるすべてのtextタグを検索します。

$ret = $html->find('div[id=text]');
4
lokeshsk