如何解析部分 HTML?

Posted

技术标签:

【中文标题】如何解析部分 HTML?【英文标题】:How do I parse partial HTML? 【发布时间】:2010-12-28 08:45:26 【问题描述】:

我正在尝试在 php 中使用 DOM 解析一些 html,但遇到了一些问题。首先,如果这改变了解决方案,我拥有的 HTML 不是一个完整的页面,而是它的一部分。

<!-- This is the HTML that I have --><a href='/games/'>
<div id='game'>
<img src='http://images.example.com/games.gif' width='300' height='137' border='0'>
<br><b> Game </b>
</div>
<div id='double'>
<img src='http://images.example.com/double.gif' width='300' height='27' border='0' alt='' title=''>
</div>
</a>

现在我试图只获取 ID 为 double 的 div。我已经尝试了以下代码,但它似乎无法正常工作。我可能做错了什么?

//The HTML has been loaded into the variable $html
$dom=new domDocument;
$dom->loadHTML($html);
$dom->preserveWhiteSpace = false; 
$keepme = $dom->getElementById('double'); 

$contents = '<div style="text-align:center">'.$keepme.'</a></div>';
echo $contents;

【问题讨论】:

它在做什么或不做什么? 【参考方案1】:

HTML Tidy 应该能够“纠正”破碎和碎片化的 HTML 文档,将它们变成可以用其他工具解析的东西

http://devzone.zend.com/article/761

Tidy 扩展是 PHP 5 中的新功能, 并且可以从 PHP 版本获得 5.0b3 向上。它基于 TidyLib 库,并允许 开发人员进行验证、修复和 解析 HTML、XHTML 和 XML 文档 来自 PHP。

【讨论】:

【参考方案2】:

来自DomDocument::getElementById

要使此功能起作用,您将 需要要么设置一些ID属性 使用 DOMElement::setIdAttribute 或 DTD 将属性定义为 类型 ID。在后一种情况下,您 需要验证您的文件 使用 DOMDocument::validate 或 DOMDocument->validateOnParse 之前 使用这个函数。

更多信息

Simplify PHP DOM XML parsing - how? How do you parse and process HTML/XML in PHP?

由于迟早有人会提到使用正则表达式来做这件事,所以您可以使用以下模式:/&lt;div id='double'&gt;(.*)&lt;\/div&gt;/simU

此外,您可以只使用常规字符串函数来提取 div 部分,例如

$div = strstr($html, '<div id="double">');
$div = substr($div, 0, strpos($div, '</div>') + 6);
echo $div;

虽然我同意,你不应该使用 RegEx 或 String 函数来解析 HTML 或 XML,我觉得这样做绝对没问题,只要你唯一关心的是得到这个片段中的单个 div。保持简单。

【讨论】:

当然,除非有嵌套的 div 标签。正则表达式不是用于解析html。 如果他真的在解析那个片段,我会同意。但他只是想从中提取一个明确定义的片段。又不是他在遍历DOM,所以我想把fragment当作字符串来处理就可以了。 此外,我在第一句话中已经将他指向 SimpleHTML。【参考方案3】:

我认为DOMDocument::getElementById 不适用于您的情况:(引用)

要使此功能起作用,您将 需要设置一些ID属性 与DOMElement::setIdAttribute 或 DTD 将属性定义为 类型 ID。 在后一种情况下,您 需要验证您的文件 与DOMDocument::validateDOMDocument-&gt;validateOnParse之前 使用这个函数。

一个可能有效的解决方案是使用一些 XPath query 来提取您正在寻找的元素。

首先,让我们加载 HTML 部分,就像你第一次做的那样:

$dom=new domDocument;
$dom->loadHTML($html);
var_dump($dom->saveHTML());

var_dump 在这里只是为了证明 HTML 部分已经成功加载——从它的输出来看,它已经成功了。

然后,实例化DOMXPath 类,并使用它来查询您想要获取的元素:

$xpath = new DOMXpath($dom);
$result = $xpath->query("//*[@id = 'double']");
$keepme = $result->item(0);

我们现在必须添加你想要的元素 ;-)

但是,为了将它的 HTML 内容注入到另一个 HTML 段中,我们必须首先获取它的 HTML 内容。

我不记得有任何“简单”的方法可以做到这一点,但是像这样的东西可以解决问题:

$tempDom = new DOMDocument();
$tempImported = $tempDom->importNode($keepme, true);
$tempDom->appendChild($tempImported);
$newHtml = $tempDom->saveHTML();
var_dump($newHtml);

而且...我们有您的double &lt;div&gt; 的 HTML 内容:

string '<div id="double">
<img src="http://images.example.com/double.gif"   border="0"  title="">
</div>
' (length=125)

现在,你只需要用它做任何你想做的事;-)

【讨论】:

是的!我到处寻找如何获取片段与完整的 HTML 文档,几乎放弃了。谢谢!【参考方案4】:

一个 XML 文档在根级别只能有一个元素。很可能,HTML 解析器也有类似的要求。尝试将内容包装在 &lt;body/&gt; 标记中。

似乎是别的东西。 This page 描述了可能的原因。我建议您使用 XPath 来获取元素。

【讨论】:

【参考方案5】:

片段是 HTML,但要通过 DOM 解析,它应该是 XHTML。 每个打开的标签都必须关闭。

在您的情况下,这意味着您应该将 &lt;br&gt; 替换为 &lt;br /&gt; 并将 &lt;img ... &gt; 替换为 &lt;img ... /&gt;

【讨论】:

这实际上不是真的。 $dom->loadHTML("") 工作得很好并且不会失败解析。事实上,$dom->saveXML() 会显示带有正确闭合标签的输出。 这完全取决于您使用的库。在 python 中: xml.dom.minidom.parseString("") -> 返回异常。 xml.dom.minidom.parseString("") 有效。我宁愿一开始就以正确的格式输入,而不是像我期望的那样依赖库来解析不正确的输入。【参考方案6】:

在同一个问题苦苦挣扎了几个小时后,我找到了这个对我有用的解决方案,与我在网上找到的其他解决方案相比,它相对简单。

此解决方案修复了不需要的 DOCTYPE 和 html、正文标签以及编码问题。

$htmlContent = "<h1>This is a heading</h1><p>This is a paragraph</p>";

// 1.) Load the html
$dom = new DOMDocument();
$dom->loadHTML("<meta http-equiv='Content-Type' content='charset=utf-8' /><div>$htmlContent</div>");

// 2.) Do you logic
$dom->getElementsByTagName('h1')[0]->setAttribute('class', 'happy');

// 3.) Render the html
$wrapperNode = $dom->getElementsByTagName('div')[0];
$renderedHtml = $dom->saveHTML($wrapperNode);
// If you want to keep the wrapper div
echo $renderedHtml;
// Or remove the wrapper <div>
echo substr(trim($renderedHtml), 5, -6);

【讨论】:

以上是关于如何解析部分 HTML?的主要内容,如果未能解决你的问题,请参考以下文章

如何解决 Django 中显示“无法解析剩余部分”的 TemplateSyntaxError

浏览器如何部分加载 DOM 和 CSSOM?

使用 Javascript 解析电子邮件源的文本/html 部分

解析多个.html文件并删除部分html代码的方法

将HTML元素解析成部分[重复]

Beautifulsoup:解析 html – 获取部分 href