XPATH、CSS选择器及正则表达式

在爬虫采集数据的过程中,如何定位及匹配数据是必须解决的一项任务。最常用的定位方式有三种:XPATH,CSS选择器及正则表达式。以下我们来系统的学习他们。

一、XPATH 语法

参考文档:XPATH教程 from runoob

1. Xpath是什么

XPath是一个W3C标准,可以供XSLT、XPointer以及其他XML解析软件使用;它包含一个标准函数库;使用路径表达式在XML文档中进行导航。在爬虫学习中,我们最需要了解的就是最后一项:如何使用XPath路径表达式进行导航。在此之前,首先让我们学习下XPath的基本概念之一:节点。

2. XPath节点及相关

XPath中有七种类型的节点:元素,属性,文本,命名空间,处理指令,注释以及文档(根)节点。除了节点之外,还有基本值(Atomic value)的概念。

基本值:无父或无子的节点。从定义上看,基本值是一种特殊节点,常见于文本。

项目(Item):基本值或者节点。

XML是被作为文档树来对待的,也因此会涉及根节点、父子节点等概念,下面让我们总结下节点关系。

3. XPath节点关系

父(Parent): 每个元素或属性都有一个父,即其直接上级节点。

子(Children):元素节点可以有0、1或多个子,即其直接下级节点。

兄弟(Sibling):拥有相同的父的节点或节点集合。

先辈(Ancestor):某节点的父,父的父,以此类推十八代(虚指)。

后代(Descendant):某节点的子,子的子,以此类推。

了解了基本概念,接下来是语法。

4. XPath语法

4.1 节点选取

nodename 选取当前节点的所有nodename子节点;

/ 从根节点选取,即绝对路径;

// 从当前节点选取,即相对路径;

. 选取当前节点;

.. 选取当前节点的父节点;

@ 选取属性。

4.2 谓语(Predicates)

结合实例解释如下:

/bookstore/book[1] 选取bookstore子元素的第一个book元素;

/bookstore/book[last()] 选取bookstore子元素的最后一个book元素;

/bookstore/book[position()<3] 选取bookstore元素的前两个book元素;

*之前提到XPath中包含一个标准函数库;last()和position()就是其中常见的例子。

//title[@lang] 选取拥有lang属性的title元素;

//title[@lang='eng'] 选取lang属性为'eng'的title元素;

/bookstore/book[price>35.00] 选取bookstore元素中的所有book元素,且其中的price元素大于35.00。

4.3 通配符

* 匹配任何元素节点; @*匹配任何属性节点;node()匹配任何类型的节点。

4.4 路径组合

//book/title | //book/price 选取book元素的所有title和price元素。

之前我们介绍了节点关系的概念,那么如何利用节点关系来定位节点呢,请看XPath轴。

5. XPath轴(Axes)

ancestor 选取当前节点的所有先辈;

ancestor-or-self 选取当前节点及其所有先辈;

descendant 选取当前节点的所有后辈;

descendant-or-self 选取当前节点及其所有后辈;

parent 选取当前节点的父节点;

child 选取当前节点的子节点;

following 选取当前节点之后的所有节点;

following-sibling 选取当前节点之后的所有兄弟节点;

preceding 选取当前节点之前的所有节点;

preceding-sibling 选取当前节点之前的所有兄弟节点;

self 选取当前节点;

attribute 选取当前节点所有属性;

namespace 选取当前节点的所有命名空间节点。

用法,比如要查找<a>元素之后的<span>元素,使用'//a/following::span'。

6. XPath运算符

| 计算两个节点集;

+ - * div mod加减乘除求余;

= != < <= > >= 比较;

or and 或与。

二、CSS选择器语法

参考资料:CSS选择器 from w3school

在定位元素时,CSS选择器和XPath经常可以相互替代。常用的CSS选择器如下:

.class 根据class属性选择元素;

#id 根据id属性选择元素;

* 选择所有元素;

element 选择所有element元素;

element,element1 选择所有element及element1元素;

element element1 选择element内部的所有element1元素;

element>element1 选择element的element1子元素;

element+element1 选择紧接在element之后的element1元素;

[attribute] 选择带有attribute属性的所有元素;

[attribute=value] 选择attribute属性值为value的所有元素;

[attribute~=value] 选择attribute属性值包含value的所有元素;

[attribute|=value] 选择attribute属性值以value开头的所有元素;

a:link 选择所有未被访问的链接;a:visited 选择所有已被访问链接;a:hover 选择活动链接;

element:focus 选择获得焦点的element元素;

element:first-letter 选择element元素首字母;element:first-line 选择element元素首行;

element:first-child 选择属于element父元素的第一个子元素的每个element元素;

element:lang(language) 选择带有以language开头的lang属性值得每个element元素;

ele1~ele2 选择前面有ele1元素的每个ele2元素;

ele[attribute^=value] 选择attribute属性值以value开头的每个ele元素;

ele[attribute$=value] 选择attribute属性值以value结尾的每个ele元素;

ele[attribute*=value] 选择attribute属性值包含value的每个ele元素;

ele:first-of-type 选择属于其父元素的首个ele元素的每个ele元素;

ele:last-of-type 选择属于其父元素的最后ele元素的每个ele元素;

ele:only-of-type 选择属于其父元素唯一的ele元素的每个ele元素;

ele:only-child 选择属于其父元素的唯一子元素的每个ele元素;

ele:nth-child(n) 选择属于其父元素的第n个子元素的每个ele元素;

ele:nth-last-child(n) 选择属于其父元素的倒数第n个子元素的每个ele元素;

ele:nth-of-type(n) 选择属于其父元素的第n个元素的每个ele元素;

ele:nth-last-of-type(n) 选择属于其父元素的倒数第n个元素的每个ele元素;

ele:last-child 选择属于其父元素最后一个子元素的每个ele元素;

:root 选择文档根元素;

ele:empty 选择没有子元素的每个ele元素;

ele:target 选择当前活动的ele元素;

ele:enabled 选择每个启用的ele元素;ele:disabled 选择每个禁用的ele元素;

ele:checked 选择每个被选中的ele元素;

:not(selector) 选择非selector的每个元素;

::selection 选择被用户选取的元素部分。

三、正则表达式语法

参考教程:正则表达式 from runoob

当我们使用word或text之类的办公软件时,经常用到搜索和筛选来定位查找词语。这个功能很便利,但是它的不足之处也很明显。其中之一就是:作为过滤器的模式非常有限。相比之下,正则表达式可以实现前者的所有工作,而且更加强大和灵活。下面让我来看看,它是如何做到这一点的。

1. 正则表达式记号

普通字符 大小写字母,所有数字,所有标点和一些其他字符(如非打印字符)。

非打印字符 

\cx 匹配由x指明的控制字符;x的值必须为A-Za-z之一;否则c将被视为字母c;

\f 匹配换页符;\n 匹配换行符;\r 匹配回车符; \s 匹配任何空白字符,包括空格、制表符、换页符等;\S 匹配任何非空白字符;\t 匹配任何制表符;\v 匹配垂直制表符。

特殊字符

^ 匹配开始位置,在方括号中时,表示否定,即不接受该字符集合;$ 匹配结尾位置;

* 匹配前面的子表达式0或多次; + 匹配前面的子表达式1或多次;

? 匹配前面的子表达式0或1次,或指定一个非贪婪限定符;

. 匹配除换行符\n之外的任何单字符;

\ 转义字符;

| 指明两项之间的其中一个。

() 标记一个子表达式的开始和结束位置。子表达式可以获得,供以后使用;

[] 标记一个中括号表达式的开始;

{ } 标记限定符表达式的开始;

限定符

* + ? 见特殊字符

{n} 匹配确定的n次;{n,} 至少匹配n次;{n,m} 匹配n到m次。

定位符

^ $ 见特殊字符

\b 匹配字边界(字与空格间的位置);\B 非字符边界

子表达式

前面提到,()可以标记一个子表达式,且该表达式可以被捕获缓存。如果这并不是你想要的,那么可以使用?:消除这种副作用,即将子表达式标记为非捕获元。

除此之外,还有另外两个很重要的非捕获元?=和?!,前者称为正向预查,后者称为反向预查。两者还经常被称为零宽断言(正向、反向);此外还有逆序正向预查和逆序反向预查。

正向预查(?=exp) a. 当单词同时满足前部匹配条件和exp时,返回前部匹配; b. exp非捕获

举例: \b\w+(?=ing\b)  输入 singing and dancing 输出 sing和danc

反向预查(?!exp) a. 当单词满足前部匹配条件且不满足exp时,返回前部匹配,b. exp非捕获

逆序正向预查(?<=exp) a. 当单词同时满足exp和后部匹配条件时,返回后部匹配;b. exp非捕获;

逆序反向预查(?<!exp) a. 当单词不满足exp且满足后部匹配条件时,返回后部匹配;b. exp非捕获;

*名字很拗口,可以这么理解:正向、反向指的是要匹配的字符是在前面还是后面;正序、逆序指的是肯定还是否定子表达式。

引用

每个被捕获的子表达式都会存储在缓冲区,且被编号为1-99。每个缓冲区可以通过\n来访问,其中n为标识特定缓冲区的一位或两位十进制数。最简单,最有用的应用为查找文本中两个相同的相邻单词。

2. 元字符

\ ^ $ * + ? {n} {n,} {n,m} (pattern) (?:pattern) (?=pattern) (?!pattern) x|y [xyz] [^xyz] [a-z] [^a-z]

\b \B \cx \f \n \r \s \S \t \v

以上这些已经介绍过了,下面再看些常用的元字符。

\d 匹配一个数字字符,即[0-9];\D 匹配一个非数字字符;

\w 匹配包括下划线的任何单词字符,即[A-Za-z0-9];

\W 匹配任何非单词字符;

\xn 匹配n,其中n为十六进制,必须为确定的两个数字;

\num 如果前面至少num个被捕获子表达式,则表示引用;否则,如果num为0-7的数字,则匹配八进制;

\un 匹配n,其中n是四个十六进制数字表示的字符。

了解了这么多的符号和运算,很容易想到一个问题,这些运算符的优先级是怎么样的?

3. 运算符优先级

优先级从高到低为:

\ 转义符;

(),[] 子表达式和中括号表达式;

*,+,?,{} 限定符;

^,$,\任何元字符,任何字符 定位点和普通字符;

| 选择。

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

推荐阅读更多精彩内容