phpQuery 和 simple_html_dom DOM 解析器对比

phpQuery 和 simple_html_dom 都是非常优秀的 DOM 解析器。

phpQuery 主要使用方法,更多方法查看 https://github.com/TobiaszCudnik/phpquery | https://github.com/punkave/phpQuery

1.加载文档的几种方式

// $html 为内容字符串,$contentType 为文档类型,如果不指定则默认以 text/html in utf-8 类型加载。
phpQuery::newDocument($html,  $contentType = null)
// $file 为文件路径或 url 地址,$contentType 为文档类型,如果不指定则默认以 text/html in utf-8 类型加载。
phpQuery::newDocument($html,  $contentType = null)
// $html 为内容字符串,$charset 为字符串编码,如果不指定默认为 utf8
phpQuery::newDocumentHTML($html,  $charset =  'utf-8')

2.pq() 三种使用方式:

// $param 可以是选择器字符串 (相当于 jquery 中的 $ 包含的字符串), 可以是迭代器中的变量 (相当于 jquery 中 each 中的 this)
pq($param, $context = null);
// $context是一个参考选择器或ID, 例如选择该文档class="myClass"的div节点
pq('div.myClass',  $pq->getDocumentID());
// 以 $pq 为根节点, 选择 $pq 节点中 class="myClass" 的 div 节点
pq('div.myClass',  $pq);

3.与 jquey 语法兼容的基本选择器

1) #id                      pq("#myDiv");
2) element                  pq("div"); 
3) .class                   pq(".myClass"); 
4) *                        pq("*") 
5) selector1,selectorN      pq("div,span,p.myClass")

4.与 jquey 语法兼容的层级选择器

1) ancestor descendant  pq("form input") 
2) parent > child       pq("form > input") 
3) prev + next          pq("label + input") 
4) prev ~ siblings      pq("form ~ input")

5.与 jquey 语法兼容的简单过滤器

1) :first           pq("tr:first") 
2) :last            pq("tr:last") 
3) :not(selector)   pq("input:not(:checked)") 
4) :even            pq("tr:even") 
5) :odd             pq("tr:odd") 
6) :eq(index)       pq("tr:eq(1)")
7) :gt(index)       pq("tr:gt(0)") 
8) :lt(index)       pq("tr:lt(2)")
9) :header          pq(":header").css("background", "#EEE");

6.与 jquey 语法兼容的内容过滤器

1) :contains(text)  pq("div:contains('John')") 
2) :empty           pq("td:empty") 
3) :has(selector)   pq("div:has(p)").addClass("test"); 
4) :parent          pq("td:parent")

7.与 jquey 语法兼容的属性选择器

1) [attribute]              pq("div[id]") 
2) [attribute=value]        pq("input[name='newsletter']").attr("checked", true); 
3) [attribute!=value]       pq("input[name!='newsletter']").attr("checked", true); 
4) [attribute^=value]       pq("input[name^='news']")
5) [attribute$=value]       pq("input[name$='letter']")
6) [attribute*=value]       pq("input[name*='man']")
7) [selector1][selectorN]   pq("input[id][name$='man']")

8.与 jquey 语法兼容的子元素选择器

1) :nth-child(index/even/odd/equation) pq("ul li:nth-child(2)")
2) :first-child     pq("ul li:first-child")
3) :last-child      pq("ul li:last-child")
4) :only-child      pq("ul li:only-child")

9.与 jquey 语法兼容的表单选择器

1) :input       pq(":input")
2) :text        pq(":text")
3) :password    pq(":password")
4) :radio       pq(":radio")
5) :checkbox    pq(":checkbox")
6) :submit      pq(":submit")
7) :image       pq(":image")
8) :reset       pq(":reset") 
9) :button      pq(":button")
10) :file       pq(":file")
11) :hidden     pq("tr:hidden")
  1. 与 jquey 语法兼容的表单过滤器
1) :enabled     pq("input:enabled")
2) :disabled    pq("input:disabled")
3) :checked     pq("input:checked")
4) :selected    pq("select option:selected")
  1. 与 jquey 语法兼容的对象取值和赋值方法
1) attr                 pq("img")->attr("src");
2) attr(properties)     pq("img")->attr({ src: "test.jpg", alt: "Test Image" });
3) attr(key,value)      pq("img")->attr("src","test.jpg");
4) attr(key,fn)         pq("img")->attr("title", function() { return this.src });
5) removeAttr(name)     pq("img")->removeAttr("src");
6) addClass(class)      pq("p")->addClass("selected");
7) removeClass(class)   pq("p")->removeClass("selected");
8) toggleClass(class)   pq("p")->toggleClass("selected");
9) html()               pq("div")->html();
10) html(val)           pq("div")->html("<p>Hello Again</p>");
11) text()              pq("p")->text();
12) text(val)           pq("p")->text("<b>Some</b> new text.");
13) val()               pq("input")->val();
14) val(val)            pq("input")->val("hello world!");
  1. 与 jquey 语法兼容的筛选方法
1) eq(index)            pq("p")->eq(1)
2) hasClass(class)      pq("div")->hasClass("protected")
3) filter(expr)         pq("p")->filter(".selected") 
4) filter(fn)           pq("p")->filter(function($index) { return pq("ol", pq($index))->size() == 0; }); 
5) is(expr)             pq("input[type='checkbox']")->parent()->is("form")
6) map(callback)        pq("p")->append(pq("input").map(function(){ return pq(this)->val(); })->get()->join(", "));
7) not(expr)            pq("p")->not(pq("#selected")[0])
8) slice(start,[end])   pq("p")->slice(0, 1)->wrapInner("<b></b>");
9) add(expr)            pq("p")->add("span")
10) children([expr])    pq("div")->children()
11) contents()          pq("p")->contents()->not("[@nodeType=1]").wrap("<b/>");
12) find(expr)          pq("p")->find("span")13) next([expr])      pq("p")->next()
14) nextAll([expr])     pq("div:first")->nextAll()->addClass("after");
15) parent([expr])      pq("p")->parent()
16) parents([expr])     pq("span")->parents()
17) prev([expr])        pq("p").prev()
18) prevAll([expr])     pq("div:last")->prevAll()->addClass("before"); 
19) siblings([expr])    pq("div")->siblings()
20) andSelf()           pq("div")->find("p")->andSelf()->addClass("border");
21) end()               pq("p")->find("span")->end()
  1. 与 jquey 语法兼容的文档处理
1) append(content)          pq("p")->append("<b>Hello</b>");
2) appendTo(content)        pq("p")->appendTo("#foo");
3) prepend(content)         pq("p")->prepend("<b>Hello</b>");
4) prependTo(content)       pq("p")->prependTo("#foo");
5) after(content)           pq("p")->after("<b>Hello</b>");
6) before(content)          pq("p")->before("<b>Hello</b>");
7) insertAfter(content)     pq("p")->insertAfter("#foo");
8) insertBefore(content)    pq("p")->insertBefore("#foo");
9) wrap(html)               pq("p")->wrap("<div class='wrap'></div>");
10) wrap(elem)              pq("p")->wrap(pq("#content"));
11) wrapAll(html)           pq("p")->wrapAll("<div></div>");
12) wrapAll(elem)           pq("p")->wrapAll(pq("#content")); 
13) wrapInner(html)         pq("p")->wrapInner("<b></b>");
14) wrapInner(elem)         pq("p")->wrapInner(pq(".content"));
15) replaceWith(content)    pq("p")->replaceWith("<b>Paragraph. </b>");
16) replaceAll(selector)    pq("<b>Paragraph. </b>")->replaceAll("p");
17) empty()                 pq("p")->empty();
18) remove([expr])          pq("p")->remove();
19) clone()                 pq("b")->clone()->prependTo("p");
20) clone(true)             pq("button")->clone(true)->insertAfter(pq("b"))
  1. Ajax请求(略)

申明:部分 API 可能无法正常工作,常用 API 已通过测试。也就是 pq(), find(), html(), text(), eq(), attr() 等方法。phpQuery 除了"解析" DOM 之外,还可以像 jquery 一样对 DOM 进行 CRUD 操作,然后输出。

注意,使用 phpQuery 释放内存的命令,使用该命令会清除当前所有解析文档,对循环解析大量文档非常管用。

phpQuery:: $documents =  array ();

此外,phpQuery 作者还编写更多复杂的 API 和插件。

simple_html_dom 主要使用方法,更多方法查看 https://github.com/voku/simple_html_dom | http:// simplehtmldom.sourceforge.net/

include 'simple_html_dom.php';
// 面向过程方式 2 种读取方式 
$html = file_get_html('http:// www.baidu.com');
$html = str_get_html(file_get_contents ('http:// www.baidu.com'));
//  面向对象方式  种读取方式
$html =  new simple_html_dom();
$html->load_file('http:// www.baidu.com');
$html->load(file_get_contents ('http:// www.baidu.com'));
foreach($html->find('img') as $img){  
     print_r($img->src). "<br>" ;
}

simple_html_dom 的 find 方法参数一与 jquery 的 模式基本一致,可以使用条件搜索,返回的变量 e 是一个对象,具有以下几类属性:

$e->tag         与原生 js 的 tagName 对应,jquery 的 $(e).attr('nodeName') 对应
$e->outertext   与原生 js 的 outerHTML 对应,jquery 的 $(e).attr('outerHTML') 对应
$e->innertext   与原生 js 的 innerHTML 对应,jquery 的 $(e).attr('innerHTML') 或 $(e).html() 对应
$e->plaintext   与原生 js 的 innerText 对应,jquery 的 $(e).attr('innerText') 或 $(e).text() 对应

常用的方法如下:
mixed $e->children(index)   index 为索引序号,返回第 n 个子节点对象
element $e->parent()        返回父节点对象
element $e->first_child()   返回第一个子节点对象
element $e->last_child()    返回最后一个子节点对象
element $e->next_sibling()  返回下一个邻节点对象
element $e->prev_sibling()  返回上一个邻节点对象

simple_html_dom 主打 find 方法,如果 find 只有一个参数其查找到的元素一般以对象数组的方式进行遍历;如果添加第二个参数表示索引则返回一个元素,如下:

echo "<pre>";
print_r($html->find('img', 0)->src);
echo "</pre>";

功能虽然发现的不多,但应对一般的 html 解析已经足够。注意:如果需要解析大量 html 建议使用 $html->clear() 释放内存。

比较:

phpQuery 在语法风格上更像 jquery 并且功能更强大,优点是稳定,兼容性好,jquery 一样简单易用,一般情况下即使获取不存在的对象属性或方法都不会报错。缺点是占用内存大,解析过程中可能会遇到解析失败(但不报错)的情况,例如解析 top.baidu.com 页面的时候会出现获取的 a 标签数量非常少。

simple_html_dom 在语法风格上更像原生 js 但是支持类似 jquery 选择器(只是类似,如 find 中的选择器),返回的对象不需要使用任何包装器,直接获取对象值或调用对象方法。优点是兼容性更好,占用内存低,缺点是不稳定(编写调试过程中需要额外编写代码保证对象是否获取成功以及是否拥有某个属性和方法)。

一般情况下,使用 phpQuery 即可快速完成网页解析,其 API 众多易用,支持复杂的选择器和获取方法,和 jquery 相似度极高,可以参考 jquery 手册。

当 phpQuery 不能正常解析的时候可以考虑 simple_html_dom,因为 simple_html_dom 支持的属性和方法太少了,但是使用 simple_html_dom 需要注意代码的严谨性,需要经常考虑每一步操作是否返回预期的值(例如获取不到对象的时候再获取返回值的属性是会报错的)。

本文链接: https://blog.csdn.net/zdw19861127/article/details/78808208

posted on 2021-03-29 10:39  sochishun  阅读(213)  评论(0编辑  收藏  举报