开发人员时不时地需要抓取网页以从网站上获取一些信息。 例如,假设您正在一个个人项目中,必须从Wikipedia获取有关不同国家首都的地理信息。 手动输入此内容会花费很多时间。 但是,您可以通过在PHP的帮助下抓取Wikipedia页面来非常快地完成操作。 您还可以自动解析HTML以获取特定信息,而不必手动进行整个标记。
在本教程中,我们将学习一个名为DiDOM的快速,易于使用HTML解析器。 我们将从安装过程开始,然后学习如何使用不同类型的选择器(例如标签,类等)从网页上的不同元素中提取信息。
安装及使用
您可以通过运行以下命令在您的项目目录中轻松安装DiDOM:
composer require imangazaliev/didom
一旦运行了以上命令,就可以从字符串,本地文件或网页中加载HTML。 这是一个例子:
require_once('vendor/autoload.php');
use DiDom\Document;
$document = new Document($washington_dc_html_string);
$document = new Document('washington_dc.html', true);
$url = 'https://en.wikipedia.org/wiki/Washington,_D.C.';
$document = new Document($url, true);
当您决定从文档中解析HTML时,它可能已经被加载并存储在变量中。 在这种情况下,您可以简单地将该变量传递给Document()
并且DiDOM将为解析准备字符串。
如果必须从文件或URL加载HTML,则可以将其作为第一个参数传递给Document()
,并将第二个参数设置为true
。
您也可以使用不带任何参数的new Document()
创建一个新的Document
对象。 在这种情况下,可以调用loadHtml()
方法从字符串加载HTML,并loadHtmlFile()
从文件或网页加载HTML。
查找HTML元素
从元素获取HTML或文本之前,要做的第一件事就是找到元素本身。 最简单的方法是简单地使用find()
方法并将预期元素CSS选择器作为第一个参数传递。
您还可以将元素的XPath传递为find()
方法的第一个参数。 但是,这要求您传递Query::TYPE_XPATH
作为第二个参数。
如果只想使用XPath值来查找HTML元素,则可以简单地使用xpath()
方法,而不必每次都将Query::TYPE_XPATH
作为第二个参数传递给find()
。
如果DiDOM可以找到与传递CSS选择器或XPATH表达式匹配的元素,则它将返回DiDom\Element
的实例数组。 如果找不到这样的元素,它将返回一个空数组。
由于这些方法返回数组,因此可以使用find()[n-1]
直接访问第n个匹配元素。
一个例子
在以下示例中,我们将从Wikipedia文章中有关华盛顿特区的所有第一和第二级标题中获取内部HTML
require_once('vendor/autoload.php');
use DiDom\Document;
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
$main_heading = $document->find('h1.firstHeading')[0];
echo $main_heading->html();
$sub_headings = $document->find('h2');
foreach($sub_headings as $sub_heading) {
if($sub_heading->text() !== 'See also') {
echo $sub_heading->html();
} else {
break;
}
}
首先,通过传递有关华盛顿特区的Wikipedia文章的URL,创建一个新的Document对象。此后,我们使用find()
方法获取主标题元素,并将其存储在名为$main_heading
的变量中。 现在,我们将能够对此元素调用不同的方法,例如text()
, innerHtml()
, html()
等。
对于主标题,我们只需要调用html()
方法即可,该方法返回整个head元素HTML。 同样,我们可以使用innerHtml()
方法在特定元素内获取HTML。 有时,您会对元素的纯文本内容而不是HTML更加感兴趣。 在这种情况下,您可以简单地使用text()
方法并完成它。
二级标题将Wikipedia页面分为定义明确的部分。 但是,您可能想要摆脱一些子标题,例如“另请参阅”,“注释”等。
一种方法是遍历所有第二级标题并检查text()
方法返回的值。 如果返回的标题文本为“另请参见”,我们将跳出循环。
您可以分别使用$document->find('h2')[3]
和$document->find('h2')[5]
直接进入第4级或第6级标题。
遍历DOM
一旦可以访问特定元素,该库就可以让您上下移动DOM树以轻松访问其他元素。
您可以使用parent()
方法转到HTML元素的parent()
。 同样,您可以使用nextSibling()
和previousSibling()
方法到达元素的下一个或上一个同级。
也有很多方法可以访问DOM元素的子级。 例如,您可以使用child(n)
方法访问特定的子元素。 同样,您可以使用firstChild()
和lastChild()
方法访问特定元素的第一个或最后一个孩子。 您可以使用children()
方法遍历特定DOM元素的所有children()
。
到达特定元素后,您将能够使用html()
, innerHtml()
和text()
方法访问其HTML等。
在下面的示例中,我们从第二级标题元素开始,并继续检查下一个同级元素是否包含一些文本。 一旦找到带有文本的同级元素,便将其输出到浏览器。
require_once('vendor/autoload.php');
use DiDom\Document;
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
$sub_headings = $document->find('h2');
for($i = 1; $i < count($sub_headings); $i++) {
if($sub_headings[$i]->text() !== 'See also') {
$next_sibling = $sub_headings[$i]->nextSibling();
while(!$next_elem->html()) {
$next_sibling = $next_sibling->nextSibling();
}
echo $next_elem->html()."<br>";
} else {
break;
}
}
您可以使用类似的技术来遍历所有同级元素,并且仅在文本包含特定字符串或同级元素是段落标记等时才输出文本。一旦您了解了基础知识,就很容易找到正确的信息。
操纵元素属性
在某些情况下,获取或设置不同元素的属性值的能力非常有用。 例如,我们可以使用$image_elem->attr('src')
Wikipedia文章中所有img标签的src属性值。 以类似的方式,您可以获取文档中所有a标签的href属性值。
有三种方法可以获取HTML元素的给定属性的值。 您可以使用getAttribute('attrName')
方法并将您感兴趣的属性的名称作为参数传递。 您还可以使用attr('attrName')
方法,该方法与getAttribute()
。 最后,该库还允许您使用$elem->attrName
直接获取属性值。 这意味着您可以使用$imageElem->src
直接获取图像元素的src属性值。
require_once('vendor/autoload.php');
use DiDom\Document;
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
$images = $document->find('img');
foreach($images as $image) {
echo $image->src."<br>";
}
一旦拥有src属性的访问权限,就可以编写代码以自动下载所有图像文件。 这样,您将可以节省大量时间。
您还可以使用三种不同的技术来设置给定属性的值。 首先,您可以使用setAttribute('attrName', 'attrValue')
方法设置属性值。 您还可以使用attr('attrName', 'attrValue')
方法来设置属性值。 最后,可以使用$Elem->attrName = 'attrValue'
设置给定元素的属性值。
添加,删除和替换元素
您还可以使用库提供的不同方法来更改已加载HTML文档。 例如,您可以使用appendChild()
, replace()
和remove()
方法在DOM树中添加,替换或删除元素。
该库还允许您创建自己HTML元素,以便将它们附加到原始HTML文档中。 您可以使用new Element('tagName', 'tagContent')
创建一个新的Element对象。
请记住,如果您的程序在实例化元素对象之前不包含use DiDom\Element
的行,则会出现未捕获的错误:未找到类'Element'的错误。
拥有元素后,可以使用appendChild()
方法将其附加到DOM中的其他元素,也可以使用replace()
方法将新实例化的元素用作文档中某些旧HTML元素的替换。 以下示例应有助于进一步阐明该概念。
require_once('vendor/autoload.php');
use DiDom\Document;
use DiDom\Element;
$document = new Document('https://en.wikipedia.org/wiki/Washington,_D.C.', true);
// This will result in error.
echo $document->find('h2.test-heading')[0]->html()."\n";
$test_heading = new Element('h2', 'This is test heading.');
$test_heading->class = 'test-heading';
$document->find('h1')[0]->replace($test_heading);
echo $document->find('h2.test-heading')[0]->html()."\n";
最初,我们的文档中没有带有test-heading类的h2元素。 因此,如果尝试访问此类元素,我们将不断出错。
确认没有这样的元素后,我们创建一个新的h2元素并将其class属性的值更改为test-heading 。
之后,我们用新创建的h2元素替换文档中的第一个h1元素。 再次在文档上使用find()
方法来查找带有test-heading类的h2标题,现在将返回一个元素。
最后的想法
本教程介绍了PHP DiDOM HTML解析器的基础知识。 我们从安装开始,然后学习了如何从字符串,文件或URL加载HTML。 之后,我们讨论了如何基于CSS选择器或XPath查找特定元素。 我们还学习了如何获取元素的同级,父级或子级。 其余各节介绍了如何处理HTML文档中特定元素的属性或添加,删除和替换元素。
如果您希望我在本教程中阐明任何内容,请随时在评论中让我知道。
翻译自: https://code.tutsplus.com/tutorials/parsing-html-with-php-using-didom--cms-31242