提问



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

最佳参考


原生XML扩展



我更喜欢使用其中一个本机XML扩展,因为它们与PHP捆绑在一起,通常比所有第三方库更快,并且给了我对标记所需的所有控制。[48]


DOM




  DOM扩展允许您通过PHP API使用PHP 5对XML文档进行操作。它是W3C的文档对象模型核心级别3的实现,这是一个平台和语言中立的接口,允许程序和脚本动态访问并更新文件的内容,结构和风格。[49]



DOM能够解析和修改现实世界(破碎)的HTML,并且可以执行XPath查询。它基于libxml。[50] [51]


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


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


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


的XMLReader




  XMLReader扩展是一个XML pull解析器。读取器在文档流上作为光标前进,并在途中停在每个节点上。 [55]



与DOM一样,XMLReader基于libxml。我不知道如何触发HTML分析器模块,因此使用XMLReader来分析损坏的HTML的可能性要小于使用DOM的可靠性,您可以明确告诉它使用libxml的HTML分析器模块。


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


XML Parser




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



XML Parser库也基于libxml,并实现了SAX样式的XML推送解析器。它可能是比DOM或SimpleXML更好的内存管理选择,但是比XMLReader实现的pull解析器更难以使用。[58]


的SimpleXML




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



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


一个基本的用法示例可以在一个简单的程序到CRUD节点和xml文件的节点值中找到,PHP手册中还有很多其他的例子。 [61]





第三方库(基于libxml)



如果您更喜欢使用第三方库,我建议使用实际上使用DOM/libxml而不是字符串解析的库。[62] [63]


FluentDom




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



HtmlPageDom




  Wa72 \\ HtmlPageDom`是一个易于操作HTML的PHP​​库
  使用它的文档需要来自Symfony2的DomCrawler
  遍历的组件
  DOM树并通过添加操作DOM的方法来扩展它
  HTML文档树。[65] [66]



phpQuery(多年未更新)




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



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


Zend_Dom




  Zend_Dom提供了处理DOM文档和结构的工具。目前,我们提供Zend_Dom_Query,它提供了一个统一的界面,用于使用XPath和CSS选择器查询DOM文档。 [69]



的QueryPath




  QueryPath是一个用于操作XML和HTML的PHP​​库。它不仅适用于本地文件,还适用于Web服务和数据库资源。它实现了大部分jQuery接口(包括CSS样式选择器),但它经过大量调整以供服务器端使用。可以通过Composer安装。[70]



fDOMDocument




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



军刀/XML




  saber/xml是一个包装和扩展XMLReader和XMLWriter类的库,用于创建一个简单的xml到对象/数组映射系统和设计模式。编写和读取XML是单遍的,因此可以很快并且需要在大型xml文件上使用低内存。[72]



FluidXML




  FluidXML是一个PHP库,用于通过简洁流畅的API来操作XML。
  它利用XPath和流畅的编程模式,既有趣又有效。[73]






第三方(不是基于libxml的)



构建DOM/libxml的好处是,您可以获得良好的开箱即用性能,因为您基于本机扩展。但是,并非所有第三方库都沿着这条路线行进。其中一些列在下面


PHP简单HTML DOM解析器




  

      
  • 用PHP5 +编写的HTML DOM解析器允许您以非常简单的方式操作HTML!

  •   
  • 需要PHP 5 +。

  •   
  • 支持无效的HTML。

  •   
  • 使用选择器在HTML页面上查找标签,就像jQuery一样。

  •   
  • 从一行中提取HTML中的内容。

  •   



我一般不推荐这个解析器。代码库很糟糕,解析器本身很慢而且内存很耗。并非所有jQuery选择器(例如子选择器)都是可能的。任何基于libxml的库都应该很容易胜过这个。[74] [75]


PHP Html Parser




  PHPHtmlParser是一个简单,灵活的html解析器,允许您使用任何css选择器(如jQuery)选择标签。目标是协助开发需要快速,简单的方法来废弃html的工具,无论它是否有效!这个项目是由sunra/php-simple-html-dom-parser原始支持但是支持似乎已停止,所以这个项目是我改编他以前的工作。[76]



同样,我不推荐这个解析器。 CPU使用率很高,速度相当慢。还没有清除已创建DOM对象的内存的功能。这些问题尤其适用于嵌套循环。文档本身不准确且拼写错误,自4月14日以来没有对修复的响应。


加农




  

      
  • 通用标记器和HTML/XML/RSS DOM解析器
      
      

        
    • 操纵元素及其属性的能力

    •   
    • 支持无效的HTML和UTF8

    •   

  •   
  • 可以对元素执行类似CSS3的高级查询(例如jQuery - 支持的命名空间)

  •   
  • HTML美化器(如HTML Tidy)
      
      

        
    • 缩小CSS和Javascript

    •   
    • 排序属性,更改字符大小写,更正缩进等。

    •   

  •   
  • 可扩展
      
      

        
    • 使用基于当前字符/令牌的回调解析文档

    •   
    • 以较小的功能分隔的操作,以便轻松覆盖

    •   

  •   
  • 快捷方式

  •   



从未使用过它。无法判断它是否有用。[77]





HTML 5



您可以使用上面的方法来解析HTML5,但由于HTML5允许的标记,可能存在怪癖。因此,对于HTML5,您要考虑使用专用解析器,如


html5lib [79]



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



HTML5最终确定后,我们可能会看到更多专用解析器。还有一篇由W3标题为如何进行html 5解析的博客文章,值得一试。[80]





Web服务



如果你不想编写PHP,你也可以使用Web服务。总的来说,我发现这些实用程序很少,但那只是我和我的用例。


YQL




  YQL Web服务使应用程序能够在Internet上查询,过滤和组合来自不同来源的数据。 YQL语句具有类似SQL的语法,对任何具有数据库经验的开发人员来说都很熟悉。[81]



ScraperWiki。




  ScraperWiki的外部界面允许您以您希望在Web或您自己的应用程序中使用的形式提取数据。您还可以提取有关任何刮刀状态的信息。[82]






正则表达式



最后和最少推荐,您可以使用正则表达式从HTML中提取数据。一般情况下,不建议在HTML上使用正则表达式。


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


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


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


另见Parsing Html The Cthulhu Way [85]





图书



如果你想花一些钱,看看吧



  • PHP架构师使用PHP进行Webscraping指南



我不隶属于PHP架构师或作者。[86]

其它参考1


尝试简单的HTML DOM解析器 [87]



  • 用PHP  5+编写的HTML DOM解析器,可让您以非常简单的方式操作HTML!

  • 需要PHP 5 +。

  • 支持无效的HTML。

  • 使用选择器在HTML页面上查找标签,就像jQuery一样。

  • 从一行中提取HTML中的内容。

  • 下载





实施例

[88] [89]


如何获取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;






Scraping 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);

其它参考2


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

其它参考3


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


首先,一个常见的误称:Regexp不适用于解析 HTML。但是,正则表达式可以提取数据。提取是他们的目的。正则表达式HTML提取优于正确的SGML工具包或基线XML解析器的主要缺点是它们的语法功能和不同的可靠性。


考虑制作一个有点可靠的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残留很容易用regexp来驯服

  • 正则表达式通常可以节省后期处理。但是,HTML实体通常需要手动处理。

  • 最后,对于e 非常简单的任务,例如提取< img src=urls,它们实际上是一个可能的工具。与SGML/XML解析器相比,速度优势通常只适用于这些非常基本的提取过程。



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


注意:我实际上有这个应用程序,我可以选择使用XML解析和正则表达式。就在上周,PyQuery解析破了,正则表达式仍然有效。是的很奇怪,我自己也无法解释。但事情就这样发生了
因此,请不要投票考虑现实世界的考虑因素,因为它与正则表达式=邪恶模因不匹配。 但是,我们也不要过多地投票。这只是这个话题的旁注。 [91]

其它参考4


phpQuery和QueryPath在复制流畅的jQuery API方面非常相似。这也是为什么他们在PHP中正确解析HTML的两种最简单的方法。[92] [93]


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()使用简单的#id.classDIV标签选择器。但您也可以使用XPath语句,有时速度更快。同样典型的jQuery方法,如->children()->text(),特别是->attr(),可以简化提取正确的HTML代码段。 (已经解码了他们的SGML实体。)[94]


 $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上的返回机器上的这种比较。 (原始来源丢失了,所以这里是一个互联网档案链接。是的,你仍然可以找到丢失的页面,人。)[95]


这是一个全面的QueryPath介绍。[96]


优点



  • 简单性和可靠性

  • 简单易用->find("a img, a object, div a")

  • 正确的数据转义(与正则表达式grepping相比)


其它参考5


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


simplehtmldom.sourceforge [97]


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


我已经在许多工具中使用它,在许多不同类型的网页上测试它,我认为它很有效。

其它参考6


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


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

其它参考7


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


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


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

其它参考8


顺便说一句,这通常被称为屏幕抓取。我用过的库是Simple HTML Dom Parser。[103]

其它参考9


我们之前已经为我们的需求创建了很多爬虫。在一天结束时,通常是简单的正则表达式来做最好的事情。虽然上面列出的库是好的,但是如果你知道你在寻找什么,正则表达式是一种更安全的方式,因为你也可以处理无效的HTML/XHTML结构,如果加载的话,它会失败通过大多数解析器。[104] [105]

其它参考10


我推荐PHP Simple HTML DOM Parser。[106]


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


foreach($html->find('img') as $element)
       echo $element->src . '<br>';

其它参考11


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

其它参考12


使用DOM而不是String解析的SimpleHtmlDom的第三方替代方案:phpQuery,Zend_Dom,QueryPath和FluentDom。[109] [110] [111] [112]

其它参考13


是的,你可以使用simple_html_dom来达到目的。但是我在simple_html_dom上做了很多工作,特别是对于网页报废,并且发现它太脆弱了。它完成了基本的工作,但我还是不推荐它。


我从来没有使用卷曲,但我学到的是卷曲可以更有效地完成工作并且更加坚固。


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

其它参考14


QueryPath 是好的,但要注意跟踪状态原因如果你没有意识到这意味着什么,它可能意味着你浪费了大量的调试时间试图找出发生了什么以及为什么代码不行。


这意味着结果集上的每个调用都会修改对象中的结果集,它不像jquery那样可链接,其中每个链接都是一个新集合,你有一个集合,它是查询和每个函数的结果调用修改该单个集合。


为了获得类似jquery的行为,你需要在进行过滤/修改之类的操作之前进行分支,这意味着它将更加接近地反映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不会被修改,你可以一次又一次地重复使用结果集,或许有更多知识的人可以清楚这一点,但它基本上就像我发现的那样。

其它参考15


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

其它参考16


对于HTML5,html5 lib已经被放弃多年了。该只有HTML5库,我可以找到最新的更新和维护记录是html5-php,这是一个多星期前刚刚带到beta 1.0。[115] [116]

其它参考17


Advanced Html Dom是一个简单的HTML DOM替代品,提供相同的界面,但它基于DOM,这意味着没有相关的内存问题发生。[117] [118]


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

其它参考18


我创建了一个名为 PHPPowertools/DOM-Query 的库,它允许您像使用jQuery一样抓取HTML5和XML文档。[120]


在幕后,它使用 symfony/DomCrawler 将CSS选择器转换为XPath选择器。即使将一个对象传递给另一个对象,它总是使用相同的DomDocument,以确保良好的性能。[121] [122]





使用示例:



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. 重命名为select,原因显而易见

  2. 重命名为void,因为empty是PHP中的保留字






注意:



该库还包含自己的零配置自动加载器,用于PSR-0兼容库。包含的示例应该开箱即用,无需任何其他配置。或者,您可以将它与作曲家一起使用。 [123] [124] [125] [126] [127] [128] [129] [130] [131] [132] [133] [134] [135] [136] [137] [138] [139] [140] [141] [142] [143] [144] [145] [146] [147] [148] [149] [150] [151] [152]

其它参考19


您可以尝试使用HTML Tidy之类的东西来清理任何损坏的HTML并将HTML转换为XHTML,然后您可以使用XML解析器进行解析。[153]

其它参考20


您可以尝试的另一个选项是QueryPath。它的灵感来自jQuery,但在PHP服务器上并用于Drupal。[154] [155] [156]

其它参考21


XML_HTMLSax相当稳定 - 即使它不再维护。另一种选择可能是通过Html Tidy管道HTML,然后使用标准XML工具解析它。[157] [158]

其它参考22


Symfony框架具有可以解析HTML的bundle,你可以使用CSS样式来选择DOM而不是使用XPath。[159] [160] [161]

其它参考23


有许多方法可以处理HTML/XML DOM,其中大多数已经提到过。因此,我不会尝试自己列出这些。


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



  • iit充分利用底层C代码的性能优势

  • 它是OO PHP(并允许我将其子类化)

  • 它的级别相当低(这使我可以将它用作更高级行为的非膨胀基础)

  • 它提供了对DOM的每个部分的访问(不像简单的SimpleXml,它忽略了一些鲜为人知的XML特性)。

  • 它有一个用于DOM抓取的语法,类似于原生Javascript中使用的语法。



虽然我错过了DOMDocument使用CSS选择器的能力,但是有一种相当简单方便的方法来添加这个特性:继承DOMDocument并添加类JS querySelectorAll和[[]] 46]]子类的方法。


为了解析选择器,我建议使用Symfony框架中非常简约的CssSelector组件。该组件只是将CSS选择器转换为XPath选择器,然后可以将其输入DOMXpath以检索相应的节点列表。[162] [163]


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


下面的代码直接来自我的DOM-Query库并使用我描述的技术。[164]


对于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组件以及如何使用它。[165]

其它参考24


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


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

其它参考25


有几个原因不能通过正则表达式解析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/")));

其它参考26


来自XML的JSON和数组有三行:


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


塔达!

其它参考27


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


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


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

其它参考28


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


<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或缺少引号。