Xpath语法

Xpath是一门在XML文档中查找信息的语言,对HTML文档也有很好的支持。

1 节点选择

Xpath使用路径表达式在XML文档中选取节点。节点是通过沿着路径或者step来选取的。

表达式 描述 示例 注释
nodename 选取此节点的所有子节点 xpath(‘//div’) 选取div节点的所有子节点
/ 从根节点选取 xpath(‘/div’) 从根节点上选取div节点
// 选取所有的当前节点,不考虑他们的位置 xpath(‘//div’) 选取所有的div节点
. 选取当前节点 xpath(‘./div’) 选取当前节点下的div节点
.. 选取当前节点的父节点 xpath(‘..’) 回到上一个节点
@ 选取属性 xpath(’//@calss’) 选取所有的class属性

2 谓语

Xpath语法中的谓语用来查找某个特定的节点或者包含某个指定值的节点,谓语被嵌在方括号中。常见的谓语如下:

表达式 结果
xpath(‘/body/div[1]’) 选取body下的第一个div节点
xpath(‘/body/div[last()]’) 选取body下最后一个div节点
xpath(‘/body/div[last()-1]’) 选取body下倒数第二个div节点
xpath(‘/body/div[positon()<3]’) 选取body下前两个div节点
xpath(‘/body/div[@class]’) 选取body下带有class属性的div节点
xpath(‘/body/div[@class=”main”]’) 选取body下class属性为main的div节点
xpath(‘/body/div[price>35.00]’) 选取body下price元素值大于35的div节点

3 通配符

Xpath中也可以使用通配符来选取位置的元素,常用的就是“ * ” 通配符,它可以匹配任何元素节点。

表达式 结果
xpath(’/div/*’) 选取div下的所有子节点
xpath(‘/div[@*]’) 选取所有带属性的div节点

4 取多个路径

使用“|”运算符可以同时选取多个路径

表达式 结果
xpath(‘//div|//table’) 选取所有的div和table节点

5 Xpath轴

轴可以定义相对于当前节点的节点集。

轴名称 表达式 描述
ancestor xpath(‘./ancestor::*’) 选取当前节点的所有先辈节点(父、祖父)
ancestor-or-self xpath(‘./ancestor-or-self::*’) 选取当前节点的所有先辈节点以及节点本身
attribute xpath(‘./attribute::*’) 选取当前节点的所有属性
child xpath(‘./child::*’) 返回当前节点的所有子节点
descendant xpath(‘./descendant::*’) 返回当前节点的所有后代节点(子节点、孙节点)
following xpath(‘./following::*’) 选取文档中当前节点结束标签后的所有节点
following-sibing xpath(‘./following-sibing::*’) 选取当前节点之后的兄弟节点
parent xpath(‘./parent::*’) 选取当前节点的父节点
preceding xpath(‘./preceding::*’) 选取文档中当前节点开始标签前的所有节点
preceding-sibling xpath(‘./preceding-sibling::*’) 选取当前节点之前的兄弟节点
self xpath(‘./self::*’) 选取当前节点

6 功能函数

使用功能函数能够更好的进行模糊搜索。

函数 用法 解释
starts-with xpath(‘//div[starts-with(@id,”ma”)]‘) 选取id值以ma开头的div节点
contains xpath(‘//div[contains(@id,”ma”)]‘) 选取id值包含ma的div节点
and xpath(‘//div[contains(@id,”ma”) and contains(@id,”in”)]‘) 选取id值包含ma和in的div节点
text() xpath(‘//div[contains(text(),”ma”)]‘) 选取节点文本包含ma的div节点

7 xpath使用技巧

在爬虫实战中,Xpath路径也可以通过浏览器复制得到,同selector选择器中介绍的方法。

当需要进行批量爬取时,类似于BeautifulSoup中的selector()方法删除谓语部分不可行的。这时的思路为“先抓大后抓小,寻找循环点”。以从糗事百科的网站爬取用户id为例,打开浏览器进行“检查”,通过“三角形符号”折叠元素,找到每个段子完整的信息标签。

(1)首先通过复制构造div标签路径,此时的路径为:

 'div[@class="article block untagged mb15"]'

这样就定位到了每个段子信息,这就是“循环点”。

(2)通过谷歌浏览器进行“检查”定位用户ID,复制Xpath到记事本中:

//*[@id="qiushi_tag_121251148"]/div[1]/a[2]/h2

因为第一部分为循环部分,将其删除得到:

 div[1]/a[2]/h2

这便是用户ID的信息。

完整获取用户ID的代码如下:

import requests
from lxml import etree

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

url = 'https://www.qiushibaike.com/text/'
r = requests.get(url, headers=headers)
selector = etree.HTML(r.text)
url_infos = selector.xpath('//div[@class="article block untagged mb15"]')       
for url_info in url_infos:
    user_id = url_info.xpath('div[1]/a[2]/h2/text()')[0]        #尾部加上text()获取文本
    print(user_id)
image

starts-with()

有时候会遇到相同的字符开头的多个标签:

<li class="tag-1">需要的内容 1</li>

<li class="tag-2">需要的内容 2</li>

<li class="tag-3">需要的内容 3</li>

想同时爬取时,不需要构造多个Xpath路径,通过starts-with()便可获取多个便签内容,接上例,目前糗事百科按上例的方法已经行不通了,看下图:

image

可以发现在 **article block untagged mb15 **的后面增加了typs_long、typs_hot、typs_old等,还按上例那样是匹配不到标签的,这时候就可以用到starts-with(),来提取属性类似的标签信息。

代码改变如下:

import requests
from lxml import etree

headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 \
(KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}

url = 'http://www.qiushibaike.com/text'
r = requests.get(url, headers=headers)
selector = etree.HTML(r.text)
url_infos = selector.xpath('//div[starts-with(@class,"article block untagged mb15")]')
for url_info in url_infos:
    try:
        user_id = url_info.xpath('div[1]/a[2]/h2/text()')[0]        #尾部加上text()获取文本
    except IndexError:
        user_id = '匿名用户'            #此处遇到匿名用户会抛出IndexError
    print(user_id)

string(.)

当遇到标签套标签情况时:

<div class="red">需要的内容 1
        <h1>需要的内容2</h1>
</div>

想同时爬取文本内容,可以通过string(.)完成:

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

推荐阅读更多精彩内容