您如何在PHP中解析和处理HTML / XML?

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

RobertPitt asked 2019-11-15T07:37:04Z
30个解决方案
1853 votes

本机XML扩展

我更喜欢使用本机XML扩展之一,因为它们与PHP捆绑在一起,通常比所有第3方库都快,并为我提供了所需的所有标记控制权。

DOM

DOM扩展使您可以使用PHP 5通过DOM API通过XML文档进行操作。它是W3C的Document Object Model Core Level 3的实现,它是一种平台和语言无关的界面,允许程序和脚本动态访问和更新。 文件的内容,结构和样式。

DOM能够解析和修改实际(损坏的)HTML,并且可以执行XPath查询。 它基于libxml。

使用DOM需要花一些时间,但是IMO值得花时间。 由于DOM是与语言无关的接口,因此您会找到许多语言的实现,因此,如果需要更改编程语言,那么您很可能已经知道如何使用该语言的DOM API。

可以在Grabbing A元素的href属性中找到一个基本的用法示例,并且可以在php的DOMDocument中找到一个一般的概念概述。

StackOverflow上已广泛讨论了如何使用DOM扩展,因此,如果您选择使用它,则可以确保可以通过搜索/浏览Stack Overflow来解决所遇到的大多数问题。

XMLReader

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

与DOM一样,XMLReader也基于libxml。 我不知道如何触发HTML解析器模块,因此使用XMLReader解析损坏的HTML的机会可能不如使用DOM健壮,因为在DOM中您可以明确地告诉它使用libxml的HTML解析器模块。

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

XML解析器

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

XML解析器库也基于libxml,并实现了SAX样式的XML推送解析器。 与DOM或SimpleXML相比,内存管理可能是更好的选择,但与XMLReader实现的请求解析器相比,使用起来更加困难。

SimpleXml

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

当您知道HTML是有效的XHTML时,可以选择SimpleXML。 如果您需要解析损坏的HTML,甚至不用考虑SimpleXml,因为它会阻塞。

一个简单的程序可以找到CRUD节点和xml文件的节点值,并在PHP手册中有很多其他示例。


第三方库(基于libxml)

如果您更喜欢使用第三方库,则建议使用实际上在下面使用DOM / libxml的库,而不是字符串解析。

FluentDom-回购

FluentDOM为PHP中的DOMDocument提供了类似jQuery的Fluent XML接口。 选择器以XPath或CSS编写(使用CSS到XPath转换器)。 当前版本扩展了DOM的实现标准接口,并增加了DOM Living Standard的功能。 FluentDOM可以加载JSON,CSV,JsonML,RabbitFish等格式。 可以通过Composer安装。

HtmlPageDom

Wa72 \ HtmlPageDom`是一个PHP库,可轻松操作HTML   使用It的文档需要Symfony2的DomCrawler   用于遍历的组件   DOM树并通过添加操作DOM的方法对其进行扩展   HTML文档树。

phpQuery(多年未更新)

phpQuery是服务器端可链接的CSS3选择器驱动的文档对象模型(DOM)API,它基于用PHP5编写的jQuery JavaScript库,并提供了附加的命令行界面(CLI)。

另请参见:[https://github.com/electrolinux/phpquery]

Zend_Dom

Zend_Dom提供了用于处理DOM文档和结构的工具。 当前,我们提供Zend_Dom_Query,它提供了一个统一的接口,用于同时使用XPath和CSS选择器查询DOM文档。

查询路径

QueryPath是一个用于处理XML和HTML的PHP库。 它不仅可以与本地文件一起使用,还可以与Web服务和数据库资源一起使用。 它实现了许多jQuery接口(包括CSS样式的选择器),但为服务器端使用做了很大的调整。 可以通过Composer安装。

fDOMDocument

fDOMDocument扩展了标准DOM以在所有错误情况下都使用异常,而不是PHP警告或通知。 它们还添加了各种自定义方法和快捷方式,以方便使用并简化DOM的使用。

军刀/ XML

sabre / xml是一个包装和扩展XMLReader和XMLWriter类的库,以创建简单的“从XML到对象/数组”的映射系统和设计模式。 写入和读取XML是单次通过,因此可以快速进行,并且在大型xml文件上所需的内存较少。

FluidXML

FluidXML是一个PHP库,用于使用简洁流畅的API来处理XML。   它利用XPath和流畅的编程模式来使游戏变得有趣而有效。


第三方(不是基于libxml的)

在DOM / libxml上构建的好处是,由于您基于本机扩展,因此可以立即获得良好的性能。 但是,并非所有第3方库都遵循这条路线。 下面列出其中一些

PHP简单HTML DOM解析器

  • 用PHP5 +编写的HTML DOM解析器使您可以非常简单地操作HTML!
  • 需要PHP 5+。
  • 支持无效的HTML。
  • 使用jQuery之类的选择器在HTML页面上查找标签。
  • 从HTML中提取内容。

我通常不建议使用此解析器。 代码库太可怕了,解析器本身也很慢并且占用大量内存。 并非所有的jQuery选择器(例如子选择器)都是可行的。 任何基于libxml的库都应轻而易举地胜过它。

PHP HTML解析器

PHPHtmlParser是一个简单,灵活的html解析器,它使您可以使用任何CSS选择器(如jQuery)来选择标签。 目标是协助开发工具,这些工具需要快速,简便的方式来废弃html,无论它是否有效! 该项目最初由sunra / php-simple-html-dom-parser支持,但支持似乎已停止,因此该项目是我对他先前工作的改编。

同样,我不建议使用此解析器。 CPU使用率很高时,速度相当慢。 也没有清除创建的DOM对象的内存的功能。 这些问题在嵌套循环中尤为严重。 文档本身不准确且拼写错误,自16年4月14日以来未对修复程序做出任何回应。

加农

  • 通用标记器和HTML / XML / RSS DOM解析器
    • 能够操纵元素及其属性
    • 支持无效的HTML和UTF8
  • 可以对元素执行类似CSS3的高级查询(例如jQuery-支持名称空间)
  • HTML美化器(如HTML Tidy)
    • 缩小CSS和Javascript
    • 排序属性,更改字符大小写,正确缩进等
  • 可扩展的
    • 使用基于当前字符/令牌的回调解析文档
    • 将操作分成较小的功能,以便于覆盖
  • 快速简便

没用过。 无法判断是否有好处。


HTML 5

您可以使用上面的代码来解析HTML5,但是由于HTML5允许标记,因此可能会有一些古怪之处。 因此,对于HTML5,您需要考虑使用专用的解析器,例如

html5lib

基于WHATWG HTML5规范的HTML解析器的Python和PHP实现,以实现与主要桌面Web浏览器的最大兼容性。

HTML5完成后,我们可能会看到更多专用的解析器。 W3上还有一个博客文章,标题为How-To,用于html 5解析,值得一试。


网页服务

如果您不想编写PHP,也可以使用Web服务。 通常,我发现这些工具的实用性很小,但这就是我和我的用例。

ScraperWiki。

ScraperWiki的外部接口允许您以想要在Web或您自己的应用程序中使用的形式提取数据。 您还可以提取有关任何刮板状态的信息。


常用表达

最后也是最不推荐的方法是,您可以使用正则表达式从HTML提取数据。 通常不建议在HTML上使用正则表达式。

您可以在网络上找到与标记匹配的大多数代码片段。 在大多数情况下,它们仅适用于非常特殊的HTML。 微小的标记更改(例如在某处添加空格,在标签中添加或更改标签中的属性)会使RegEx在编写不正确时失败。 在HTML上使用RegEx之前,您应该知道自己在做什么。

HTML解析器已经知道HTML的语法规则。 必须为您编写的每个新RegEx教授正则表达式。 RegEx在某些情况下还可以,但实际上取决于您的用例。

您可以编写更可靠的解析器,但是当上述库已经存在并且在此方面做得更好时,编写具有正则表达式的完整且可靠的自定义解析器会浪费时间。

另请参阅解析Cthulhu方式的HTML


图书

如果你想花一些钱,看看

  • PHP建筑师使用PHP进行网络爬取的指南

我不隶属于PHP Architect或作者。

Gordon answered 2019-11-15T07:46:55Z
319 votes

尝试简单HTML DOM解析器

  • 用PHP 5+编写的HTML DOM解析器,可让您以非常简单的方式操作HTML!
  • 需要PHP 5+。
  • 支持无效的HTML。
  • 使用jQuery之类的选择器在HTML页面上查找标签。
  • 从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 . '<br>';

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


如何修改HTML元素:

// Create DOM from string
$html = str_get_html('<div id="hello">Hello</div><div id="world">World</div>');

$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;


刮Slashdot:

// 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);
Naveed answered 2019-11-15T07:48:06Z
232 votes

只需使用DOMDocument-> loadHTML()即可完成。 libxml的HTML解析算法非常好且快速,并且与流行的看法相反,它不会阻止格式错误的HTML。

Edward Z. Yang answered 2019-11-15T07:48:31Z
146 votes

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

首先,一个常见的误称:正则表达式不是用于“解析” 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注释/<!--CONTENT-->(.+?)<!--END-->/,但是注释有时对于提取更为有用。 特别是伪HTML变体<$var>或SGML残基很容易与正则表达式配合。
  • 通常,正则表达式可以节省后期处理。 但是,HTML实体通常需要手动维护。
  • 最后,对于提取<img src = url之类的极其简单的任务,它们实际上是一种可能的工具。 相对于SGML / XML解析器的速度优势主要体现在这些非常基本的提取过程中。

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

注意:我实际上有这个应用程序,在这里我可以选择使用XML解析和正则表达式。 就在上周,PyQuery解析中断,并且正则表达式仍然有效。 是的,很奇怪,我自己也无法解释。 但是,它发生了。
因此,请勿仅仅因为它与regex = evil meme不匹配而否决现实世界中的考虑因素。 但是,我们也不要对此投票太多。 这只是该主题的旁注。

mario answered 2019-11-15T07:50:03Z
130 votes

phpQuery和QueryPath在复制流畅的jQuery API方面极为相似。 这就是为什么它们是在PHP中正确解析HTML的两种最简单方法。

QueryPath的示例

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

 $qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL

结果对象包含HTML文档的完整树形表示。 可以使用DOM方法遍历它。 但是常见的方法是像在jQuery中一样使用CSS选择器:

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

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

通常,您希望为->find()使用简单的->find("a img, a object, div a")->writeHTMLDIV标记选择器。但是您也可以使用XPath语句,这有时会更快。 同样,典型的jQuery方法(如->children()->text(),尤其是->attr())也简化了提取正确的HTML代码段的过程。 (并且已经对其SGML实体进行了解码。)

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

QueryPath还允许将新标签注入到流中(->find("a img, a object, div a")),然后输出并美化更新的文档(->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")
  • 正确的数据转义(与正则表达式grepping相比)
mario answered 2019-11-15T07:51:57Z
87 votes

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

simplehtmldom.sourceforge

它以面向对象的方式处理DOM元素,新的迭代涵盖了很多不兼容的代码。 还有一些很棒的功能,如您在JavaScript中看到的那样,例如“ find”功能,该功能将返回该标记名称的元素的所有实例。

我已经在许多工具中使用了此工具,并在许多不同类型的网页上对其进行了测试,并且我认为它的效果很好。

Robert Elwell answered 2019-11-15T07:52:44Z
59 votes

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

但是对于您的特定问题,您应该看一下这个项目:[http://fivefilters.org/content-only/]-这是Readability算法的修改版本,旨在仅提取文本内容( 而不是页眉和页脚)。

Eli answered 2019-11-15T07:53:21Z
55 votes

对于1a和2:我将投票支持新的Symfony Componet类DOMCrawler(DomCrawler)。此类允许类似于CSS选择器的查询。 看看这个演示,了解真实的例子:symfony2世界新闻。

该组件旨在独立运行,可以在不使用Symfony的情况下使用。

唯一的缺点是它仅适用于PHP 5.3或更高版本。

Timo answered 2019-11-15T07:54:00Z
52 votes

顺便说一句,这通常称为屏幕抓取。 我用于此的库是Simple HTML Dom Parser。

Joel Verhagen answered 2019-11-15T07:54:27Z
41 votes

以前,我们已经为我们的需求创建了许多爬虫。 归根结底,通常最简单的正则表达式可以做到最好。 尽管上面列出的库因其创建的原因而很有用,但是如果您知道要查找的内容,则正则表达式是一种更安全的方法,因为您还可以处理无效的HTML / XHTML结构,如果加载它们会失败 通过大多数解析器。

jancha answered 2019-11-15T07:54:53Z
38 votes

我建议使用PHP简单HTML DOM解析器。

它确实具有不错的功能,例如:

foreach($html->find('img') as $element)
       echo $element->src . '<br>';
Greg answered 2019-11-15T07:55:26Z
36 votes

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

Jens answered 2019-11-15T07:55:54Z
29 votes

使用DOM而不是字符串解析的SimpleHtmlDom的第三方替代产品:phpQuery,Zend_Dom,QueryPath和FluentDom。

Amal Murali answered 2019-11-15T07:56:22Z
24 votes

是的,您可以为此使用simple_html_dom。 但是,我已经对simple_html_dom进行了大量工作,尤其是对于Web抓取,并且发现它过于脆弱。 它可以完成基本工作,但我还是不会推荐它。

我从来没有使用过curl来达到目的,但是我了解到curl可以更有效地完成工作,并且更加牢固。

请查看此链接:scraping-websites-with-curl

Rafay answered 2019-11-15T07:57:02Z
23 votes

QueryPath很好,但是要小心“跟踪状态”,因为如果您没有意识到这意味着什么,那可能意味着您浪费了大量的调试时间来试图找出发生了什么以及代码为什么不起作用。

这意味着对结果集的每次调用都会修改对象中的结果集,这与jquery中的可链接性不同,jquery中的每个链接都是一个新集合,您只有一个集合,这是查询的结果,每个函数调用都会对其进行修改 那一套。

为了获得类似jquery的行为,您需要在执行类似filter / modify的操作之前进行分支,这意味着它将更紧密地反映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将不会被修改,并且您可以一次又一次地重用结果集,也许某个有更多知识的人可以将其清除一些,但是从我发现的结果来看,基本上是这样的。

Christopher Thomas answered 2019-11-15T07:57:59Z
19 votes

Advanced Html Dom是提供相同接口的简单HTML DOM替换,但是它基于DOM,这意味着不会发生任何相关的内存问题。

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

pguardiario answered 2019-11-15T07:58:33Z
18 votes

对于HTML5,html5库已被放弃多年。 我可以找到的唯一具有最近更新和维护记录的HTML5库是html5-php,它是在一周多前才发布到beta 1.0的。

Reid Johnson answered 2019-11-15T07:58:59Z
17 votes

我写了一个通用的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

Paul Warelis answered 2019-11-15T07:59:35Z
17 votes

我创建了一个名为PHPPowertools / DOM-Query的库,该库使您可以像使用jQuery一样对HTML5和XML文档进行爬网。

在后台,它使用symfony / DomCrawler将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('<div class="site-center"></div>');

// 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('<section><div class="footer-wrapper"></div></section>');

[...]

支持的方法:

  • [x] $(1)
  • [x] $ .parseHTML
  • [x] $ .parseXML
  • [x] $ .parseJSON
  • [x] $ selection.add
  • [x] $ selection.addClass
  • [x] $ selection.after
  • [x] $ selection.append
  • [x] $ selection.attr
  • [x] $ selection.before
  • [x] $ selection.children
  • [x] $ selection.closest
  • [x] $ selection.contents
  • [x] $ selection.detach
  • [x] $ selection.each
  • [x] $ selection.eq
  • [x] $ selection.empty(2)
  • [x] $ selection.find
  • [x] $ selection.first
  • [x] $ selection.get
  • [x] $ selection.insertAfter
  • [x] $ selection.insertBefore
  • [x] $ selection.last
  • [x] $ selection.parent
  • [x] $ selection.parents
  • [x] $ selection.remove
  • [x] $ selection.removeAttr
  • [x] $ selection.removeClass
  • [x] $ selection.text
  • [x] $ selection.wrap

  1. 由于明显的原因,将其重命名为“选择”
  2. 重命名为“ void”,因为“ empty”是PHP中的保留字

注意 :

该库还包括用于PSR-0兼容库的自己的零配置自动加载器。 包含的示例无需任何其他配置即可直接使用。 或者,您可以将其与作曲家一起使用。

John Slegers answered 2019-11-15T08:04:10Z
15 votes

您可以尝试使用HTML Tidy之类的东西来清理所有“损坏的” HTML,并将HTML转换为XHTML,然后可以使用XML解析器进行解析。

CesarB answered 2019-11-15T08:04:37Z
15 votes

您可以尝试的另一种选择是QueryPath。 它受jQuery的启发,但在PHP的服务器上使用,并在Drupal中使用。

Richard Le Poidevin answered 2019-11-15T08:05:05Z
12 votes

XML_HTMLSax非常稳定-即使不再维护。 另一种选择是通过HTML Tidy通过HTML传递HTML,然后使用标准XML工具对其进行解析。

troelskn answered 2019-11-15T08:05:32Z
11 votes

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

Tuong Le answered 2019-11-15T08:05:59Z
11 votes

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

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

  • iit充分利用了基础C代码的性能优势
  • 它是OO PHP(并允许我对其进行子类化)
  • 它的级别很低(这使我可以将其用作更高级行为的非膨胀基础)
  • 它提供对DOM各个部分的访问(与SimpleXml不同,例如SimpleXml会忽略一些鲜为人知的XML功能)
  • 它具有用于DOM爬网的语法,该语法类似于本机Javascript中使用的语法。

而且,尽管我错过了为DOMXpath使用CSS选择器的能力,但是有一种相当简单方便的方法来添加此功能:子类化DOMDocument并将子类JS类querySelectorAllquerySelector添加到您的子类中。

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

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

下面的代码直接给出了我的DOM-Query库,并使用了我描述的技术。

对于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决定使用CSS选择器解析XML文档,有关他决定为Symfony创建CssSelector组件以及如何使用它。

John Slegers answered 2019-11-15T08:07:48Z
9 votes

使用FluidXML,您可以使用XPath和CSS选择器查询和迭代XML。

$doc = fluidxml('<html>...</html>');

$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]

Daniele Orlando answered 2019-11-15T08:08:27Z
7 votes

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

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

da!

Antonio Max answered 2019-11-15T08:08:57Z
7 votes

不使用正则表达式解析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/")));
Daniel Loureiro answered 2019-11-15T08:09:33Z
2 votes

我创建了一个名为HTML5DOMDocument的库,该库可从[https://github.com/ivopetkov/html5-dom-document-php]免费获得。

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

$dom = new IvoPetkov\HTML5DOMDocument();
$dom->loadHTML('<!DOCTYPE html><html><body><h1>Hello</h1><div class="content">This is some text</div></body></html>');
echo $dom->querySelector('h1')->innerHTML;
Ivo Petkov answered 2019-11-15T08:10:09Z
0 votes

如果您熟悉jQuery选择器,则可以使用ScarletsQuery for PHP

<pre><?php
include "ScarletsQuery.php";

// Load the HTML content and parse it
$html = file_get_contents('https://www.lipsum.com');
$dom = Scarlets\Library\MarkupLanguage::parseText($html);

// Select meta tag on the HTML header
$description = $dom->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);

该库通常需要不到1秒的时间来处理脱机html。
它还接受无效的HTML或标记属性上缺少引号。

StefansArya answered 2019-11-15T08:10:51Z
0 votes

解析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;
}
user8031209 answered 2019-11-15T08:11:19Z
translate from https://stackoverflow.com:/questions/3650125/how-to-parse-html-with-php