对于网页的节点来说,定义id,class或其他属性。而且节点之间还有层级关系,在网页中通过XPath或CSS选择器来定位一个或多个节点,对于这种解析库非常多,其中比较强大的库有lmxl,Beautiful Soup、pyquery等,

目录

XPath概览

XPath常用规则

也可以使用文本解析

所有的节点

子节点

父节点

属性匹配

文本获取

属性获取

属性多值匹配

多属性匹配

按顺序选择

节点轴选择


XPath概览

XPath,全程XML Path Language ,即XML语言,它是一门在XML文档中查找信息的语言。它最初是用来搜寻XML文档的,但是它同样适用于HTML文档的搜索

XPath的选择功能十分强大,它提供了非常简介明了的路径选择表达式,另外,他还提供了超过100个内建函数,用于字符串、数值、时间的匹配以及节点、序列的处理等。几乎所有我们想要定位的节点,都可以用XPath来选择。

XPath与1999年11月16日成为W3C标准,他被设计为供XSTL、XPointer以及其他XML解析软件使用,更多的文档可以访问其官方网站:https://www.w3.org/TR/xpath/

XPath常用规则

表达式 描述
nodename 选取此节点的所有子节点
从当前节点选取直接子节点
//  从当前节点选取子孙节点
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

这里列出了XPath的常用匹配规则,示例://title[@lang='eng']   
选择所有名称为title,同时属性的值为eng的节点

from lxml import etreetext = """
<div>
<ul>
<li class="item-O"><a href="linkl. html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class ="item-0"><a hrer="link5.html">fifth item</a>
</ul>
</div>"""htlm = etree.HTML(text)
result = etree.tostring(htlm)
print(result.decode("utf-8"))结果:
<html><body><div>
<ul>
<li class="item-O"><a href="linkl. html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class=""><a hrer="">fifth item</a>
</li></ul>
</div></body></html>

首先导入lxml库的etree模块,然后声明一段HTML文本,调用HTML类进行初始化,这杨就构成了一共XPath解析对象,这里需要主义的是,HTML文本中的最后一共li节点是没有闭合的,但是etree模块可以自动修正HTML文本。我们调用totstring() 方法输出即可修正后的HTML代码,但是结果是bytes类型。利用decode()方法将其转成str类型

也可以使用文本解析

from lxml import etreehtml = etree.parse('./test.html',etree.HTMLParser())
resutl = etree.tostring(html)
print(resutl.decode("utf-8"))结果:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body><div>
<ul>
<li class="item-O"><a href="linkl. html">first item</a></li>
<li class="item-1"><a href="link2.html">second item</a></li>
<li class="item-inactive"><a href="link3.html">third item</a></li>
<li class="item-1"><a href="link4.html">fourth item</a></li>
<li class="item-0"><a hrer="link5.html">fifth item</a>
</li></ul>
</div></body></html>

这次的输出结果略有不同,多了一个DOCTYPE的声明,不过对解析无任何影响

所有的节点

一般会用//开头的XPath规则来选取所有符合要求的节点。这里以前面的HTML文本为例

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//*")
print(result)结果:
[<Element html at 0x1bc5238>, <Element body at 0x1bc5210>, <Element div at 0x1bc51e8>, <Element ul at 0x1bc51c0>, <Element li at 0x1bc1eb8>, <Element a at 0x1bc1cb0>, <Element li at 0x1bc1cd8>, <Element a at 0x1bc1d00>, <Element li at 0x1bc1ad0>, <Element a at 0x1bc1aa8>, <Element li at 0x1bc1940>, <Element a at 0x1bc1918>, <Element li at 0x1bc16e8>, <Element a at 0x1bc16c0>]

这里我们获取的是所有节点,也就是整个HTML文本中的所有节点都会被获取,以列表形式返回,每个元素是Element元素,后面跟着节点名称:如html,body,div,ul,li,a等

也可以通过节点来获取://li   如果是要其中的一个对象也是可以加上索引

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li")
print(result)结果
[<Element li at 0x2035210>, <Element li at 0x20351e8>, <Element li at 0x20351c0>, <Element li at 0x2031eb8>, <Element li at 0x2031cb0>]

子节点

通过//或/ 即可查找元素的子节点或子孙节点。举例:选择li节点的所有直接a子节点

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li/a")
print(result)结果:
[<Element a at 0x1c451e8>, <Element a at 0x1c451c0>, <Element a at 0x1c45198>, <Element a at 0x1c41e90>, <Element a at 0x1c41cb0>]

通过追加/a即选择了所有li节点的所有直接a子节点。因为//li用户选择所有li节点,/a用户选中li节点的所有直接子节点a,二者组合在一起即获取所有li节点的所有直接a子节点

此处/ 用户选取直接子节点,如果要获取所有子孙节点,就可以使用//,例如:要获取ul 节点下的所有子孙节点

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//ul//a")
print(result)结果:
[<Element a at 0x1755238>, <Element a at 0x1755210>, <Element a at 0x17551e8>, <Element a at 0x1751ee0>, <Element a at 0x1751cd8>]

运行结果是相同的

获取//ul/a,就无法获取任何结果了,因为/用户获取直接子节点,而在ul节点下没有直接的a子节点,只有li节点,所有无法获取任何匹配结果

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//ul/a")
print(result)结果
[]

/ 用户获取直接子节点, // 用户获取子孙节点

父节点

通过连续的 / 或 // 可以查找子节点或子孙节点,那么加入我们直到了子节点,怎么来找父节点?

通过href属性为link4.html 的a 节点,然后再获取其父节点,然后再获取class属性

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//a[@href='link3.html']/../@class")
print(result)结果:
['item-inactive']

同时我们可以是通过 parent:: 来获取父节点

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//a[@href='link3.html']/parent::*/@class")
print(result)结果:
['item-inactive']

属性匹配

我们可以使用@符号进行属性过滤。比如,这里如果要选取class 为 item-0 的节点

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[@class='item-0']")
print(result)结果:
[<Element li at 0x22251c0>, <Element li at 0x2225198>]

限制了节点的class属性为item-0,而HTML文本中符合条件的li节点有两个,所以结果应该返回两个匹配到的元素,至于是不是正确的两个,后面再验证

文本获取

XPath中的text()  方法获取节点中的文本,获取li节点中的文本

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[@class='item-0']/text()")
print(result)结果:
['\r\n']

我们发现并没有获取到任何文本,值获取到了一个换行符?因为XPath中text() 前面是 / ,而此处 / 的含义是选取直接子节点,很明显li的直接子节点都是a节点,文本都是在a节点内部的,所以这里匹配到的结果就是被修正的li节点的内部的换行符,自动修正的li节点的尾标签换行了

匹配选中的是这两个节点:

<li class="item-0"><a href="linkl.html">first item</a></li>
<li class="item-0"><a hrer="link5.html">fifth item</a>
</li>

最后一个节点因为自动修正,li节点的尾标签添加的时候换行了,所以提取文本得到的唯一结果就是li节点的尾标签和a节点的尾部标签之间的换行符

所以获取li内部的文本:1、先选取a节点在获取文本,2、另外一种就是使用 //

选取a节点再获取文本

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[@class='item-0']/a/text()")
print(result)结果:
['first item', 'fifth item']

另外一种使用 //

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[@class='item-0']//text()")
print(result)结果:
['first item', 'fifth item', '\r\n']

这里返回的是三个结果,这里是选取所有子孙节点的文本,其中前两个就是li节点的子节点a节点内部的文本,另外一个就是最后一个li节点内部的文本,即换行符

如果要想获取子孙节点内部的所有文本,可以直接用 // 加 text () 的方式,这样可以保证 获取到最全面的文本信息,但是可能会夹杂一些换行符等特殊字符 如果想获取某些特定子孙节点下 的所有文本,可以先选取到特定的子孙节点,然后再调用 text() 方法获取其内部文本,这样可以保证获取的结果是整洁的

属性获取

使用@符号就可以获取到:获取所有li节点下所有节点的href属性

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li/a/@href")
print(result)结果:
['linkl.html', 'link2.html', 'link3.html', 'link4.html']

这里我们通过@href 即可获取节点的 href 属性。注意,此处和属性匹配的方法不同,属性匹配 中括号加属性名和值来限定某个属性,如[@href="linkl.html ”],而此处的@href 指的是获取节点的某 个属性,二者需要做好区分

属性多值匹配

有时候,某些节点的某个属性可能有多个值,HTML 文本中 li 节点的 class 属性有两个值 li li-first ,此时如果还想用之前的属性匹配获取,就无法匹配了

这个时候就需要contains() 函数

from lxml import etreetext = '<li class="li li-frist"><a href="link2.html">second item</a></li>'# html = etree.parse("./test.html",etree.HTMLParser())
html = etree.HTML(text)
result = html.xpath("//li[contains(@class,'li')]/a/text()")
print(result)结果:
['second item']

通过contains()  方法,第一个参数传入属性名称,第二个传入属性值,只要此属性包含所传入的属性值,就可以完成匹配

多属性匹配

另外,我们可能还遇到一种情况,那就是根据多个属性确定一个节点,这时就需要同时匹配多个 属性 此时可以使用运算符 and 来连接

from lxml import etreetext = '<li class="li li-frist" name="item"><a href="link2.html">second item</a></li>'html = etree.HTML(text)
result = html.xpath("//li[contains(@class,'li') and @name='item']/a/text()")
print(result)结果:
['second item']

li 节点又增加了一个属性 name 要确定这个节点,需要同时根据 class和name 属性来选择,一个条件是 class 属性里面包含 li 字符串,另一个条件是 name 属性为 item 字符串,二者需要同 时满足,需要用 and 作符相连,相连之后置于中括号内进行条件筛选

除了and还是其他XPath中运算符

按顺序选择

在选择的时候某些属性可能同时匹配了多个节点,但是只想要其中的某个节点,如 第二个节点或者最后一个节点,我们可以利用中括号传入索引的方法获取特定次序

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[1]/a/text()")
print(result)
result =html.xpath("//li[last()]/a/text()")
print(result)
result =html.xpath("//li[position()<3]/a/text()")
print(result)
result =html.xpath("//li[last()-2]/a/text()")
print(result)结果:
['first item']
['fifth item']
['first item', 'second item']
['third item']

选取了第一个 li 节点,中括号中传入数字1 即可, 注意,这里和代码中不 同,序号是以 1开头的,不是以 0开头;

选取了最后一个 li 节点,中括号中传入 last() 即可,返回的便是最后 一个 li 节点;

选取了位置小于 li 节点,也就是位置序号为1和2 的节点,得到的结果就是前两个 li 节点;

选取了倒数第三个 li 节点,中括号中传入 last()-2 即可。 因为 last() 是最后一个,所以 last()-2 就是倒数第三个;

这里我们使用了 last ()、 position ()等函数 XPat 中,提供了 100 多个函数,包括存取 值、字符串、逻辑、节点、序列等处理功能,它们的具体作用可以参考:w3school 在线教程

节点轴选择

XPath 提供了很多节点轴选择方法,包括获取子元素 、兄弟元素、父元素、祖先元素等,

from lxml import etreehtml = etree.parse("./test.html",etree.HTMLParser())
result = html.xpath("//li[1]/ancestor::*")
print(result)
result =html.xpath("//li[1]/ancestor::div")
print(result)
result =html.xpath("//li[1]/attribute::*")
print(result)
result =html.xpath("//li[1]/child::a[@href='link1.html']")
print(result)
result =html.xpath("//li[1]/descendant::span")
print(result)
result =html.xpath("//li[1]/following::*[2]")
print(result)
result =html.xpath("//li[1]/following-sibling::*")
print(result)结果:
[<Element html at 0x1525238>, <Element body at 0x15251e8>, <Element div at 0x15251c0>, <Element ul at 0x1522eb8>]
[<Element div at 0x15251c0>]
['item-0']
[<Element a at 0x15251e8>]
[]
[<Element a at 0x1525210>]
[<Element li at 0x15251e8>, <Element li at 0x15251c0>, <Element li at 0x1522eb8>, <Element li at 0x1522cb0>]
ancestor::*  调用ancestor轴:可以获取所有祖先节点,其后需要跟着两个冒号,然后是节点的选择器,这里我们直接使用* 表示匹配所有节点,因此返回结果是第一个li节点的所有祖先节点,包括html、 body、 div、 ul。ancestor::div  调用ancestor轴,又加了限定条件,这次在冒号后面加了 div ,这样得到的结果就只有 div 个祖先节点了
attribute::*   调用了attribute轴,可以获取所有属性值,其后跟的选择器还是*,这代表获取节点的所有属性,返回值就是 li 节点的所有属性值
child::a[@href='link1.html']  调用child 轴,可以获取所有直接子节点 这里我们又加了限定条件,选取 href 属性为 linkl.html 的 a 节点
descendant::span  调用了descendant 轴,可以获取所有子孙节点 这里我们又加了限定条件获 span 节点,所以返回的结果只包含 span 节点而不包含 a 节点
following::*[2]  调用 following 轴,可以获取当前节点之后的所有节点, 这里我们虽然使用的是*匹配,但又加了索引选择,所以只获取了第二个后续节点
following-sibling::* 调用 following -sibling ,可以获取当前节点之后的所有同级节点这 里我们使用*匹配,所以获取了所有后续同级节点

爬虫:Xpath定位相关推荐

  1. Python - 爬虫 - Xpath定位之starts-with()和string()函数的简单使用

    Python - 爬虫 - Xpath定位之starts-with()和string()函数的简单使用 文章目录 Python - 爬虫 - Xpath定位之starts-with()和string( ...

  2. 从入门到入土:Python爬虫学习|实例练手|爬取百度产品列表|Xpath定位标签爬取|代码注释详解

    此博客仅用于记录个人学习进度,学识浅薄,若有错误观点欢迎评论区指出.欢迎各位前来交流.(部分材料来源网络,若有侵权,立即删除) 本人博客所有文章纯属学习之用,不涉及商业利益.不合适引用,自当删除! 若 ...

  3. python xpath定位元素方法_Python爬虫杂记 - Xpath高级用法

    xpath 高级用法 1. 匹配当前节点下的所有: .// . 表示当前 // 表示当前标签下的所有标签 注: 要配合使用 2. 匹配某标签的属性值: /@属性名称 这里以input里的value值为 ...

  4. python xpath定位 嵌套标签_python爬虫中使用Xpath方法定位a标签中所有的子标签的方法...

    老板扔给了我一个陈年语料,让我通过文章标题回原网址爬取一下对应的doi号,文章很好定位,但是在解析标题的时候遇到了问题,a标签中混合了i.sub.sup标签,在使用xpath时不能直接使用text方法 ...

  5. python xpath定位打印元素_python基础教程:8种selenium元素定位的实现

    前言 selenium是一个非常厉害的爬虫利器,不,简直是神器了,它可以自动的控制浏览器,但是你得告诉浏览器,你想干嘛,爬哪里,这时候就要用到元素定位了,在HTML中都有着不同的标签和属性,selen ...

  6. Python爬虫——XPath的使用

    Python爬虫--XPath的使用 使用实例一:获取需要的文字 1.导入需要使用的模块 import urllib.request from lxml import etree 2.发送请求访问网站 ...

  7. Python 爬虫 xpath 数据解析基本用法

    Python 爬虫 xpath 数据解析基本用法 1. 基本语法 1.1 解析 html 语法 1.2 获取标签 1.3 获取标签中的内容 1.4 获取标签中的属性 1.5 通过内容寻找结点 2. 实 ...

  8. XPath定位语法总结

    XPath介绍 XPath(XML Path Language)是一门解析XML文档的语言,可在XML文档中对元素和属性进行遍历.因为XML和HTML语法类似,所以,XPath广泛用于解析HTML文档 ...

  9. pythonxpath定位_一文搞懂 XPath 定位

    一文搞懂XPath 定位 XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历. XPath定位在爬虫和自动化测试中 ...

  10. python xpath定位不到_Xpath定位方法深入探讨及元素定位失败常见情况

    一.Xpath定位方法深入探讨 (1)常用的Xpath定位方法及其特点 使用绝对路径定位元素. 例如: driver.findElement(By.xpath("/html/body/div ...

最新文章

  1. Elasticsearch 参考指南(脚本)
  2. java 暂停多线程_关于java中多线程的暂停
  3. Vue学习(一)-邂逅Vuejs
  4. 运算服务器v9型号,v9云服务器
  5. 微信公众号发多个消息php,微擎系统微信公众号关键字触发回复多条消息实现
  6. 深入理解Java:内省(Introspector)
  7. 人工操作阶段计算机是如何工作的,管理信息系统作业参考答案
  8. Forefront TMG 2010 篇(二)--安装
  9. java遍历hashMap、hashSet、Hashtable
  10. hdoj--5621--KK's Point(简单数学)
  11. 解决Ubuntu下VNC客户端无法输入s和m的方法
  12. python3.x编程模板总结
  13. TTF字体文件内容获取
  14. openssl 加盐_nodejs-md5加盐到解密比对
  15. Swagger怎么下载文件
  16. 本篇文章带你秒懂——区块链到底是什么鬼?
  17. 证券公司信息化1-证券行业的本质是什么?什么是资本市场?什么又是一级市场和二级市场?
  18. 自我检查,看清自己 看清自己什么皮肤。
  19. 广东迅视资管 新媒介在文艺领域的影响:如墨汁滴入水中氤氲开来
  20. stm32毕业设计 单片机遥控小车

热门文章

  1. APS系统的现状以及与MES系统的关联
  2. mybatis-sqlserver批量新增返回id
  3. 21考研:你是为了什么考研?
  4. java-集合框架库-LinkedList
  5. 从上帝视角看进程调度
  6. linux zip和gzip的区别
  7. 8.4 向量应用(二)——空间直线
  8. linux模拟蓝牙播放器,为 Ubuntu Linux 开启蓝牙 APTX / LDAC 支持
  9. python获取年末,月末,季末的日期和距指定时间的天数
  10. KALI attack 实验室