DomCrawler组件
编辑本页DomCrawler组件
DomCrawler组件简化了HTML和XML文档的DOM导航。
请注意
尽管有可能,但DomCrawler组件并不是为操纵DOM或重新转储HTML/XML而设计的。
安装
1
$作曲家需要symfony/dom-ob娱乐下载crawler
请注意
如果在Symfony应用程序外部安装此组件,则必须要求ob娱乐下载供应商/ autoload.php
文件,以启用Composer提供的类自动加载机制。读这篇文章欲知详情。
使用
另请参阅
本文解释了如何在任何PHP应用程序中使用DomCrawler特性作为独立组件。读了ob娱乐下载Symfony功能测试文章,以了解在创建Symfony测试时如何使用它。ob娱乐下载
的履带类提供了查询和操作HTML和XML文档的方法。
爬虫程序的实例表示一组DOMElement对象,它们是节点,可以按如下方式遍历:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
使用ob娱乐下载\组件\DomCrawler\履带;$超文本标记语言=< < <“HTML”< !DOCTYPE html> Hello World!
Hello Crawler!
HTML;$履带=新履带($超文本标记语言);foreach($履带作为$domElement) {var_dump($domElement->节点名);}
专业链接,图像而且形式当你遍历html树时,类对于与html链接、图像和表单交互非常有用。
请注意
DomCrawler将尝试自动修复您的HTML以匹配官方规范。例如,如果你嵌套一个< p >
标签在另一个里面< p >
标签,它将被移动到父标签的兄弟姐妹。这是预期的,也是HTML5规范的一部分。但如果你得到了意想不到的行为,这可能是一个原因。虽然DomCrawler并不意味着转储内容,但你可以通过它看到HTML的“固定”版本倾销它.
请注意
如果您需要更好地支持HTML5内容,或者希望摆脱PHP DOM扩展的不一致性,请安装html5-php图书馆.当内容具有HTML5文档类型时,DomCrawler组件将自动使用它。
节点过滤
使用XPath表达式,您可以在文档中选择特定的节点:
1
$履带=$履带->filterXPath (“子轴或self::阀体/ p”);
提示
DOMXPath:查询
在内部实际执行XPath查询。
如果您更喜欢CSS选择器而不是XPath,请安装CssSelector组件.它允许你使用类似jquery的选择器:
1
$履带=$履带->过滤器('body > p');
匿名函数可以用来过滤更复杂的条件:
1 2 3 4 5 6 7 8 9
使用ob娱乐下载\组件\DomCrawler\履带;/ /……$履带=$履带->过滤器('body > p')->减少(函数(履带$节点,$我){//过滤所有其他节点返回($我%2) = =0;});
若要删除节点,匿名函数必须返回假
.
请注意
所有筛选器方法都返回一个new履带实例。要检查过滤器是否真的找到了一些东西,请使用$crawler->count() > 0
在这个新的履带上。
这两个filterXPath ()而且filter ()方法使用XML名称空间,这些名称空间可以自动发现,也可以显式注册。
考虑下面的XML:
12 3 4 5 6 7 8 9 10 11 12 13 14
<??> . xml version="1.0" encoding="UTF-8"<条目xmlns=“http://www.w3.org/2005/Atom”xmlns:媒体=“http://search.yahoo.com/mrss/”xmlns:欧美=“http://gdata.youtube.com/schemas/2007”><id>标签:youtube.com, 2008:视频:kgZRZmEc9j4id><欧美accessControl行动=“评论”许可=“允许”/><欧美accessControl行动=“videoRespond”许可=“主持”/><媒体:组><媒体:标题类型=“普通”>脊索动物——生物学速成班第24课媒体:标题><欧美aspectRatio>宽屏欧美aspectRatio>媒体:组>条目>
属性可以对其进行过滤履带
而不需要同时注册名称空间别名filterXPath ():
1
$履带=$履带->filterXPath (' / /默认值:输入/媒体:集团/ /欧美aspectRatio”);
而且filter ():
1
$履带=$履带->过滤器('default|entry media|group yt|aspectRatio');
请注意
默认名称空间使用前缀“default”注册。可以使用setDefaultNamespacePrefix ()方法。
如果默认名称空间是文档中唯一的名称空间,则在加载内容时删除默认名称空间。这样做是为了简化XPath查询。
类显式地注册名称空间registerNamespace ()方法:
1 2
$履带->registerNamespace (“米”,“http://search.yahoo.com/mrss/”);$履带=$履带->filterXPath (' / / m: / /欧美aspectRatio”);
验证当前节点是否匹配选择器:
1
$履带->匹配(“p.lorem”);
节点遍历
按其在列表中的位置划分接入节点:
1
$履带->过滤器('body > p')->eq (0);
获取当前选择的第一个或最后一个节点:
1 2
$履带->过滤器('body > p')->第();$履带->过滤器('body > p')->最后();
获取与当前选择的节点同级的节点:
1
$履带->过滤器('body > p')->兄弟姐妹();
在当前选择之后或之前获得相同级别的节点:
1 2
$履带->过滤器('body > p')->nextAll ();$履带->过滤器('body > p')->previousAll ();
获取所有子节点或祖先节点:
1 2
$履带->过滤器(“身体”)->孩子();$履带->过滤器('body > p')->祖先();
5.3
的祖先()
方法在Symfony 5.3中引入。ob娱乐下载
获取与CSS选择器匹配的所有直接子节点:
1
$履带->过滤器(“身体”)->儿童(“p.lorem”);
获取与所提供的选择器匹配的元素的第一个父元素(指向文档根):
1
$履带->最近的(“p.lorem”);
请注意
所有遍历方法都返回一个new履带实例。
访问节点值
访问当前选择的第一个节点的节点名(HTML标记名)。"p"或"div"):
1 2
//返回下第一个子元素的节点名(HTML标签名)$标签=$履带->filterXPath (' / /身体/ *)->节点名();
访问当前选择的第一个节点的值:
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16
//如果节点不存在,调用text()将导致异常$消息=$履带->filterXPath (' / /身体/ p ')->文本();//避免异常传递text()在node不存在时返回的参数$消息=$履带->filterXPath (' / /身体/ p ')->文本(“默认文本内容”);//默认情况下,text()修饰空格,包括内部空格/ /(如。" Foo \n bar baz \n "返回为" Foo bar baz")//传递FALSE作为第二个参数以返回原始文本$履带->filterXPath (' / /身体/ p ')->文本(“默认文本内容”,假);// innerText()与text()类似,但只返回文本//当前节点的直接后代,不包括任何子节点$文本=$履带->filterXPath (' / /身体/ p ')->innerText(实现);//如果content Foo Bar
. >Bar// innerText()返回'Foo'和text()返回'Foo Bar'
5.4
的innerText()实现
方法在Symfony 5.4中引入。ob娱乐下载
访问当前选择的第一个节点的属性值:
1
$类=$履带->filterXPath (' / /身体/ p ')->attr (“类”);
从节点列表中提取属性和/或节点值:
1 2 3 4
$属性=$履带->filterXpath (' / /身体/ p ')->提取([“_name”,“_text”,“类”]);
请注意
特殊的属性_text
表示节点值,而_name
表示元素名称(HTML标记名称)。
在列表的每个节点上调用一个匿名函数:
1 2 3 4 5 6
使用ob娱乐下载\组件\DomCrawler\履带;/ /……$nodeValues=$履带->过滤器(“p”)->每个(函数(履带$节点,$我){返回$节点->文本();});
匿名函数接收节点(作为爬虫)和位置作为参数。结果是匿名函数调用返回的值数组。
当使用嵌套爬虫时,要注意这一点filterXPath ()
在爬虫的上下文中计算:
1 2 3 4 5 6 7 8
$履带->filterXPath (“父”)->每个(函数(履带$parentCrawler,$我){//直接子文件找不到$subCrawler=$parentCrawler->filterXPath (“sub-tag / sub-child-tag”);//也指定父标签$subCrawler=$parentCrawler->filterXPath (“父/ sub-tag / sub-child-tag”);$subCrawler=$parentCrawler->filterXPath (“节点()/ sub-tag / sub-child-tag”);});
添加内容
爬虫支持多种添加内容的方式,但它们是互斥的,所以你只能使用其中一种方式来添加内容(例如,如果你将内容传递给履带
构造函数,你不能调用addContent ()
后):
1 2 3 4 5 6 7 8 9 10
$履带=新履带(身体的< html > < / > < / html >”);$履带->addHtmlContent (身体的< html > < / > < / html >”);$履带->addXmlContent (' <根> <节点/ >根> < /”);$履带->addContent (身体的< html > < / > < / html >”);$履带->addContent (' <根> <节点/ >根> < /”,“text / xml”);$履带->add (身体的< html > < / > < / html >”);$履带->add (' <根> <节点/ >根> < /”);
请注意
的addHtmlContent ()而且addXmlContent ()方法默认为UTF-8编码,但您可以通过它们的第二个可选参数来改变这种行为。
的addContent ()方法根据给定的内容猜测最佳字符集,并默认为iso - 8859 - 1
以防无法猜出字符集。
由于爬虫的实现是基于DOM扩展的,所以它也能够与本机交互DOMDocument,DOMNodeList而且DOMNode对象:
1 2 3 4 5 6 7 8 9 10
$domDocument=新\ DOMDocument ();$domDocument->loadXml (' <根> <节点/ > <节点/ >根> < /”);$节点列表=$domDocument->getElementsByTagName (“节点”);$节点=$domDocument->getElementsByTagName (“节点”)->项目(0);$履带->addDocument ($domDocument);$履带->addNodeList ($节点列表);$履带->addnode ([$节点]);$履带->addNode ($节点);$履带->add ($domDocument);
操纵和倾倒履带
这些方法履带
最初打算填充您的履带
并且不打算用于进一步操作DOM(尽管这是可能的)。然而,自从履带
是一套DOMElement对象上可用的任何方法或属性DOMElement,DOMNode或DOMDocument.例如,您可以获得的HTML履带
就像这样:
1 2 3 4 5
$超文本标记语言='';foreach($履带作为$domElement){$超文本标记语言.=$domElement->ownerDocument->saveHTML ($domElement);}
或者,您可以使用html ():
1 2 3 4 5
//如果节点不存在,调用html()将导致异常$超文本标记语言=$履带->html ();//避免异常传递一个参数,当node不存在时html()返回$超文本标记语言=$履带->html (默认值HTML内容);
或者,您可以使用outerHtml ():
1
$超文本标记语言=$履带->outerHtml ();
表达式求值
的evaluate ()
方法计算给定的XPath表达式。返回值取决于XPath表达式。如果表达式计算为标量值(例如HTML属性),将返回一个结果数组。如果表达式计算为DOM文档,则new履带
实例将返回。
这种行为最好用例子来说明:
12 34 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 46 47
使用ob娱乐下载\组件\DomCrawler\履带;$超文本标记语言= article 1 article 2 article 3 ';$履带=新履带();$履带->addHtmlContent ($超文本标记语言);$履带->filterXPath (' / /跨度(包含(@ id,“文章——“))”)->评估(“substring-after (@ id,“-”));/ *结果:[0 = > ' 100 ',1 = > ' 101 ',2 = > ' 102 ',);* /$履带->评估(“substring-after(/ /跨度(包含(@ id,“文章——”)]/ @ id,“-”)”);/* Result: [0 => '100',] */$履带->filterXPath (' / /跨度(@class =“文章”)”)->评估(“数(@ id)”);/* Result: [0 => 1.0, 1 => 1.0, 2 => 1.0,] */$履带->评估(“计数(/ /跨度[@class = "文章"])”);/* Result:[0 => 3.0,] */ .输出说明$履带->评估(/ /跨[1]”);// Syob娱乐下载mfony\Component\DomCrawler\Crawler实例
链接
使用filter ()
方法通过它们来查找链接id
或类
属性,并使用selectLink ()
方法根据其内容查找链接(它还查找在其内容中包含该内容的可单击图像alt
属性)。
两个方法都返回履带
实例,只使用所选链接。使用链接()
方法来获取链接对象,该对象表示链接:
12 3 4 5 6 7 8 9 10 11 12
//首先,通过id,类或内容选择链接…$linkCrawler=$履带->过滤器(“#注册”);$linkCrawler=$履带->过滤器(“.user-profile”);$linkCrawler=$履带->selectLink (“登录”);/ /……然后,获取Link对象:$链接=$linkCrawler->链接();//或者一次执行所有这些操作:$链接=$履带->过滤器(“#注册”)->链接();$链接=$履带->过滤器(“.user-profile”)->链接();$链接=$履带->selectLink (“登录”)->链接();
的链接对象有几个有用的方法来获取有关所选链接本身的更多信息:
1 2
//返回可用于发出另一个请求的正确URI$uri=$链接->getUri ();
请注意
的getUri ()
特别有用,因为它能清洁href
重视并将其转化为真正应该处理的方式。例如,与的链接href = " # foo”
,这将返回当前页面的完整URI# foo
.从getUri ()
始终是一个完整的URI,您可以对其进行操作。
图片
通过它找到一个图像alt
属性,使用selectImage
方法。返回一个履带
实例,只使用所选映像。调用图像()
给你一个特别的图像对象:
1 2 3 4 5
$imagesCrawler=$履带->selectImage (“小猫”);$图像=$imagesCrawler->图像();//或者一次执行所有这些操作$图像=$履带->selectImage (“小猫”)->图像();
形式
对表单也给予特殊处理。一个selectButton ()
方法在爬虫上可用,它会返回另一个匹配的爬虫< >按钮
或< input type = " submit " >
或< input type = " button " >
元素(或< img >
其中的元素)。参数所给出的字符串将在id
,alt
,的名字
,价值
属性和这些元素的文本内容。
此方法特别有用,因为您可以使用它返回形式对象,该对象表示按钮所在的表单:
12 3 4 5 6 7 8 9 10 11 12 13 14 15
//按钮示例: .//你可以通过它的标签得到按钮$形式=$履带->selectButton (“我的超级按钮”)->形式();//或通过按钮id (#my-super-button)如果按钮没有标签$形式=$履带->selectButton (“my-super-button”)->形式();//或者你可以过滤整个表单,例如一个表单有一个class属性:$履带->过滤器(“.form-vertical”)->形式();//或用数据“填充”表单字段$形式=$履带->selectButton (“my-super-button”)->形式([“名字”= >“瑞恩”]);
的形式Object有很多非常有用的方法来处理表单:
1 2 3
$uri=$形式->getUri ();$方法=$形式->getMethod ();$的名字=$形式->getName ();
的getUri ()方法所做的不仅仅是返回行动
表单的属性。如果表单方法是GET,那么它将模拟浏览器的行为并返回行动
属性,然后是包含所有表单值的查询字符串。
请注意
可选formaction
而且formmethod
支持按钮属性。的getUri ()
而且getMethod ()
方法会考虑这些属性,总是根据用于获取表单的按钮返回正确的操作和方法。
你可以在表单上虚拟设置和获取值:
12 3 4 5 6 7 8 9 10 11 12
//在表单内部设置值$形式->setvalue ([“登记【用户名】”= >“ob娱乐下载symfonyfan”,“登记(术语)”= >1]);//返回一个值的数组-在“平面”数组中,如上面所示$值=$形式->getvalue ();//返回PHP会看到的值,//其中registration是它自己的数组$值=$形式->getPhpValues ();
处理多维字段:
1 2 3 4 5 6 7 8
<形式><输入的名字=“多[]”/><输入的名字=“多[]”/><输入的名字=“多(维)”/><输入的名字=“多(维)[]”价值=“1”/><输入的名字=“多(维)[]”价值=“2”/><输入的名字=“多(维)[]”价值=“3”/>形式>
传递一个值数组:
12 3 4 5 6 7 8 9 10 11 12 13
//设置单个字段$形式->setvalue ([“多”= > [“价值”]]);//同时设置多个字段$形式->setvalue ([“多”= > [1= >“价值”,“维”= >“另一个价值”]]);//同时勾选多个复选框$形式->setvalue ([“多”= > [“维”= > [1,3.]//它使用输入值来确定要勾选哪个复选框]]);
这很棒,但还有更好的!的形式
对象允许您像浏览器一样与您的表单交互,选择单选值,勾选复选框,并上传文件:
12 3 4 5 6 7 8 9 10 11 12 13 14
$形式[“登记【用户名】”]->setValue (“ob娱乐下载symfonyfan”);//选中或取消选中复选框$形式[“登记(术语)”]->蜱虫();$形式[“登记(术语)”]->取消勾选();//选择一个选项$形式[的登记(生日)(年)]->选择(1984);//从多个选择中选择多个选项$形式[“登记(利益)”]->选择([sob娱乐下载ymfony的,“饼干”]);//伪造文件上传$形式[“登记(图)”]->上传(“/道路/ / lucas.jpg”);
使用表单数据
做这些有什么意义?如果你在内部测试,你可以从你的表单中获取信息,就像它刚刚被提交一样,使用PHP值:
1 2
$值=$形式->getPhpValues ();$文件=$形式->getPhpFiles ();
如果你正在使用外部HTTP客户端,你可以使用表单获取所有你需要为表单创建POST请求的信息:
1 2 3 4 5 6
$uri=$形式->getUri ();$方法=$形式->getMethod ();$值=$形式->getvalue ();$文件=$形式->getfile ();//现在使用一些HTTP客户端和post使用这些信息
使用所有这些的集成系统的一个很好的例子是HttpBrowser由BrowserKit组件.它理解Symfony爬虫对象,并可以使ob娱乐下载用它直接提交表单:
12 3 4 5 6 7 8 9 10 11 12 13 14
使用ob娱乐下载\组件\BrowserKit\HttpBrowser;使用ob娱乐下载\组件\HttpClient\HttpClient;//向外部站点发出真实请求$浏览器=新HttpBrowser (HttpClient::create ());$履带=$浏览器->请求(“得到”,“https://github.com/login”);//选择表单并填写一些值$形式=$履带->selectButton (“登录”)->形式();$形式[“登录”] =“ob娱乐下载symfonyfan”;$形式[“密码”] =“anypass”;//提交给定表单$履带=$浏览器->提交($形式);
选择无效的选择值
默认情况下,选择字段(select, radio)激活了内部验证,以防止设置无效值。如果希望能够设置无效值,可以使用disableValidation ()
整个表单或特定字段的方法:
1 2 3 4 5 6
//禁用对特定字段的验证$形式[“国家”]->disableValidation ()->选择(“无效的价值”);//禁用整个表单的验证$形式->disableValidation ();$形式[“国家”]->选择(“无效的价值”);
解析URI
5.1
的UriResolverhelper类是在Symfony 5.1中添加的。ob娱乐下载
的UriResolver类接受一个URI(相对URI、绝对URI、片段URI等),并将其转换为相对于另一个给定的基URI的绝对URI:
1 2 3 4 5
使用ob娱乐下载\组件\DomCrawler\UriResolver;UriResolver::解决(' / foo ',“http://localhost/bar/foo/”);/ / http://localhost/fooUriResolver::解决(”?a = b”,“http://localhost/bar foo”);/ / http://localhost/bar?a=bUriResolver::解决(“. . / . . /”,“http://localhost/”);/ / http://localhost/