解析HTML的DOM方法

3
我们有一个古老的(内部)静态信息网站。我们将用更好的东西来替换它,因此我需要获取所有信息。我过去使用正则表达式来完成此操作,但最近我看到了一些文章,指出使用正则表达式从HTML中解析信息是邀请克苏鲁来到这个领域
因此,我决定学习一些新技巧,重新开始并使用DOM方式处理它。 我需要的HTML部分如下:
<table id="articles">
    <tr>
    <th>
        <a href='articles/aa123.html'><img src="/iamges/aa123.jpg" alt="some article"></a>
        <br />short description
    </th>
    <td>
        <table class='details'>
        <tr><th><a href='articles/aa123.html'>Some Article</a></th></tr>
        <tr><th>Type:</th><td>article type</td></tr>
        <tr><th>Price:</th><td>€ 99</td></tr>
        <tr><th>Manufacturer:</th><td>Some Company</td></tr>
        <tr><th>Warehouse:</th><td>x</td></tr>
        </table>
    </td>
</tr>   
</table>

到目前为止,我得到了这个:

$dom = new DOMDocument();
@$dom->loadHTMLFile ($file);
$xpath = new DOMXPath($dom);
$query = "/html/body/table[@id='articles']//th"; //catch all TH's 
$data = $xpath->evaluate($query);

我在这里遇到了困难。我知道返回的 TH 元素的所有内容都在 ChildNodes 中,但是我很难获取这些值。我需要详细页面的 URL 和 Price 列的值。

我该如何提取它们?

目前我想到了以下方法:

$query = '//table[@class="details"]//td';
$data= $xpath->evaluate($query);
$c = $ths->length;

for ($i = 0; $i < $c; $i++) {   
    echo htmlentities($data->item($i)->nodeValue);      
}

但是这只显示TD中的文本值。当内容是链接时,它只显示链接标题。而不是URL。

更新 感谢Fab的建议,我取得了一些进展。目前我得到了以下内容:

$tables = $xpath->query('//table[@class="details"]');
foreach($tables as $table) {
    $url = $xpath->evaluate('//th/a/@href', $table);
    $articleName= $xpath->evaluate('//th/a', $table);
    $Manufacturer= $xpath->evaluate('//th[text()="Manufacturer:"]/../td', $table);

    echo 'articleName:' . $articleName . ' <br />';
    echo 'Manufacturer:' . $Manufacturer. ' <br />';
    echo 'url:' . $url. ' <br />';
    echo '<br />';
}

但是出于某些原因,它总是显示第一篇文章的数据(对于页面上有多少篇文章,就重复显示多少次)。就好像“foreach”语句总是返回找到的第一个表格一样。有什么建议吗?

1个回答

1
XPath获取URL的表达式为:

//a/@href

//table[@class="details"]//th/a@href

"而对于价格列:"
//table[@class="details"]//th[text()="Price:"]/../td

也许你想单独获取每个表格的URL和价格,为此,你可以先使用DOMNodeList收集所有“details”表格,然后在其中搜索(使用上下文参数):

$tables = $xpath->query('//table[@class="details"]');
foreach($tables as $table) {
    $url = $xpath->evaluate('//th/a@href', $table);
    $price = $xpath->evaluate('//th[text()="Price:"]/../td', $table);
    echo "$url - $price <br>";
}

更新

我忘记了一件事:上下文参数仅对相对路径起作用,而//th/...是绝对路径。你需要在开头加一个点:.//th/...

请看这个链接: 工作演示

(我还必须将evaluate替换为query并明确访问第一项的值:

$xpath->query(...)->item(0)->nodeValue;

谢谢!我会尝试的(我一直在关注如何使用正则表达式来获取所有信息)。 - Walter81
我取得了一些进展,但仍然有一些东西缺失。请参见我上面的更新。 - Walter81
太好了!非常感谢(另外,phpsandbox网站也是一个很好的提示;o) - Walter81
一个小问题:为什么URL值存储在“value”键中,而其他值存储在“nodevalue”键中?有什么区别吗? - Walter81
URL在属性(DOMAttr)中,该属性具有值,其他元素的内部文本(DOMElement)。实际上,属性也是节点,它们的节点值等于它们的值,因此您也可以在任何地方使用nodeValue。 - Fabian Schmengler
我明白了。感谢您的帮助!我已经快要回到“好老的正则表达式”了,但现在我看到了这种方法的优点。 - Walter81

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接