DomCrawler工作原理:
工作原理就是将抓取到的html页面字符串实例化为一个dom对象,通过 xpath 语法或者 css选择器 语法选择其中的dom节点,类似于jquery的css选择器一样,提取页面元素的属性或者值,基本能获取到页面任意想要的内容,非常强大,是一个应用于爬虫中分析html元素及提取内容的利器。
安装:
composer require symfony/dom-crawler //css-selector也需要安装,才能使用xpath选择器 composer require symfony/css-selector
使用:
1.简单使用
require_once 'vendor/autoload.php';
#引入安装的composer类库
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\CssSelector\CssSelectorConverter;
#抓取到的html字符串
$html = <<<'HTML'
Hello Crawler!
HTML;
#实例化dom对象
$crawler = new Crawler();
$crawler->addHtmlContent($html);
#获取节点元素
foreach ($crawler as $domElement) {
var_dump($domElement->nodeName);
}
2. css选择器的使用
$crawler->filter('selector名称');
如果想要选择页面的某个元素下的内容,css选择器语法该怎么写呢?
有一个简单的方法,以谷歌浏览器为例,打开 www.baidu.com,比如我要获取到 百度一下 这个按钮下的内容
按 F12 打开开发者工具,光标定位到该元素,是如下的元素:
想要获取上图中span下的内容,点击span > 右键 > copy >copy selector,便复制了该按钮的css选择器。
然后使用以下规则:
$crawler->filter('#s_btn_wr');
就能获取到该span下的内容了,至于获取到某个元素下的内容后怎么进一步处理,比如获取元素属性值,元素内容等,后面会详细说。
当然我们有时候页面某个元素并没有一个id或者class的选择器,但是也可以按照以上的方法来获取css选择器,只不过这个选择器可能会比较长了,如下:
#有时候可能会这样,不过也能获取到某个元素下的内容
#rmain > div > div:nth-child(2) > div:nth-child(3) > div:nth-child(5) > div.bd > table > tbody > tr
###获取页面中所有a标签href属性值包含 *info* 关键词的a元素,在提取页面某一类url很有用
$crawler->filterXPath('//a[contains(@href,"info")]');
###获取文本中包含 *职称* 两个字的span标签,这在通过文本信息来提取某类元素有用
$crawler->filterXPath('//span[contains(text(),"职称")]');
####选择两个特定元素之间的所有元素,这个很变态,很强大,放一个公式吧,具体怎么用可参考https://ask.helplib.com/xml/post_1005470 文章内容
$ns1[count(.|$ns2) = count($ns2)]
关于xpath语法更多详细的使用,大家可参考下xpath教程的一些语法规则,多用用就知道了。
在这里我介绍一个谷歌浏览器的xpath的插件,在谷歌应用商店下载 xpath helper(前提需要fanqiang)如下图:
很好用,可以在某个页面中打开,用来检测自己的xpath表达式是否正确,很有用。
$crawler->filter('body > p')->eq(0); ###获取body下的第一个p元素
$crawler->filter('body > p')->first(); ###获取body下的第一个p元素
$crawler->filter('body > p')->last(); ###获取body下的最后一个p元素
$crawler->filter('body > p')->siblings(); ###获取body下p元素的所有兄弟元素
$crawler->filter('body > p')->nextAll(); ###获取body下p元素所有后面的元素
$crawler->filter('body > p')->previousAll(); ###获取body下p元素所有前面的元素
$crawler->filter('body')->children(); ###获取body下的所有子元素
$crawler->filter('body > p')->parents(); ###获取body下p元素的父元素
$crawler->filterXPath('//body/*')->nodeName(); ###获取body下元素节点名称
$crawler->filterXPath('//body/p')->text(); ###获取body下p元素中的文本内容
$crawler->filterXPath('//body/p')->attr('class'); ###获取body下p元素的class属性值
有时候会获取到多个节点,需要采用循环对每一个节点进行处理,可以用循环如下:
$crawler->filter('p')->each(function (Crawler $node, $i) {
return $node->text();
});
composer require symfony/css-selector #composer安装
use Symfony\Component\CssSelector\CssSelectorConverter; #php页面中引入
$crawler = new Crawler();
$crawler->addHtmlContent($html);
#rmain > div > div:nth-child(2) > div:nth-child(3) > div:nth-child(5) > div.bd > table > tbody > tr
我们在查看页面源代码的时候,也许table下是没有tbody的,可能table下直接是tr,不过为什么通过开发者工具复制出来的selector有呢,因为浏览器对html的table有时候会自动把tbody给补上的,但是页面源代码中并没有,所有我们有时候还需要结合页面源代码来分析选择器是否正确。