一, 简介
xpath 作为对网页, 对 xml 文件进行定位的工具, 速度快, 语法简洁明了, 在网络爬虫解析内容的过程中起到很大的作用, 除了 xpath 的基础用法之外 (可参考我之前写的(数据科学学习手札 50) 基于 Python 的网络数据采集 - selenium 篇),xpath 中还存在着非常之多的进阶用法, 本文将对笔者日常使用中积累的 xpath 进阶用法进行总结并举例说明:
二, xpath 进阶用法
本文以 http://quotes.toscrape.com / 示例页面, 首先抓取网页源码并利用 etree 解析:
- import requests
- from lxml import etree
- html = requests.get('http://quotes.toscrape.com/')
- tree = etree.HTML(HTML.text)
2.1 获取某一节点的上一级节点
在 xpath 中 /.. 表示向上一级, 这里我们用 xpath 按照下图中的路径提取 a 标签里的内容:
- '''提取页面中符合下列位置规则的所有 keyword'''
- tree.xpath("//meta[@class='keywords']/../a[@class='tag']/text()")
或者利用 parent 来向上一级跳转, 效果是一样的:
- '''提取页面中符合下列位置规则的所有 keyword'''
- tree.xpath("//meta[@class='keywords']/parent::*/a[@class='tag']/text()")
2.2 定位指定属性以某个特定字符开头的标签
在 xpath 中有函数 starts-with(属性名称, 开始字符), 可用于定位指定属性以某个特定字符开头的标签, 如下例, 实现与 2.1 中相同功能:
- '''提取 href 属性以 / tag 开头的 a 标签内容'''
- tree.xpath("//a[starts-with(@href,'/tag')]/text()")
2.3 定位指定属性值包含特定字符片段的标签
在 xpath 中函数 contains(属性名称, 包含字符)可用于定位指定属性值包含特定字符片段的标签内容, 比如我们想要找到所有 text()内容中带有 know 的名人名言, 就可以像下面这样做:
- '''提取 text()内容包含 know 的 span 标签对应的 text()内容'''
- tree.xpath("//span[contains(text(),'know')]/text()")
2.4 匹配具有某属性的所有标签
比如说我们想获取页面中所有的 href 超链接, 就可以用下面的方式:
- '''获取整个页面内所有 href 属性'''
- tree.xpath("//@href")
2.5 同时定位多个内容
比如说我们想在一行代码里同时取得两种不同的规则下匹配的内容, 可以在 xpath 语句中将不同的多个 xpath 语句用 | 连接起来, 最终返回的结果在同一个列表里, 所以使用这种语法时需要考虑取得的内容是否适合放在一起:
- '''同时取得多个定位规则下的内容'''
- tree.xpath("//span[contains(text(),'know')]/text() | //span[contains(text(),'world')]/text()")
2.6 选取指定节点下所有子元素
有时候我们想要快捷的获取某一节点下一级所有标签的某一属性内容, 可以使用 child 来表示下一级节点:
- '''选取 class 为 quote 的 div 节点下所有 span 子节点的 text()内容'''
- tree.xpath("//div[@class='quote']/child::span/text()")
当不指定标签名称而使用 * 代替时, 代表匹配所有子节点:
- '''选取 class 为 quote 的 div 节点下所有子节点的 text()内容'''
- tree.xpath("//div[@class='quote']/child::*/text()")
2.7 选取某一节点所有的属性值
有时候我们想要获取满足条件的节点下所有的属性值:
- '''选取 class 为 quote 的 div 标签下所有的属性值'''
- tree.xpath("//div[@class='quote']/attribute::*")
也可以指定要提取的具体属性值, 如这里我们只提取 href, 只需要将 * 替换成 href 即可:
- '''选取 class 为 tag 的 a 标签下所有的 href 属性值'''
- tree.xpath("//a[@class='tag']/attribute::href")
2.8 定位某一节点的祖先节点
比如我们想要获取 class 为 keywords 的 meta 标签之上所有标签的 class 属性内容, 可以像下面这样:
tree.xpath("//meta[@class='keywords']/ancestor::*/@class")
若想同时包含所有祖先节点及自己本身, 则可使用 ancestor-or-self:
tree.xpath("//meta[@class='keywords']/ancestor-or-self::*/text()")
2.9 定位某一节点的后代节点
类似 2.8, 只不过这里我们来定位某一节点之下的所有后代节点, 使用 descendant:
- '''获取 class 为 tags 的标签下所有后代节点中 a 标签的 href 信息'''
- tree.xpath("//div[@class='tags']/descendant::a/@href")
2.10 条件与或非
在 xpath 中使用逻辑运算来定位的方法如下:
与:
- '''定位 class 为 text 且 itemprop 为 text 的 span 标签'''
- tree.xpath("//span[@class='text'and @itemprop='text']/text()")
或:
tree.xpath("//div[@class='quote'or @class='tags']/@class")
非:
- '''提取所有 span 标签 class 属性不为 text 的 class 属性值'''
- tree.xpath("//span[not(@class='text')]/@class")
2.11 选取指定标签结束之后的所有指定标签
- '''提取所有 class 为 keywords 的 meta 标签结束标签之后出现的标签 a 的 text()内容'''
- tree.xpath("//meta[@class='keywords']/following::a/text()")
- '''选取 body 标签之前的所有标签的 text()内容'''
- tree.xpath("//body/preceding::*/text()")
- '''提取所有 class 为 keywords 的 meta 标签结束标签之后出现的同级别标签 a 的 text()内容'''
- tree.xpath("//meta[@class='keywords']/following-sibling::a/text()")
- '''选取 body 标签之前的所有同级标签的 text()内容'''
- tree.xpath("//body/preceding-sibling::*/text()")
- '''清洗前'''
- tree.xpath("//p[@class='text-muted']/text()")
- '''清洗后'''
- tree.xpath("normalize-space(//p[@class='text-muted']/text())")
- tree.xpath(r"//a[@class='tag'and ns:match(@href,'.*?-.*?page.*?')]/text() | //a[@class='tag'and ns:match(@href,'.*?-.*?page.*?')]/@href",
- namespaces={"ns": "http://exslt.org/regular-expressions"})
来源: http://www.bubuko.com/infodetail-3095019.html