如何在 PHP 中分析和处理 HTML\ xml?

共30个回答,已解决, 标签: php xml parsing xml-parsing html-parsing

如何解析 HTML\ xml 并从中提取信息?

第1个答案(采用)

本机 XML 扩展

我更喜欢使用一个本机 xml 扩展, 因为它们与 php 捆绑在一起, 通常比所有第三方的 libs 都快, 并给了我对标记所需的所有控制。

Dom

DOM 扩展允许您通过 php5 的 DOM API 对 XML 文档进行操作。它是 W3c 文档对象模型核心级别 3 的实现, 这是一个与平台和语言无关的接口, 允许程序和脚本动态访问和更新文档的内容、结构和样式。

DOM 能够分析和修改真实世界 (断开) 的 HTML, 并且它可以执行Xpath 查询。它是基于libxml.

使用 DOM 需要一些时间来提高工作效率, 但这段时间是非常值得的。由于 DOM 是一个与语言无关的接口, 您会发现许多语言的实现, 因此, 如果您需要更改编程语言, 那么您很可能已经知道如何使用该语言的 DOM API。

抓取 a 元素的 href 属性中可以找到一个基本的用法示例, 在Php 中的 domdocument中可以找到一般的概念概述

如何使用 Dom 扩展已在堆栈溢出上广泛介绍,因此, 如果您选择使用它, 则可以确保您遇到的大多数问题都可以通过搜索/浏览堆栈溢出来解决。

XMLReader

XMLReader 扩展是一个 XML 拉分析器。读取器充当光标, 在文档流上前进, 并在途中的每个节点上停止。

XMLReader 和 DOM 一样, 是基于 libxml 的。我不知道如何触发 HTML 解析器模块, 因此使用 XMLReader 分析损坏的 HTML 的可能性可能不如使用 DOM 更强大, 在 DOM 中, 您可以显式地告诉它使用 libxml 的 HTML 解析器模块。

使用 php 从 h1 标记中获取所有值时, 可以找到一个基本的使用示例

XML 解析器

此扩展允许您创建 XML 分析器, 然后为不同的 XML 事件定义处理程序。每个 XML 解析器还具有一些可以调整的参数。

XML 解析器库也基于 libxml, 并实现了 sax样式的 xml 推送解析器。它可能是比 DOM 或 SimpleXML 更好的内存管理选择, 但与 XMLReader 实现的拉分析器相比, 它将更难使用。

简单的

简单 Xml 扩展提供了一个非常简单且易于使用的工具集, 用于将 XML 转换为可使用普通属性选择器和数组迭代器处理的对象。

当您知道 HTML 是有效的 XHTML 时, 简单 Xml 是一个选项。如果你需要解析破碎的 HTML, 甚至不要考虑 SimpleXml, 因为它会窒息。

一个基本的使用示例可以在[](https://stackoverflow.com/questions/4906073/a-simple-program-to-crud-node-and-node-values- href=)

第2个答案

尝试简单的 Html Dom 解析器

  • 用 PHP5 + 编写的 HTML dom 解析器, 让您以一种非常简单的方式操作 HTML!
  • 要求 PHP 5 +。
  • 支持无效的 HTML。
  • 在 HTML 页面上查找带有选择器的标记, 就像 jQuery 一样。
  • 从一行中提取 html 中的内容。
  • 下载

例子:

如何获取 HTML 元素:

// Create DOM from URL or file
$html = file_get_html('http://www.example.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '';

如何修改 HTML 元素:

// Create DOM from string
$html = str_get_html('HelloWorld');

$html->find('div', 1)->class = 'bar';

$html->find('div[id=hello]', 0)->innertext = 'foo';

echo $html;

从 HTML 中提取内容:

// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;

刮板板:

// Create DOM from URL
$html = file_get_html('http://slashdot.org/');

// Find all article blocks
foreach($html->find('div.article') as $article) {
    $item['title']     = $article->find('div.title', 0)->plaintext;
    $item['intro']    = $article->find('div.intro', 0)->plaintext;
    $item['details'] = $article->find('div.details', 0)->plaintext;
    $articles[] = $item;
}

print_r($articles);
第3个答案

只需使用Domdount-> 加载 html ()并完成它。libxml 的 HTML 解析算法相当好, 速度很快, 与流行的观点相反, 它不会阻塞格式错误的 html。

第4个答案

为什么你不应该,什么时候应该使用正则表达式?

首先, 一个常见的用词不当: Regexps 不是用于*"解析"* html。然而注册可以*"提取" 数据* 。提取是他们的目的。在适当的 SGML 工具包或基线 XML 解析器上, 正则表达式 HTML 提取的主要缺点是它们的语法工作和不同的可靠性。

考虑到, 使一个有点可靠的 HTML 提取正则表达式:

]+id="(\d+)".+?    ]+href="(http://[^">]+)"[^>]*>([^<>]+).+?

比简单的 phpQuery 或 QueryPath 等效的可读性要低:

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

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

  • 许多 DOM 遍历前端不会显示 HTML 注释 (.+?)/ , 并使用更简单的 html 解析器前端处理其余内容。

    请注意:实际上, 我有这个应用程序, 在那里我使用 xml 解析和正则表达式交替使用。就在上周, PyQuery 解析中断了, 正则表达式仍然有效。是的, 怪怪的, 我自己也解释不清楚。但事情就这样发生了。
    所以, 请不要投票现实世界的考虑下来, 只是因为它不匹配的正则表达式 = 邪恶的模子。但我们也不要过多投票。这只是这个话题的一个旁白.

第5个答案

phpqueryquerypath在复制流畅的 jquery api 方面极为相似。这也是为什么它们是在 PHP 中正确解析 html 的两种最简单的方法。

查询路径的示例

基本上, 您首先从 HTML 字符串创建一个可查询的 DOM 树:

 $qp = qp("title..."); // or give filename or URL

生成的对象包含 HTML 文档的完整树表示形式。它可以使用 DOM 方法遍历。但常见的方法是使用 Css 选择器, 如 jQuery 中的选择器:

 $qp->find("div.classname")->children()->...;

 foreach ($qp->find("p img") as $img) {
     print qp($img)->attr("src");
 }

大多数情况下, 您希望使用简单 #id.class / DIV 或标记选择 ->find() 器。但您也可以使用Xpath语句, 这些语句有时会更快。还有典型的 jQuery 方法, ->children() ->text() 喜欢并特别 ->attr() 简化了提取正确的 html 代码段。(并且已经解码了他们的 SGML 实体。

 $qp->xpath("//div/p[1]");  // get first paragraph in a div

QueryPath 还允许向流 () 中注入新标记 ->append , 以及以后的输出和美化更新的文档 ( ->writeHTML )。它不仅可以解析格式错误的 HTML, 还可以分析各种 XML 方言 (使用命名空间), 甚至可以从 HTML 微格式 (XFN、vCard) 中提取数据。

 $qp->find("a[target=_blank]")->toggleClass("usability-blunder");

.

phpQuery 还是 QueryPath?

通常, QueryPath 更适合于文档的操作。虽然 phpQuery 也实现了一些伪 AJAX 方法 (只是 HTTP 请求), 以更接近于 jQuery。据说, phpQuery 通常比 QueryPath 更快 (因为整体功能较少)。

有关差异的更多信息, 请参见tagbyte. org 的回溯机上的此比较。(原始来源丢失, 所以这里有一个互联网存档链接。是的, 您仍然可以找到丢失的页面, 人员。

这里有一个全面的 QueryPath 介绍

优势

  • 简单和可靠
  • 易于使用的替代品->find("a img, a object, div a")
  • 正确的数据解锁 (与正则表达式的删除相比)
第6个答案

简单的 HTML DOM 是一个伟大的开源解析器:

simplehtmldom. sourcefem

它以面向对象的方式处理 DOM 元素, 并且新的迭代对不符合的代码有很大的覆盖率。还有一些很好的函数, 比如你在 JavaScript 中看到的, 比如 "find" 函数, 它将返回该标记名称元素的所有实例。

我在许多工具中使用过, 在许多不同类型的网页上对其进行测试, 我认为它很管用。

第7个答案

这里没有提到的一个通用方法是通过tidi运行 html, 可以将其设置为吐出保证有效的 xhtml。然后, 您可以在其上使用任何旧的 XML 库。

但对于您的具体问题, 您应该看看这个项目: http://fivefilters.org/content-only/ --它是可读性算法的修改版本, 它在提取文本内容 (而不是页眉和页脚))。

第8个答案

对于 1a 和 2:i. 我将投票给新的 Symfony 组件 Et 类 DOMCrawler ( domcrawler )。 此类允许类似于 CSS 选择器的查询。看看这个演示文稿, 看看真实世界的例子: 新闻的符号 2 世界。

该组件设计为独立工作, 无需 Symfony 即可使用。

唯一的缺点是, 它将只适用于 PHP 5.3 或更新的。

第9个答案

顺便说一下, 这通常被称为屏幕刮擦.我用于此目的的库是简单的 Html Dom 解析器

第10个答案

我们以前为我们的需要创造了不少爬虫。说到底, 通常是简单的正则表达式做得最好。虽然上面列出的库是好的, 因为它们是创建的原因, 如果你知道你在寻找什么, 正则表达式是一个更安全的方法, 因为你也可以处理无效的 Html/xhtml 结构, 这将失败, 如果加载通过大多数解析 器。

第11个答案

我推荐Php 简单的 HTML Dom 解析器

它确实有很好的功能, 例如:

foreach($html->find('img') as $element)
       echo $element->src . '';
第12个答案

这听起来像是 W3C xpath技术的一个很好的任务描述。很容易表达像 "在 href 嵌套的标记中返回所有属性" 这样的查询 img elements 。不是 PHP 爱好者, 我不能告诉你 XPath 可能以什么形式提供。如果可以调用外部程序来处理 HTML 文件, 则应该能够使用 XPath 的命令行版本。 有关快速介绍, 请参阅http://en.wikipedia.org/wiki/XPath

第13个答案

使用 DOM 而不是字符串分析的简单的简单的替代方法的第三方选择: phpqueryzend _ domquerypathfluentdom

第14个答案

是的, 你可以使用简单 _ html _ dom 的目的。然而, 我已经工作了相当多的简单 _ html _ dom, 特别是对于网络报废, 并发现它是太脆弱。它做的基本工作, 但我不会推荐它反正。

我从来没有把卷发用于这个目的, 但我学到的是, 卷曲可以更有效地完成工作, 而且更扎实。

请查看此链接:刮网网站-卷曲

第15个答案

Querypath是好的, 但要小心 "跟踪状态", 因为如果你没有意识到它的含义, 这可能意味着你浪费了大量的调试时间试图找出发生了什么, 为什么代码不工作。

它的意思是, 结果集上的每个调用都会修改对象中的结果集, 它并不像在每个链接是一个新集合的 jquery 中那样是可链接的, 您有一个集合, 它是查询的结果, 每个函数调用都修改该单个集。

为了获得类似于 jquery 的行为, 在执行类似于操作的 filter/修改之前, 您需要分支, 这意味着它将更紧密地反映 jquery 中发生的情况。

$results = qp("div p");
$forename = $results->find("input[name='forename']");

$results现在包含的 input[name='forename'] 不是原始查询的结果集, "div p" 这绊倒了我很多, 我发现的是, querypath跟踪过滤器和查找和所有这些修改您的结果并将它们存储在对象中。 你需要这样做, 而不是

$forename = $results->branch()->find("input[name='forname']")

然后 $results 不会被修改, 你可以重复使用的结果集一次又一次, 也许有人有更多的知识可以澄清这一点, 但它基本上是这样从我所发现的。

第16个答案

高级 Html dom是一个简单的 html dom替换, 它提供了相同的接口, 但它是基于 dom 的, 这意味着没有发生任何关联的内存问题。

它还具有完整的 CSS 支持, 包括Jquery扩展。

第17个答案

对于Html5来说, html l5 lib 已经废弃多年了。我可以找到的唯一 HTML5 库与最近的更新和维护记录是html php , 它刚刚被带到测试版 1.0 刚刚超过一个星期。

第18个答案

我编写了一个通用的 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 回购: XmlExtractor

第19个答案

我创建了一个名为Phpowgetwits/dom 查询的库, 它允许您对 HTML5 和 xml 文档进行爬网, 就像您对 jquery 所做的那样。

在引擎盖下, 它使用Symfony\ domerwller将 css 选择器转换为xpath选择器。它始终使用相同的 DomDocument, 即使将一个对象传递给另一个对象时也是如此, 以确保良好的性能。


示例用法:

namespace PowerTools;

// Get file content
$htmlcode = file_get_contents('https://github.com');

// Define your DOMCrawler based on file string
$H = new DOM_Query($htmlcode);

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query($H->select('body'));

// Passing a string (CSS selector)
$s = $H->select('div.foo');

// Passing an element object (DOM Element)
$s = $H->select($documentBody);

// Passing a DOM Query object
$s = $H->select( $H->select('p + p'));

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
    return $i . " - " . $val->attr('class');
});

// Append the following HTML to all site blocks
$siteblocks->append('');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('');

[...]

支持的方法:

第20个答案

您可以尝试使用类似于Html Ti 一个小时的内容来清理任何 "损坏" 的 html, 并将 html 转换为 xhtml, 然后使用 xml 解析器进行解析。

第21个答案

您可以尝试的另一个选项是querypath。它的灵感来自 jQuery, 但在 PHP 中的服务器上, 在Drupal中使用。

第22个答案

XML_HTMLSax是相当稳定的-即使它不再保持。另一个选择可能是通过html Tidy 为您发送 html, 然后使用标准的 xml 工具对其进行分析。

第23个答案

Symfony框架具有可以分析 html 的捆绑包, 您可以使用 css 样式选择dom , 而不是使用xpath

第24个答案

处理 htmlxml DOM 的方法很多, 其中大多数已经提到。因此, 我不会尝试列出这些自己。

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

  • it 充分利用了基础 C 代码的性能优势
  • 它是 OO PHP (并允许我对其进行子类)
  • 它的水平相当低 (这允许我使用它作为一个非膨胀的基础更先进的行为)
  • 它提供了对 DOM 的每个部分的访问 (不像。SimpleXml, 它忽略了一些鲜为人知的 XML 功能)
  • 它具有用于 DOM 爬网的语法, 类似于本机 Javascript 中使用的语法。

虽然我错过了使用 CSS 选择器的能力 DOMDocument , 但有一种相当简单和方便的方法可以添加此功能: 将类似 js 的方法和方法子类进行子类化 DOMDocument querySelectorAll 并将其添加 querySelector 到子类中。

对于解析选择器, 我建议使用Symfony 框架中非常简约的cssel 分校组件。此组件只是将 CSS 选择器转换为 XPath 选择器, 然后可以将其输入到一个 DOMXpath 中, 以检索相应的 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, '') === 0) {
                $html5->loadHTML($data);
            } else {
                @$this->loadHTML('');
                $t = $html5->loadHTMLFragment($data);
                $docbody = $this->getElementsByTagName('body')->item(0);
                while ($t->hasChildNodes()) {
                    $docbody->appendChild($t->firstChild);
                }
            }
        }
    }

    [...]
}

另请参阅 Symfony 的创建者 Fabien Potencier使用 CSS 选择器分析 xml 文档, 了解他为 Symfony 创建 cssel 选定器组件的决定以及如何向您创建

第25个答案

使用Fluidxml , 您可以使用Xpathcss 选择器查询和迭代 xml。

$doc = fluidxml('...');

$title = $doc->query('//head/title')[0]->nodeValue;

$doc->query('//body/p', 'div.active', '#bgId')
        ->each(function($i, $node) {
            // $node is a DOMNode.
            $tag   = $node->nodeName;
            $text  = $node->nodeValue;
            $class = $node->getAttribute('class');
        });

https://github.com/servo-php/fluidxml

第26个答案

JSON 和来自 XML 的数组分为三行:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

塔达!

第27个答案

不通过正则表达式分析 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_]*)[^>]*>(.*?)#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/")));
第28个答案

我创建了一个名为 Html5ddom 文档的库, 可在https://github.com/ivopetkov/html5-dom-document-php免费使用

它也支持查询选择器, 我认为这对你的情况会非常有帮助。下面是一些示例代码:

$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('HelloThis is some text');
echo $dom->querySelector('h1')->innerHTML;
第29个答案

如果您熟悉 jQuery 选择器, 则可以使用Scarletsquery 进行 Php

selector('head meta[name="description"]')[0];

// Get 'content' attribute value from meta tag
print_r($description->attr('content'));

$description = $dom->selector('#Content p');

// Get element array
print_r($description->view);
第30个答案

解析 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 '';
echo $link=$feedItem->link;
echo '';
if($feedItem->description !='') {$des=$feedItem->description;} else {$des='';}
echo $des;
echo '';
if($i>5) break;
}

相关问题

mysql _ 拿给数组 ()/mysql_fetch_assoc ()/mysql_fetch_row ()/mysql_num_rows 等希望参数1是资源或结果 参考-此错误在 PHP 中意味着什么? 如何在 PHP 中分析和处理 HTML\ xml? 在 Scrollview 中向右对齐按钮? 了解 schematron 验证 PHP 分析/语法错误;以及如何解决这些问题? C: 如何将格式化文本文件中的大量数据读取到程序中? 如何限制来自文字新闻短代码的内容?