composer类库-HTML分析组件DomCrawler

最近用php进行爬虫学习,用composer安装了一个类库 symfony/dom-crawler,用来分析抓取到的网页html元素,提取其中想要的内容。因其没有中文文档,也很少有使用这个类库的相关中文资料,所以使用过程中也遇到了一些坑,在这里将使用过程中的心得及遇到问题和解决办法记录一下。


  • DomCrawler工作原理:
    工作原理就是将抓取到的html页面字符串实例化为一个dom对象,通过 xpath 语法或者 css选择器 语法选择其中的dom节点,类似于jquery的css选择器一样,提取页面元素的属性或者值,基本能获取到页面任意想要的内容,非常强大,是一个应用于爬虫中分析html元素及提取内容的利器。

  • 安装:

composer require symfony/dom-crawler
composer require symfony/css-selector    #css-selector也需要安装,才能使用xpath选择器
  • 使用:
  1. 简单使用
require_once 'vendor/autoload.php';

#引入安装的composer类库
use Symfony\Component\DomCrawler\Crawler;
use Symfony\Component\CssSelector\CssSelectorConverter;

#抓取到的html字符串
$html = <<<'HTML'
<!DOCTYPE html>
<html>
    <body>
        <p class="message">Hello World!</p>
        <p>Hello Crawler!</p>
    </body>
</html>
HTML;

#实例化dom对象
$crawler = new Crawler();
$crawler->addHtmlContent($html);

#获取节点元素
foreach ($crawler as $domElement) {
    var_dump($domElement->nodeName);
}

  1. 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

  1. xpath选择器语法使用
    用css选择器可能有时候会比较憋屈,因为copy出来的选择器会比较长,而且有时候不一定准,要结合页面源代码观察,而且有时候在某些特殊情况下并没有办法获取到想要的内容,比如有以下要求:获取一个页面所有包含某个关键词的a标签href属性中的链接,这个用传统的css选择器比较难做到,需要费很大劲,这时候xpath选择器就上场了,不得不说,xpath很强大,非常强大,几乎能获取到页面中想要获取的任何内容,我在这里说几个典型的常用的用法吧,具体如何使用可以参考 xpath教程
###获取页面中所有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表达式是否正确,很有用。


  1. 用选择器获取到元素下内容后的进一步处理
    以获取某个页面 body > p 元素内容后的进一步处理为例:
$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();
});

  • 使用中问题及解决办法:
  1. composer安装了 dom-crawler 后使用不了 xpath选择器,即调用 $crawler->filterXPath('//xxx') 会报错,如何解决?
    解决办法:composer安装 css-selector,php页面引入 CssSelectorConverter
composer require symfony/css-selector  #composer安装
use Symfony\Component\CssSelector\CssSelectorConverter;   #php页面中引入
  1. new Crawler($html) 返回的结果会出现乱码,如何解决?
    解决办法:这个应该与页面编码有关,所以可以采用下面的方式,先初始化crawler,然后添加node。
$crawler = new Crawler();
$crawler->addHtmlContent($html);
  1. 用css选择器的时候,按照上面说的步骤去获取,为什么有时候获取不到,会报错 The current node list is empty,如何解决?
    因为有时候用开发者工具获取的css选择器不太准,比如获取的以下内容:
#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给补上的,但是页面源代码中并没有,所有我们有时候还需要结合页面源代码来分析选择器是否正确。


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,653评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,321评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,833评论 0 324
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,472评论 1 266
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,306评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,274评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,658评论 3 385
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,335评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,638评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,697评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,454评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,311评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,699评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,986评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,254评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,647评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,847评论 2 335

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,709评论 1 92
  • 在线阅读 http://interview.poetries.top[http://interview.poetr...
    程序员poetry阅读 114,117评论 24 450
  • 你是不是也有过一样的经历。 当你面临着一个重要的有难度的考试,但是只有晚上的空闲时间去复习,不知如何是好。你上网一...
    佴悦恺阅读 602评论 0 3
  • 雁南塞北风, 少年鬓霜翁。 不与沽名钓, 独领自骚风。
    墨笔清风_1120阅读 231评论 0 0
  • 郭相麟 人在江湖 有时候的捕风捉影 只是一种 自欺欺人的恐慌 对此 我们需要拥有 质疑的勇气 需要放大思考...
    郭相麟阅读 96评论 0 0