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()

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

  • 需要的内容 1
  • 需要的内容 2
  • 需要的内容 3
  • 想同时爬取时,不需要构造多个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(.)

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

    需要的内容 1

    需要的内容2

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

    from lxml import etree
    html2 = '''
    
    需要的内容 1

    需要的内容2

    ''' selector = etree.HTML(html2) content1 = selector.xpath('//div[@class="red"]')[0] content2 = content1.xpath('string(.)') print(content2) #string(.)方法可用于标签套标签情况
    image

    你可能感兴趣的:(Xpath语法)