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


当前回答

只需使用DOMDocument->loadHTML()就可以了。libxml的HTML解析算法非常好,速度也很快,与流行的观点相反,它不会对格式错误的HTML产生影响。

其他回答

Symfony框架具有可以解析HTML的捆绑包,您可以使用CSS样式来选择DOM,而不是使用XPath。

只需使用DOMDocument->loadHTML()就可以了。libxml的HTML解析算法非常好,速度也很快,与流行的观点相反,它不会对格式错误的HTML产生影响。

处理HTML/XML DOM的方法有很多,其中大多数已经提到。因此,我不会亲自列出这些。

我只想补充一点,我个人更喜欢使用DOM扩展,以及为什么:

iit充分利用了底层C代码的性能优势它是OO PHP(并允许我对其进行子类化)它的级别相当低(这允许我将其用作更高级行为的非臃肿基础)它提供对DOM的每个部分的访问(不像SimpleXml,它忽略了一些鲜为人知的XML特性)它具有用于DOM爬行的语法,与原生Javascript中使用的语法类似。

虽然我怀念为DOMDocument使用CSS选择器的能力,但有一种非常简单和方便的方法可以添加此功能:将DOMDocument子类化,并将类似于querySelectorAll和querySelector的JS方法添加到子类中。

为了解析选择器,我建议使用Symfony框架中的非常简约的CsSelector组件。该组件只是将CSS选择器转换为XPath选择器,然后可以将其输入到DOMX路径中以检索相应的Nodelist。

然后,您可以使用这个(仍然是非常低级的)子类作为更高级类的基础,例如解析非常特定的XML类型或添加更多类似jQuery的行为。

下面的代码直接来自我的DOM查询库,并使用了我描述的技术。

对于HTML分析:

namespace PowerTools;

use \Symfony\Component\CssSelector\CssSelector as CssSelector;

class DOM_Document extends \DOMDocument {
    public function __construct($data = false, $doctype = 'html', $encoding = 'UTF-8', $version = '1.0') {
        parent::__construct($version, $encoding);
        if ($doctype && $doctype === 'html') {
            @$this->loadHTML($data);
        } else {
            @$this->loadXML($data);
        }
    }

    public function querySelectorAll($selector, $contextnode = null) {
        if (isset($this->doctype->name) && $this->doctype->name == 'html') {
            CssSelector::enableHtmlExtension();
        } else {
            CssSelector::disableHtmlExtension();
        }
        $xpath = new \DOMXpath($this);
        return $xpath->query(CssSelector::toXPath($selector, 'descendant::'), $contextnode);
    }

    [...]

    public function loadHTMLFile($filename, $options = 0) {
        $this->loadHTML(file_get_contents($filename), $options);
    }

    public function loadHTML($source, $options = 0) {
        if ($source && $source != '') {
            $data = trim($source);
            $html5 = new HTML5(array('targetDocument' => $this, 'disableHtmlNsInDom' => true));
            $data_start = mb_substr($data, 0, 10);
            if (strpos($data_start, '<!DOCTYPE ') === 0 || strpos($data_start, '<html>') === 0) {
                $html5->loadHTML($data);
            } else {
                @$this->loadHTML('<!DOCTYPE html><html><head><meta charset="' . $encoding . '" /></head><body></body></html>');
                $t = $html5->loadHTMLFragment($data);
                $docbody = $this->getElementsByTagName('body')->item(0);
                while ($t->hasChildNodes()) {
                    $docbody->appendChild($t->firstChild);
                }
            }
        }
    }

    [...]
}

另请参见Symfony的创建者Fabien Potencier关于为Symfony创建CsSelector组件的决定以及如何使用它的CSS选择器解析XML文档。

这听起来像是W3C XPath技术的一个很好的任务描述。很容易表达诸如“返回嵌套在<foo><bar><baz>元素中的img标记中的所有href属性”之类的查询。我不是一个PHP爱好者,无法告诉您XPath可能以什么形式可用。如果可以调用外部程序来处理HTML文件,则应该能够使用命令行版本的XPath。有关快速介绍,请参见http://en.wikipedia.org/wiki/XPath.

解析xml的最佳方法:

$xml='http://www.example.com/rss.xml';
$rss = simplexml_load_string($xml);
$i = 0;
foreach ($rss->channel->item as $feedItem) {
  $i++;
  echo $title=$feedItem->title;
  echo '<br>';
  echo $link=$feedItem->link;
  echo '<br>';
  if($feedItem->description !='') {
    $des=$feedItem->description;
  } else {
    $des='';
  }
  echo $des;
  echo '<br>';
  if($i>5) break;
}