Gor*_*don 1861
我更喜欢使用其中一个原生XML扩展,因为它们与PHP捆绑在一起,通常比所有第三方库更快,并且给了我对标记所需的所有控制权.
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扩展是一个XML pull解析器.读取器在文档流上作为光标前进,并在途中停在每个节点上.
与DOM一样,XMLReader基于libxml.我不知道如何触发HTML解析器模块,因此使用XMLReader解析损坏的HTML的可能性可能不如使用DOM,因为您可以明确告诉它使用libxml的HTML解析器模块.
使用php从h1标签获取所有值时,可以找到一个基本用法示例
此扩展允许您创建XML解析器,然后为不同的XML事件定义处理程序.每个XML解析器还有一些您可以调整的参数.
XML Parser库也基于libxml,并实现了SAX样式的XML推送解析器.它可能是比DOM或SimpleXML更好的内存管理选择,但是比XMLReader实现的pull解析器更难以使用.
SimpleXML扩展提供了一个非常简单且易于使用的工具集,用于将XML转换为可以使用普通属性选择器和数组迭代器处理的对象.
当您知道HTML是有效的XHTML时,SimpleXML是一个选项.如果你需要解析破碎的HTML,甚至不要考虑SimpleXml,因为它会窒息.
一个基本的用法示例可以在一个简单的CRUD节点程序和xml文件的节点值中找到,PHP手册中还有很多其他的例子.
如果您更喜欢使用第三方库,我建议使用实际上使用DOM/libxml而不是字符串解析的库.
FluentDOM为PHP中的DOMDocument提供了类似jQuery的流畅XML接口.选择器是用XPath或CSS编写的(使用CSS到XPath转换器).当前版本扩展了DOM实现标准接口并添加了DOM Living Standard的功能.FluentDOM可以加载JSON,CSV,JsonML,RabbitFish等格式.可以通过Composer安装.
Wa72\HtmlPageDom`是一个用于轻松操作HTML文档的PHP库.它需要来自Symfony2组件的DomCrawler来遍历DOM树,并通过添加操作HTML文档的DOM树的方法来扩展它.
phpQuery是一个服务器端,可链接,CSS3选择器驱动的文档对象模型(DOM)API,基于用PHP5编写的jQuery JavaScript库,并提供额外的命令行界面(CLI).
另见:https://github.com/electrolinux/phpquery
Zend_Dom提供了处理DOM文档和结构的工具.目前,我们提供Zend_Dom_Query,它提供了一个统一的界面,用于使用XPath和CSS选择器查询DOM文档.
QueryPath是一个用于操作XML和HTML的PHP库.它不仅适用于本地文件,还适用于Web服务和数据库资源.它实现了许多jQuery接口(包括CSS样式的选择器),但它在服务器端使用时经过了大量调整.可以通过Composer安装.
fDOMDocument扩展了标准DOM,以便在所有错误情况下使用异常,而不是PHP警告或通知.为方便起见,他们还添加了各种自定义方法和快捷方式,并简化了DOM的使用.
saber/xml是一个包装和扩展XMLReader和XMLWriter类的库,用于创建一个简单的"xml到对象/数组"映射系统和设计模式.编写和读取XML是单遍的,因此可以快速并且需要大型xml文件的低内存.
FluidXML是一个用于使用简洁流畅的API来操作XML的PHP库.它利用XPath和流畅的编程模式,既有趣又有效.
构建DOM/libxml的好处是,您可以获得良好的开箱即用性能,因为您基于本机扩展.但是,并非所有第三方库都沿着这条路走下去.其中一些列在下面
- 用PHP5 +编写的HTML DOM解析器允许您以非常简单的方式操作HTML!
- 需要PHP 5+.
- 支持无效的HTML.
- 使用选择器在HTML页面上查找标签,就像jQuery一样.
- 从一行中提取HTML中的内容.
我一般不推荐这个解析器.代码库很糟糕,解析器本身很慢而且内存很耗.并非所有jQuery选择器(例如子选择器)都是可能的.任何基于libxml的库都应该比这更容易.
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
- 排序属性,更改字符大小写,更正缩进等.
- 扩展
- 使用基于当前字符/标记的回调解析文档
- 操作以较小的功能分隔,以便轻松覆盖
- 快速而简单
从未使用过它.不知道它是否有用.
您可以使用上面的内容来解析HTML5,但由于HTML5允许的标记,可能会有怪癖.因此,对于HTML5,您要考虑使用专用解析器,例如
基于WHATWG HTML5规范的HTML解析器的Python和PHP实现,可与主要桌面Web浏览器实现最大兼容性.
HTML5最终确定后,我们可能会看到更多专用解析器.还有一个W3的博客文章,名为How-To for html 5 parsing,值得一试.
如果您不想编写PHP,您也可以使用Web服务.一般来说,我发现这些实用程序很少,但那只是我和我的用例.
ScraperWiki的外部界面允许您以您希望在Web或您自己的应用程序中使用的形式提取数据.您还可以提取有关任何刮刀状态的信息.
最后也是最不推荐的,您可以使用正则表达式从HTML中提取数据.通常,不鼓励在HTML上使用正则表达式.
您可以在网上找到与标记相匹配的大多数片段都很脆弱.在大多数情况下,它们只适用于非常特殊的HTML.微小的标记更改,例如在某处添加空格,或添加或更改标记中的属性,可以使RegEx在未正确编写时失败.在HTML上使用RegEx之前,您应该知道自己在做什么.
HTML解析器已经知道HTML的语法规则.必须为您编写的每个新RegEx讲授正则表达式.RegEx在某些情况下很好,但它实际上取决于您的用例.
您可以编写更可靠的解析器,但是使用正则表达式编写完整可靠的自定义解析器是浪费时间,因为上述库已经存在并且在此方面做得更好.
另见Parsing Html The Cthulhu Way
如果你想花一些钱,看看吧
我不隶属于PHP Architect或作者.
Nav*_*eed 321
// 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>';
Run Code Online (Sandbox Code Playgroud)
// 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;
Run Code Online (Sandbox Code Playgroud)
// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;
Run Code Online (Sandbox Code Playgroud)
// 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);
Run Code Online (Sandbox Code Playgroud)
Edw*_*ang 233
只需使用DOMDocument-> loadHTML()并完成它.libxml的HTML解析算法非常好而且快速,与普遍看法相反,不会阻止格式错误的HTML.
mar*_*rio 147
为什么你不应该和何时应该使用正则表达式?
首先,一个常见的误称:Regexp不是用于" 解析 " HTML.但是,正则表达式可以" 提取 "数据.提取就是他们的目标.通过适当的SGML工具包或基线XML解析器进行正则表达式HTML提取的主要缺点是它们的语法功能和不同的可靠性.
考虑制作一个有点可靠的HTML提取正则表达式:
<a\s+class="?playbutton\d?[^>]+id="(\d+)".+? <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?
Run Code Online (Sandbox Code Playgroud)
比简单的phpQuery或QueryPath等价物更不易读:
$div->find(".stationcool a")->attr("title");
Run Code Online (Sandbox Code Playgroud)
但是有一些具体的用例,他们可以提供帮助.
<!--,但有时它们是提取的更有用的锚点.特别是伪HTML变体<$var>或SGML残留很容易用正则表达式来驯服.有时甚至建议使用正则表达式预提取HTML片段,/<!--CONTENT-->(.+?)<!--END-->/并使用更简单的HTML解析器前端处理剩余部分.
注意:我实际上有这个应用程序,我在其中使用XML解析和正则表达式.就在上周,PyQuery解析破了,正则表达式仍然有效.是的很奇怪,我自己无法解释.但事情发生了.
因此,请不要投票考虑现实世界的考虑因素,因为它与正则表达式=邪恶的模因不符.但是,我们也不要过多地投票.这只是本主题的旁注.
mar*_*rio 131
phpQuery和QueryPath在复制流畅的jQuery API方面非常相似.这也是为什么它们是在PHP中正确解析HTML的两种最简单的方法.
QueryPath的示例
基本上,您首先从HTML字符串创建可查询的DOM树:
$qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL
Run Code Online (Sandbox Code Playgroud)
生成的对象包含HTML文档的完整树表示.它可以使用DOM方法遍历.但常见的方法是使用jQuery中的CSS选择器:
$qp->find("div.classname")->children()->...;
foreach ($qp->find("p img") as $img) {
print qp($img)->attr("src");
}
Run Code Online (Sandbox Code Playgroud)
大多数情况下,您希望使用简单#id和/ .class或DIV标签选择器->find().但您也可以使用XPath语句,有时速度更快.还典型jQuery方法喜欢->children()和->text()特别->attr()简化提取正确的HTML片段.(已经解码了他们的SGML实体.)
$qp->xpath("//div/p[1]"); // get first paragraph in a div
Run Code Online (Sandbox Code Playgroud)
QueryPath还允许将新标记注入流(->append),然后输出并美化更新的文档(->writeHTML).它不仅可以解析格式错误的HTML,还可以解析各种XML方言(带名称空间),甚至可以从HTML微格式(XFN,vCard)中提取数据.
$qp->find("a[target=_blank]")->toggleClass("usability-blunder");
Run Code Online (Sandbox Code Playgroud)
.
phpQuery还是QueryPath?
通常,QueryPath更适合处理文档.虽然phpQuery也实现了一些伪AJAX方法(只是HTTP请求)更接近jQuery.据说phpQuery通常比QueryPath更快(因为整体功能较少).
有关差异的更多信息,请参阅tagbyte.org上的回程机器上的这种比较.(原始来源丢失了,所以这里是一个互联网档案链接.是的,你仍然可以找到丢失的页面,人.)
好处
->find("a img, a object, div a")Rob*_*ell 88
简单的HTML DOM是一个很好的开源解析器:
它以面向对象的方式处理DOM元素,并且新的迭代对非兼容代码有很多覆盖.还有一些很棒的函数,比如你在JavaScript中看到的,比如"find"函数,它将返回该标记名称的所有元素实例.
我已经在许多工具中使用它,在许多不同类型的网页上测试它,我认为它很有用.
Eli*_*Eli 60
我在这里没有提到的一个通用方法是通过Tidy运行HTML ,可以将其设置为吐出有保证的有效XHTML.然后,您可以在其上使用任何旧的XML库.
但是对于您的具体问题,您应该看看这个项目:http://fivefilters.org/content-only/ - 它是Readability算法的修改版本,旨在仅提取文本内容(不是标题)和一个页脚.
Tim*_*imo 56
对于1a和2:我会投票支持新的Symfony Componet类DOMCrawler(DomCrawler).此类允许类似于CSS选择器的查询.看看这个演示文稿,了解真实世界的例子:symfony2世界的新闻.
该组件设计为独立工作,无需Symfony即可使用.
唯一的缺点是它只适用于PHP 5.3或更高版本.
Joe*_*gen 53
顺便说一下,这通常被称为屏幕抓取.我用过的库是Simple HTML Dom Parser.
小智 38
我推荐PHP Simple HTML DOM Parser.
它确实有很好的功能,例如:
foreach($html->find('img') as $element)
echo $element->src . '<br>';
Run Code Online (Sandbox Code Playgroud)
Jen*_*ens 36
这听起来像是W3C XPath技术的一个很好的任务描述.很容易表达诸如"返回嵌套在其中的标签中的所有href属性"之类的查询.不是PHP buff,我不能告诉你XPath可用的形式.如果可以调用外部程序来处理HTML文件,则应该能够使用命令行版本的XPath.有关快速介绍,请参阅http://en.wikipedia.org/wiki/XPath.img<foo><bar><baz> elements
dan*_*car 29
SimpleHtmlDom的第三方替代品,使用DOM而不是String Parsing:phpQuery,Zend_Dom,QueryPath和FluentDom.
Raf*_*fay 24
是的,你可以使用simple_html_dom来达到目的.但是我使用simple_html_dom工作了很多,特别是对于网页报废而且发现它太脆弱了.它完成了基本工作,但我不会推荐它.
我从来没有使用curl达到目的,但我学到的是curl可以更有效地完成工作并且更加坚固.
请查看此链接:scraping-websites-with-curl
Chr*_*mas 23
QueryPath很好,但是如果你没有意识到它意味着什么,要小心"跟踪状态",这可能意味着你浪费了大量的调试时间,试图找出发生了什么以及为什么代码不起作用.
这意味着结果集上的每个调用都会修改对象中的结果集,它不像jquery中那样可链接,其中每个链接都是一个新集合,你有一个集合,它是查询的结果,每个函数调用都会修改那一套.
为了获得类似jquery的行为,你需要在进行过滤/修改之类的操作之前进行分支,这意味着它将更加密切地反映jquery中发生的事情.
$results = qp("div p");
$forename = $results->find("input[name='forename']");
Run Code Online (Sandbox Code Playgroud)
$results现在包含input[name='forename']NOT原始查询的结果集,"div p"这让我大吃一惊,我发现QueryPath跟踪过滤器并找到修改结果的所有内容并将它们存储在对象中.你需要这样做
$forename = $results->branch()->find("input[name='forname']")
Run Code Online (Sandbox Code Playgroud)
然后$results不会被修改,你可以一次又一次地重复使用结果集,也许有更多知识的人可以清楚这一点,但它基本上就像我发现的那样.
pgu*_*rio 19
Advanced Html Dom是一个简单的HTML DOM替换,提供相同的接口,但它基于DOM,这意味着不会发生任何相关的内存问题.
它还具有完整的CSS支持,包括jQuery扩展.
Pau*_*lis 17
我编写了一个通用的XML解析器,可以轻松处理GB文件.它基于XMLReader,使用起来非常简单:
$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
echo $tag->field1;
echo $tag->field2->subfield1;
}
Run Code Online (Sandbox Code Playgroud)
这是github repo:XmlExtractor
Joh*_*ers 17
我创建了一个名为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>');
[...]
Run Code Online (Sandbox Code Playgroud)
该库还包含自己的零配置自动加载器,用于PSR-0兼容库.包含的示例应该开箱即用,无需任何其他配置.或者,您可以将它与作曲家一起使用.
Joh*_*ers 11
有许多方法可以处理HTML/XML DOM,其中大多数已经提到过.因此,我不会尝试自己列出这些.
我只是想补充一点,我个人更喜欢使用DOM扩展,为什么:
虽然我错过了使用CSS选择器的能力DOMDocument,但是有一种相当简单方便的方法来添加这个功能:继承子类DOMDocument并将类似JS querySelectorAll和querySelector方法添加到子类中.
为了解析这些选择,我建议使用非常简约CssSelector组件从Symfony框架.该组件只是将CSS选择器转换为XPath选择器,然后可以将其输入到a中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);
}
}
}
}
[...]
}
Run Code Online (Sandbox Code Playgroud)
另请参阅Symfony的创建者Fabien Potencier 使用CSS选择器解析XML文档,决定为Symfony创建CssSelector组件以及如何使用它.
使用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');
});
Run Code Online (Sandbox Code Playgroud)
https://github.com/servo-php/fluidxml
来自XML的JSON和数组有三行:
$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
Run Code Online (Sandbox Code Playgroud)
塔达!
有几个原因不能通过正则表达式解析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/")));
Run Code Online (Sandbox Code Playgroud)
小智 5
我创建了一个名为 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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
403075 次 |
| 最近记录: |