如何解析HTML/XML并从中提取信息?


当前回答

SimpleHtmlDom的第三方替代方案使用DOM而不是字符串解析:phpQuery、Zend_DOM、QueryPath和FluentDom。

其他回答

XML_HTMLMax相当稳定——即使不再维护它。另一种选择是通过HtmlTidy将HTML导入,然后用标准的XML工具解析它。

不使用正则表达式解析HTML有几个原因。但是,如果您完全控制将生成什么HTML,那么可以使用简单的正则表达式。

上面是一个通过正则表达式解析HTML的函数。请注意,此函数非常敏感,要求HTML遵守某些规则,但它在许多场景中都非常有效。如果您想要一个简单的解析器,并且不想安装库,请尝试一下:

function array_combine_($keys, $values) {
    $result = array();
    foreach ($keys as $i => $k) {
        $result[$k][] = $values[$i];
    }
    array_walk($result, create_function('&$v', '$v = (count($v) == 1)? array_pop($v): $v;'));

    return $result;
}

function extract_data($str) {
    return (is_array($str))
        ? array_map('extract_data', $str)
        : ((!preg_match_all('#<([A-Za-z0-9_]*)[^>]*>(.*?)</\1>#s', $str, $matches))
            ? $str
            : array_map(('extract_data'), array_combine_($matches[1], $matches[2])));
}

print_r(extract_data(file_get_contents("http://www.google.com/")));

简单HTML DOM是一个很棒的开源解析器:

simplehtmldom.sourceforge

它以面向对象的方式处理DOM元素,新的迭代包含了大量不兼容代码。还有一些很棒的函数,如JavaScript中的“find”函数,它将返回该标记名元素的所有实例。

我已经在许多工具中使用了这个,在许多不同类型的网页上测试了它,我认为它非常有用。

为什么不应该以及何时应该使用正则表达式?

首先,一个常见的误称:Regexp不用于“解析”HTML。然而,正则表达式可以“提取”数据。提取是它们的目的。与适当的SGML工具包或基线XML解析器相比,正则表达式HTML提取的主要缺点是它们的语法工作和不同的可靠性。

考虑制作一个稍微可靠的HTML提取正则表达式:

<a\s+class="?playbutton\d?[^>]+id="(\d+)".+?    <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?

比简单的phpQuery或QueryPath等效文件可读性差得多:

$div->find(".stationcool a")->attr("title");

然而,在某些特定的用例中,它们可以提供帮助。

许多DOM遍历前端不显示HTML注释<!--,然而,它们有时是用于提取的更有用的锚。特别是伪HTML变体<$var>或SGML残基很容易用正则表达式驯服。通常,正则表达式可以节省后期处理。然而,HTML实体通常需要手动管理。最后,对于提取<img src=urls等极其简单的任务,它们实际上是一个可能的工具。与SGML/XML解析器相比,速度优势主要用于这些非常基本的提取过程。

有时甚至建议使用正则表达式/<--内容-->(.+?)<--END-->/并使用更简单的HTML解析器前端处理其余部分。

注意:我实际上有一个应用程序,在那里我交替使用XML解析和正则表达式。就在上周,PyQuery解析中断,正则表达式仍然有效。是的,很奇怪,我自己也解释不了。但事情就是这样发生的。因此,请不要因为现实世界的考虑与正则表达式=邪恶模因不匹配就投票否决。但我们也不要对此投太多赞成票。这只是这个话题的一个旁注。

我已经编写了一个通用XML解析器,可以轻松处理GB文件。它基于XMLReader,非常容易使用:

$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
    echo $tag->field1;
    echo $tag->field2->subfield1;
}

下面是github repo:XmlExtractor