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


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


1896
2017-08-26 17:19


起源




答案:


原生XML扩展

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

DOM

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

DOM能够解析和修改现实世界(破碎)的HTML,它可以做到 XPath查询。它基于 的libxml

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

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

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

XMLReader的

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

与DOM一样,XMLReader基于libxml。我不知道如何触发HTML Parser模块,因此使用XMLReader解析损坏的HTML的可能性可能不如使用DOM,因为您可以明确告诉它使用libxml的HTML Parser Module。

可以在以下位置找到基本用法示例 使用php从h1标签获取所有值

XML解析器

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

XML Parser库也基于libxml,并实现了一个 SAX style XML push parser。它可能是比DOM或SimpleXML更好的内存管理选择,但是比XMLReader实现的pull解析器更难以使用。

SimpleXML的

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

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

可以在以下位置找到基本用法示例 一个简单的CRUD节点程序和xml文件的节点值 并且有 PHP手册中的许多其他示例


第三方库(基于libxml)

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

FluentDom

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

HtmlPageDom

Wa72 \ HtmlPageDom`是一个易于操作HTML的PHP​​库   文件使用它需要 来自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

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

fDOMDocument

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

军刀/ XML

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

FluidXML

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


第三方(不是基于libxml的)

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

PHP简单的HTML DOM解析器

  • 用PHP5 +编写的HTML DOM解析器允许您以非常简单的方式操作HTML!
  • 需要PHP 5+。
  • 支持无效的HTML。
  • 使用选择器在HTML页面上查找标签,就像jQuery一样。
  • 从一行中提取HTML中的内容。

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

PHP Html解析器

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

同样,我不推荐这个解析器。 CPU使用率很高,速度相当慢。还没有清除已创建DOM对象的内存的功能。这些问题尤其适用于嵌套循环。文档本身不准确且拼写错误,自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标题为的博客文章 如何进行html 5解析 这值得一试。


网页服务

如果您不想编写PHP,也可以使用Web服务。一般来说,我发现这些实用程序的效用很小,但这只是我和我的用例。

YQL

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

ScraperWiki

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


常用表达

最后和 最不推荐的,您可以从HTML中提取数据 常用表达。通常,不鼓励在HTML上使用正则表达式。

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

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

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

另见 解析Html克苏鲁方式


图书

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

我不隶属于PHP Architect或作者。


1719
2017-08-26 17:18



@Naveed取决于您的需求。我不需要CSS Selector查询,这就是我将DOM与XPath一起使用的原因。 phpQuery旨在成为一个jQuery端口。 Zend_Dom很轻巧。你真的必须检查它们,看看你最喜欢哪一个。 - Gordon
你不使用PHP Simple HTML DOM Parser的观点似乎没有实际意义。 - Petah
截至2012年3月29日,DOM不支持html5,XMLReader不支持HTML,最后一次提交用于PHP的html5lib是在2009年9月。用什么来解析HTML5,HTML4和XHTML? - Shiplu Mokaddim
@Jimmy它没有包含任何关于cURL的内容,因为cURL不是用于解析和处理HTML / XML的工具。 cURL是各种网络协议的客户端。例如,您可以使用它获取网站。上面的大多数库都有直接加载远程URL的方法,因此您根本不需要cURL,例如DOM loadHTMLFile()。 - Gordon
@Nasha我故意将上面列表中臭名昭着的Zalgo咆哮排除在外,因为它对它本身并没有太大的帮助,并且自从写完之后导致了相当多的货物崇拜。无论正则表达式作为解决方案多么合适,人们都会被这个链接打倒。有关更平衡的意见,请参阅链接I. 没有 包括在内,并通过评论 stackoverflow.com/questions/4245008/... - Gordon


尝试 简单的HTML DOM解析器

  • 用PHP 5+编写的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 . '<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);

303
2017-11-26 20:02



首先,我需要准备的东西,如坏DOM,Invlid代码,js分析DNSBL引擎,这也将用于查找恶意网站/内容,也就像我已经建立我的网站围绕框架我已经建成它需要干净,可读,结构良好。 SimpleDim很棒,但代码有点凌乱 - RobertPitt
@Robert你可能也想看看 htmlpurifier.org 为安全相关的事情。 - Gordon
他有一个有效点:simpleHTMLDOM很难扩展,除非你使用装饰模式,我发现它很笨拙。我找到了自己 不寒而栗 只是对底层类本身进行更改。 - Erik
我做的是在将它发送到SimpleDOM之前通过整洁运行我的html。 - MB34
我目前正在使用它,将其作为处理几百个网址的项目的一部分运行。它变得非常缓慢并且定期超时持续存在。它是一个很棒的初学者脚本,直观易学,但对于更高级的项目来说太基础了。 - luke_mclachlan


只是用 上一层> loadHTML() 并完成它。 libxml的HTML解析算法非常好而且速度快,而且与普遍看法相反,它不会阻碍格式错误的HTML。


224
2017-11-15 22:16



真正。它适用于PHP的内置XPath和XSLTProcessor类,它们非常适合提取内容。 - Kornel
对于真正受损的HTML,您可以在将其交给DOM之前通过htmltidy运行它。每当我需要从HTML中抓取数据时,我总是使用DOM,或者至少使用simplexml。 - Frank Farmer
加载格式错误的HTML i的另一件事是调用libxml_use_internal_errors(true)来防止警告停止解析可能是明智之举。 - Husky
我使用DOMDocument来解析大约1000个html源代码(用不同的字符编码的各种语言)没有任何问题。您可能会遇到编码问题,但它们并非不可克服。您需要知道3件事:1)loadHTML使用元标记的字符集来确定编码2)如果html内容不包含此信息,#2可能导致不正确的编码检测3)坏的UTF-8字符可能会使解析器跳闸。在这种情况下,使用mb_detect_encoding()和Simplepie RSS Parser的编码/转换/剥离错误的UTF-8字符代码的组合来进行解决方法。 - Zero
DOM确实支持XPath,看一看 DOMXPath。 - Ryan McCue


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

首先,一个常见的误称:Regexps不适合 解析 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残留物很容易用正则表达式来驯服。
  • 通常,正则表达式可以节省后处理。但是,HTML实体通常需要手动管理。
  • 最后,对于e非常简单的任务 比如提取<img src = urls,它们实际上是一个可能的工具。与SGML / XML解析器相比,速度优势通常只适用于这些非常基本的提取过程。

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

注意: 我实际上有这个 应用,我在那里使用XML解析和正则表达式。就在上周,PyQuery解析破了,正则表达式仍然有效。是的很奇怪,我自己无法解释。但事情发生了。
因此,请不要将现实世界的考虑因素投反对票,因为它与正则表达式=邪恶的模因不符。 但是,我们也不要过多地投票。这只是本主题的旁注。


136
2018-05-01 02:04



DOMComment 可以阅读评论,所以没有理由使用正则表达式。 - Gordon
SGML工具包或XML解析器都不适合解析现实世界的HTML。为此,只有专用的HTML解析器才合适。 - Alohci
@Alohci DOM 使用 的libxml 和 libxml有一个单独的HTML解析器 加载HTML时将使用的模块 loadHTML() 所以它可以非常加载“真实世界”(读取破碎)HTML。 - Gordon
好吧,只是评论你的“现实世界的考虑”立场。当然,在解析HTML时,Regex有很多有用的情况。并且还有使用GOTO的有用情况。变量变量有很多有用的情况。因此,没有特定的实现是使用它的最终代码腐烂。但这是一个非常强烈的警告信号。平均开发人员不太可能有足够的细微差别来区分。因此,作为一般规则,正则表达式GOTO和变量变量都是邪恶的。有非恶意用途,但那些是例外(并且很少见)...(恕我直言) - ircmaxell
@mario:实际上,HTML 能够 使用正则表达式“正确”解析,尽管通常需要其中几个来完成一个公平的工作。在一般情况下,这只是一种皇室痛苦。在具有明确定义的输入的特定情况下,它接近于微不足道。那些是人的情况 应该 正在使用正则表达式。对于一般情况,大老饥饿的重型解析器确实是您所需要的,尽管偶然用户并不总是清楚在哪里绘制该线。无论哪种代码更简单,更容易,赢。 - tchrist


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");
 }

大多数情况下你想使用简单 #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")
  • 正确的数据转义(与正则表达式grepping相比)

126
2017-08-26 17:20





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

simplehtmldom.sourceforge

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

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


85
2017-10-04 13:14





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

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


58
2017-11-06 21:02





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

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

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


54
2018-04-14 19:08



类似于jquery的css查询很好说,因为在w3c文档中有一些东西缺失,但在jquery中作为额外的功能存在。 - Nikola Petkanski


这通常被称为 屏幕抓取, 顺便一提。我用过的库是 简单的HTML Dom Parser


51
2018-01-05 14:49



不完全正确(en.wikipedia.org/wiki/Screen_scraping#Screen_scraping)。线索在“屏幕”;在所描述的情况下,没有涉及屏幕。虽然,诚然,这个词最近遭受了很多滥用。 - Bobby Jack
我不是屏幕抓取,根据我的协议,将被解析的内容将由内容供应商授权。 - RobertPitt


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


40
2018-04-15 13:12