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

How do you parse and process HTML/XML in PHP?

提问人: 提问时间:8/27/2010 最后编辑:29 revs, 19 users 25%RobertPitt 更新时间:5/23/2022 访问量:474168

问:

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

php xml xml html解析

评论


答:

14赞 troelskn 11/16/2008 #1

XML_HTMLSax相当稳定 - 即使它不再维护。另一种选择是通过 Html Tidy 管道传输 HTML,然后使用标准 XML 工具对其进行解析。

92赞 Robert Elwell 11/16/2008 #2

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

simplehtmldom.sourceforge

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

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

18赞 CesarB 11/16/2008 #3

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

250赞 Edward Z. Yang 11/27/2008 #4

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

评论

20赞 Kornel 11/27/2008
真。它与 PHP 的内置 XPath 和 XSLTProcessor 类一起使用,它们非常适合提取内容。
8赞 Frank Farmer 10/13/2009
对于真正被破坏的 HTML,在将它交给 DOM 之前,你总是可以通过 htmltidy 运行它。 每当我需要从 HTML 中抓取数据时,我总是使用 DOM,或者至少使用 simplexml。
10赞 Husky 5/25/2010
加载格式错误的 HTML i 的另一件事是,调用 libxml_use_internal_errors(true) 以防止停止解析的警告可能是明智的。
6赞 Zero 9/19/2010
我已经使用 DOMDocument 解析了大约 1000 个 html 源代码(使用不同的字符集编码的各种语言),没有任何问题。您可能会遇到编码问题,但它们并非不可克服。您需要了解 3 件事:1) loadHTML 使用 meta 标记的字符集来确定编码 2) 如果 html 内容不包含此信息,#2 可能会导致不正确的编码检测 3) 错误的 UTF-8 字符可能会使解析器跳闸。在这种情况下,请使用 mb_detect_encoding() 和 Simplepie RSS 解析器的编码/转换/剥离错误的 UTF-8 字符代码的组合作为解决方法。
1赞 umpirsky 11/16/2010
是的,但是 DOMDocument 不支持 CSS 和 XPATH 查询,只支持 getElementById 或 getElementsByTagName?
345赞 Naveed 8/27/2010 #5

尝试简单的 HTML DOM 解析器

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

注意:顾名思义,它对于简单的任务很有用。它使用正则表达式而不是 HTML 解析器,因此对于更复杂的任务会慢得多。它的大部分代码库是在 2008 年编写的,从那时起只做了一些小的改进。它不遵循现代PHP编码标准,并且很难合并到符合PSR的现代项目中。

例子:

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

评论

9赞 RobertPitt 8/27/2010
首先,我需要准备一些事情,例如糟糕的 DOM、Invlid 代码,以及针对 DNSBL 引擎的 js 分析,这也将用于寻找恶意网站/内容,而且当我围绕我构建的框架构建我的网站时,它需要干净、可读且结构良好。SimpleDim 很棒,但代码有点混乱
9赞 Gordon 8/31/2010
@Robert您可能还想查看 htmlpurifier.org,了解与安全相关的内容。
3赞 Erik 9/18/2010
他有一个有效的观点:simpleHTMLDOM很难扩展,除非你使用装饰器模式,我觉得这很笨拙。我发现自己只是对基础类本身进行更改就不寒而栗
1赞 MB34 4/23/2012
我所做的是在将我的 html 发送到 SimpleDOM 之前将其整理好。
2赞 luke_mclachlan 4/7/2016
我目前正在使用它,将其作为项目的一部分运行以处理数百个 URL。它变得非常缓慢,并且定期超时仍然存在。这是一个很棒的初学者脚本,直观易学,但对于更高级的项目来说太基础了。
2008赞 Gordon 8/27/2010 #6

本机 XML 扩展

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

DOM

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

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

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

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

其他答案中提供了基本用法示例一般概念概述

XMLReader(XML管理器)

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

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

另一个答案中提供了基本用法示例

XML 解析器

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

XML 解析器库也基于 libxml,并实现了 SAX 样式的 XML 推送解析器。对于内存管理来说,它可能比 DOM 或 SimpleXML 更好,但比 XMLReader 实现的拉式解析器更难使用。

简单Xml

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

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

有一个基本的用法示例,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 文档使用 DOM。它需要来自 Symfony2 的 DomCrawler 用于遍历的组件 DOM 树,并通过添加操作 HTML 文档的 DOM 树。

php查询

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

这被描述为“废弃软件和错误:使用风险自负”,但似乎维护得很少。

laminas-dom

Laminas\Dom 组件(以前称为 Zend_DOM)提供了用于处理 DOM 文档和结构的工具。目前,我们提供 ,它提供了一个统一的接口,用于使用 XPath 和 CSS 选择器查询 DOM 文档。Laminas\Dom\Query

此软件包被视为功能完整,现在处于仅安全维护模式。

fDOMDocument

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

SABRE/XML

sabre/xml 是一个库,它包装并扩展了 XMLReader 和 XMLWriter 类,以创建简单的“xml 到对象/数组”映射系统和设计模式。写入和读取 XML 是单通道的,因此速度可能很快,并且对大型 xml 文件需要的内存不足。

流体XML

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 对象内存的功能。这些问题在嵌套循环中尤其严重。文档本身不准确且拼写错误,自 16 年 4 月 14 日以来没有对修复做出任何回应。


HTML 5的

您可以使用上述内容来解析 HTML5,但由于 HTML5 允许的标记,可能会有怪癖。因此,对于 HTML5,您可能需要考虑使用专用的解析器。请注意,这些是用PHP编写的,因此与低级语言的编译扩展相比,性能较慢,内存使用量增加。

HTML5Dom文档

HTML5DOMDocument 扩展了本机 DOMDocument 库。它修复了一些错误并添加了一些新功能。

  • 保留 html 实体(DOMDocument 不保留)
  • 保留 void 标记(DOMDocument 不保留)
  • 允许插入将正确部分移动到正确位置的 HTML 代码(头部元素插入头部,身体元素插入正文)
  • 允许使用 CSS 选择器查询 DOM(当前可用:、、、、*tagnametagname#id#idtagname.classname.classnametagname.classname.classname2.classname.classname2tagname[attribute-selector][attribute-selector]div, pdiv pdiv > pdiv + pp ~ ul
  • 添加对 element->classList 的支持。
  • 添加对 element->innerHTML 的支持。
  • 添加对 element->outerHTML 的支持。

HTML5的

HTML5 是一个完全用 PHP 编写的符合标准的 HTML5 解析器和编写器。它很稳定,在许多生产网站中使用,下载量超过 500 万次。

HTML5 提供以下功能。

  • HTML5 序列化程序
  • 支持 PHP 命名空间
  • Composer 支持
  • 基于事件(类似 SAX)的解析器
  • DOM 树构建器
  • 与 QueryPath 的互操作性
  • 在 PHP 5.3.0 或更高版本上运行

正则表达式

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

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

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

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

另请参阅解析 Html:克苏鲁之道


如果你想花点钱,可以看看

我不隶属于PHP Architect或作者。

评论

12赞 Gordon 8/27/2010
@Naveed这取决于您的需求。我不需要 CSS 选择器查询,这就是我专门将 DOM 与 XPath 一起使用的原因。phpQuery的目标是成为一个jQuery端口。Zend_Dom是轻量级的。你真的必须检查一下,看看你最喜欢哪一个。
3赞 Gordon 1/19/2011
@Ms2ger 大部分,但不是完全。如上所述,您可以使用基于 libxml 的解析器,但在特殊情况下,这些解析器会窒息。如果您需要最大的兼容性,最好使用专用的解析器。我宁愿保持这种区别。
10赞 Petah 2/27/2012
你不使用 PHP Simple HTML DOM Parser 的观点似乎没有意义。
4赞 Shiplu Mokaddim 3/29/2012
截至 2012 年 3 月 29 日,DOM 不支持 html5,XMLReader 不支持 HTML,最后一次提交 html5lib for PHP 是在 2009 年 9 月。用什么来解析 HTML5、HTML4 和 XHTML?
8赞 Gordon 4/28/2015
@Nasha 我故意将臭名昭著的 Zalgo 咆哮从上面的列表中排除,因为它本身并没有太大帮助,并且自编写以来就导致了相当多的货物崇拜。人们被这个链接打了一巴掌,无论正则表达式作为解决方案多么合适。如需更平衡的意见,请参阅我包含的链接,并浏览 stackoverflow.com/questions/4245008/ 的评论......
56赞 Joel Verhagen 8/27/2010 #7

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

评论

8赞 Bobby Jack 8/27/2010
不完全正确(en.wikipedia.org/wiki/Screen_scraping#Screen_scraping)。线索在“屏幕”中;在所描述的案例中,不涉及屏幕。虽然,不可否认,这个词最近遭受了很多滥用。
4赞 RobertPitt 8/27/2010
我不是屏幕抓取,将要解析的内容将由内容供应商根据我的协议授权。
58赞 3 revs, 3 users 53%Timo #8

对于 1a 和 2:我会投票给新的 Symfony Componet 类 DOMCrawler ( DomCrawler )。 此类允许类似于 CSS 选择器的查询。请看这个演示文稿,了解真实世界的例子:news-of-the-symfony2-world

该组件被设计为独立工作,可以在没有 Symfony 的情况下使用。

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

评论

0赞 Nikola Petkanski 5/13/2013
类似 jQuery 的 CSS 查询说得很好,因为 W3C 文档中缺少一些东西,但在 jQuery 中作为额外功能存在。
155赞 4 revs, 2 users 98%mario #9

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

首先,一个常见的用词不当:正则表达式不是用来解析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注释,但是有时HTML注释是更有用的提取锚点。特别是,伪 HTML 变体或 SGML 残基很容易用正则表达式驯服。<!--<$var>
  • 通常,正则表达式可以节省后处理。但是,HTML 实体通常需要手动处理。
  • 最后,对于极其简单的任务,例如提取 <img src= urls,它们实际上是一个可能的工具。与SGML/XML解析器相比,速度优势主要只适用于这些非常基本的提取过程。

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

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

评论

21赞 Gordon 9/6/2010
DOMComment 可以读取注释,因此没有理由为此使用正则表达式。
4赞 Alohci 9/6/2010
SGML 工具包和 XML 解析器都不适合解析真实世界的 HTML。为此,只有专用的 HTML 解析器才合适。
12赞 Gordon 9/6/2010
@Alohci DOM 使用 libxml,而 libxml 有一个单独的 HTML 解析器模块,该模块将在使用 loadHTML() 加载 HTML 时使用,因此它可以很好地加载“真实世界”(读取损坏的)HTML
6赞 ircmaxell 9/7/2010
好吧,只是对你的“现实世界考虑”立场的评论。当然,在解析 HTML 时,正则表达式有一些有用的情况。并且还有使用GOTO的有用情况。变量变量也有有用的情况。因此,没有一个特定的实现是明确的代码腐烂来使用它。但这是一个非常强烈的警告信号。而且,普通开发人员不太可能有足够的细微差别来区分。因此,作为一般规则,正则表达式 GOTO 和变量变量都是邪恶的。有非邪恶的用途,但这些都是例外(而且很少见)......(恕我直言)
11赞 tchrist 11/21/2010
@mario:实际上,HTML可以使用正则表达式进行“正确”解析,尽管通常需要几个正则表达式才能完成公平的工作。在一般情况下,这只是皇室的痛苦。在具有明确定义输入的特定情况下,它几乎是微不足道的。这些是人们应该使用正则表达式的情况。对于一般情况,大而老的、饥饿的重型解析器确实是你所需要的,尽管对于普通用户来说,并不总是清楚在哪里划线。无论哪种代码更简单、更容易,谁都赢了。
31赞 2 revs, 2 users 78%Amal Murali #10

使用 DOM 而不是字符串解析的 SimpleHtmlDom 的第三方替代品:phpQueryZend_DomQueryPathFluentDom

评论

3赞 Gordon 9/8/2010
如果您已经复制了我的评论,请至少将它们正确链接;)这应该是:建议的 SimpleHtmlDom 的第三方替代品,它们实际上使用 DOM 而不是字符串解析:phpQueryZend_DomQueryPathFluentDom
1赞 johnlemon 9/8/2010
好的答案是一个很好的来源。stackoverflow.com/questions/3606792/......
137赞 6 revs, 4 users 77%mario #11

请注意,此答案推荐的库现已废弃 10+ 年。

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

QueryPath 的示例

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

 $qp = qp("<html><body><h1>title</h1>..."); // 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");
 }

大多数情况下,您希望对 使用简单的 和 或 标签选择器。但您也可以使用 XPath 语句,这些语句有时更快。还有典型的jQuery方法,如和,特别是简化了提取正确的HTML片段。(并且已经解码了他们的SGML实体。#id.classDIV->find()->children()->text()->attr()

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

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

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

.

phpQuery 还是 QueryPath?

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

有关差异的更多信息,请参阅 tagbyte.org 的 wayback 机器上的比较。(原始来源丢失了,所以这里有一个互联网档案链接。是的,你仍然可以找到丢失的页面,人们。

优势

  • 简单可靠
  • 简单易用的替代品->find("a img, a object, div a")
  • 适当的数据转义(与正则表达式 grepping 相比)
37赞 Jens 4/15/2011 #12

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

63赞 Eli 5/1/2011 #13

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

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

18赞 Ric 5/31/2011 #14

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

44赞 jancha 10/4/2011 #15

我们之前已经为我们的需求创建了相当多的爬虫。归根结底,通常是简单的正则表达式做得最好。虽然上面列出的库是好的,因为它们是创建的原因,但如果你知道你在寻找什么,正则表达式是一种更安全的方法,因为你也可以处理无效的HTML/XHTML结构,如果通过大多数解析器加载,这些结构会失败。

12赞 Tuong Le 12/29/2011 #16

Symfony框架有可以解析HTML的bundle,你可以使用CSS样式来选择DOM,而不是使用XPath

27赞 Rafay 1/5/2012 #17

是的,您可以将simple_html_dom用于此目的。但是,我与simple_html_dom合作了很多,尤其是在网络抓取方面,发现它太脆弱了。它可以完成基本工作,但我无论如何都不会推荐它。

我从未使用过 curl 来达到这个目的,但我学到的是 curl 可以更有效地完成这项工作,并且更可靠。

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

评论

2赞 cHao 11/22/2012
curl 可以获取文件,但它不会为您解析 HTML。这是最难的部分。
24赞 Christopher Thomas 4/15/2012 #18

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

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

为了获得类似 jQuery 的行为,您需要在执行类似 Filter/Modify 的操作之前进行分支,这意味着它将更紧密地反映 jQuery 中发生的事情。

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

$results现在包含的结果集不是原始查询,这让我绊倒了很多,我发现 QueryPath 跟踪过滤器和查找以及修改结果并将其存储在对象中的所有内容。您需要改为执行此操作input[name='forename']"div p"

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

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

42赞 Greg 11/7/2012 #19

我推荐PHP简单HTML DOM解析器

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

foreach($html->find('img') as $element)
       echo $element->src . '<br>';
18赞 Paul Warelis #20

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

22赞 2 revs, 2 users 67%Reid Johnson #21

对于 HTML5,html5 lib 已经被废弃多年了。我能找到的唯一一个有最新更新和维护记录的 HTML5 库是 html5-php,它在一个多星期前刚刚发布到 beta 1.0。

10赞 2 revs, 2 users 86%Antonio Max #22

JSON和XML中的数组分为三行:

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

哒哒!

10赞 3 revs, 3 users 69%Daniel Loureiro #23

不通过正则表达式解析 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/")));
14赞 5 revsJohn Slegers #24

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

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

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

虽然我怀念使用 CSS 选择器的能力,但有一种相当简单方便的方法可以添加此功能:子类化并将类似 JS 的方法添加到您的子类中。DOMDocumentDOMDocumentquerySelectorAllquerySelector

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

然后,您可以使用这个(仍然非常低级)子类作为更高级类的基础,例如。解析非常特定类型的 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 的 Parsing XML documents with CSS selectors,了解他为 Symfony 创建 CssSelector 组件的决定以及如何使用它。

25赞 3 revs, 2 users 69%pguardiario #25

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

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

评论

0赞 ChrisJJ 11/17/2016
我从 Advanced Html Dom 中得到了很好的结果,我认为它应该在接受的答案中列出。对于任何依赖它的人来说,需要知道的一件重要事情是“这个项目的目标是成为 PHP 的简单 html dom 库的基于 DOM 的直接替代品......如果您使用 file/str_get_html,则无需更改任何内容。archive.is/QtSuj#selection-933.34-933.100 您可能需要对代码进行更改以适应一些不兼容问题。我在项目的 github 问题中注意到了四个已知的问题。github.com/monkeysuffrage/advanced_html_dom/issues
21赞 4 revs, 2 users 89%John Slegers #26

我创建了一个名为 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>');

[...]

支持的方法:


  1. 重命名为“select”,原因显而易见
  2. 重命名为“void”,因为“empty”是 PHP 中的保留字

注意:

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

评论

0赞 lithiumlab 10/17/2016
看起来是适合这项工作的工具,但在 Worpress 的 PHP 5.6.23 中没有为我加载。关于如何正确包含它的任何额外说明?包含: define(“BASE_PATH”, dirname(FILE));define(“LIBRARY_PATH”, BASE_PATH .DIRECTORY_SEPARATOR .'lib/vendor');需要LIBRARY_PATH。DIRECTORY_SEPARATOR .“加载程序.php”;加载器::init(array(LIBRARY_PATH, USER_PATH));在函数 .php 中
12赞 8 revs, 2 users 95%Daniele Orlando #27

借助 FluidXML,您可以使用 XPathCSS 选择器查询和迭代 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

5赞 Ivo Petkov #28

我创建了一个名为 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;
1赞 StefansArya #29

如果您熟悉 jQuery 选择器,则可以将 ScarletsQuery 用于 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 或标记属性上缺少引号。

3赞 2 revs, 2 users 70%user8031209 #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 '<br>';
  echo $link=$feedItem->link;
  echo '<br>';
  if($feedItem->description !='') {
    $des=$feedItem->description;
  } else {
    $des='';
  }
  echo $des;
  echo '<br>';
  if($i>5) break;
}
2赞 Muhammad Ali #31

有很多方法:

通常:

  • 原生XML扩展:它们与PHP捆绑在一起,通常比所有第三方库都快,并且为我提供了对标记所需的所有控制。

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

  • XML 读取器:XMLReader和DOM一样,都是基于libxml的。XMLReader 扩展是一个 XML 拉取解析器。读取器充当在文档流上前进的光标,并在途中的每个节点处停止

  • XML 解析器:此扩展允许您创建 XML 分析器,然后为不同的 XML 事件定义处理程序。每个 XML 解析器还具有一些可以调整的参数。它实现了 SAX 样式的 XML 推送解析器。

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

第三方库 [ 基于 libxml ]:

  • FluentDom - 存储库:FluentDOM 为 PHP 中的 DOMDocument 提供了一个类似 jQuery 的 fluent XML 接口。它可以加载 JSON、CSV、JsonML、RabbitFish 等格式。可以通过 Composer 安装。

  • HtmlPageDom:是一个PHP库,用于轻松操作HTML文档,它需要来自Symfony2组件的DomCrawler来遍历DOM树,并通过添加操作HTML文档的DOM树的方法来扩展它。

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

  • 查询路径:QueryPath 是一个用于操作 XML 和 HTML 的 PHP 库。它不仅可以处理本地文件,还可以处理 Web 服务和数据库资源。它实现了大部分 jQuery 接口(包括 CSS 样式的选择器),但它针对服务器端使用进行了大量调整。可以通过 Composer 安装。

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

  • Sabre/XML:sabre/xml 是一个库,它包装和扩展了 XMLReader 和 XMLWriter 类,以创建简单的“xml 到对象/数组”映射系统和设计模式。写入和读取 XML 是单通道的,因此速度可能很快,并且对大型 xml 文件需要的内存不足。

  • 流体XML:FluidXML 是一个 PHP 库,用于使用简洁流畅的 API 操作 XML。它利用 XPath 和流畅的编程模式来变得有趣和有效。

第三方库 [ 不基于 libxml ]:

  • PHP 简单 HTML DOM 解析器:用 PHP5+ 编写的 HTML DOM 解析器可让您以非常简单的方式操作 HTML,它需要 PHP 5+。还支持无效的 HTML。 它在一行中从 HTML 中提取内容。代码库很糟糕,而且工作速度非常慢。

  • PHP Html 解析器:HPHtmlParser 是一个简单、灵活的 HTML 解析器,它允许您使用任何 CSS 选择器(如 jQuery)选择标签。目标是帮助开发需要快速、简单的方法来抓取 HTML 的工具,无论它是否有效。它很慢,占用太多的 CPU 功率。

  • Ganon(推荐):通用分词器和 HTML/XML/RSS DOM 解析器。它具有操纵元素及其属性的能力。它支持无效的 HTML 和 UTF8。它可以对元素(如jQuery--支持命名空间)执行类似CSS3的高级查询。HTML 美化器(如 HTML Tidy)。缩小 CSS 和 Javascript。它对属性进行排序、更改字符大小写、更正缩进等。 扩展。这些操作分为更小的功能,以便于覆盖和快速且易于使用。

Web 服务:

  • 如果您不想编写 PHP 编程,也可以使用 Web 服务。ScraperWiki 的外部接口允许您以您想要的形式提取数据,以便在 Web 或您自己的应用程序中使用。您还可以提取有关任何抓取工具状态的信息。

我已经分享了所有资源,您可以根据自己的口味、实用性等进行选择。

评论

0赞 Muhammad Ali 10/20/2021
延伸阅读:newbedev.com/how-do-you-parse-and-process-html-xml-in-php