xpath总结
Python包
pip install lxml
在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。XML 文档是被作为节点树来对待的。
xpath语法
/ 代表根路径, 在下面的实例中能够找到/html, 找不到/body
from lxml import etree html = """<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> <li class="item-"><a id='i1' href="link.html">first item</a></li> <li class="item-0"><a id='i2' href="llink.html">first item</a></li> <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li> </ul> <div><a href="llink2.html">second item</a></div> </body> </html> """ page = etree.HTML(html) a = page.xpath("/html") b = page.xpath("/body") print(a) # [<Element html at 0x1e9c3aa4508>] print(b) # []
// 代表任何路径, 在下面的例子中,我们甚至可以选到li标签
from lxml import etree html = """<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> <li class="item-"><a id='i1' href="link.html">first item</a></li> <li class="item-0"><a id='i2' href="llink.html">first item</a></li> <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li> </ul> <div><a href="llink2.html">second item</a></div> <a>我是直属body的</a> </body> </html> """ page = etree.HTML(html) a = page.xpath("//li") print(a)
/可以嵌套使用,如下实例
from lxml import etree html = """<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> <li class="item-"><a id='i1' href="link.html">first item</a></li> <li class="item-0"><a id='i2' href="llink.html">first item</a></li> <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li> </ul> <div><a href="llink2.html">second item</a></div> </body> </html> """ page = etree.HTML(html) a = page.xpath("//a") b = page.xpath("//div/a") print(a) # 他有4个 print(b) # 而div下的只有一个
.和..分别是当前节点和当前节点的父节点
from lxml import etree html = """<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> <li class="item-"><a id='i1' href="link.html">first item</a></li> <li class="item-0"><a id='i2' href="llink.html">first item</a></li> <li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li> </ul> <div><a href="llink2.html">second item</a></div> </body> </html> """ page = etree.HTML(html) a = page.xpath("//ul") print(a[0].xpath("./li")) # 在ul下可以找到3个li print(a[0].xpath("../li")) # 而在ul的父标签下找不到li print(a[0].xpath("../div")) # 但是却可以找到div
66的中括号, 说出来你可能不信. 这个中括号可以根据索引取, 根据属性取, 还不是一般的索引和属性
还是用上面的那个html
a = page.xpath("//li[1]/a/text()") # 取第一个 a = page.xpath("//li[last()]/a/text()") # 取最后一个 a = page.xpath("//li[last()-1]/a/text()") # 取倒数第二个, 减几都行 # 上面是取固定的, 下面是按范围 a = page.xpath("//li[position()<3]/a/text()") # 小于3的前两个 # [@attr] 可以按照属性取值 a = page.xpath("//li[@class]/a/text()") # 这样三个就都取出来了 a = page.xpath("//li[@class='item-0']/a/text()") # 只取出来固定属性的 # 甚至可以按照元素值的大小来查找 ''' <li class="item-"> <count>88</count> <a id='i1' href="link.html">first item</a></li> <li class="item-0"><count>77</count> <a id='i2' href="llink.html">first item2</a></li> <li class="item-1"><count>66</count> <a href="llink2.html">second item<span>vv</span></a></li> ''' a = page.xpath("//li[count>68]/a/text()") # 查询子标签里的count标签里的文本大于68的
[]里还可以放函数
from lxml import etree html = """<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <ul> <li class="item-"> <count>88</count> <a id='i1' href="link.html">first item</a></li> <li class="item-0"><count>77</count> <a id='i2' href="llink.html">first item2</a></li> <li class="item-1"><count>66</count> <a href="llink2.html">second item<span>vv</span></a></li> </ul> <ul> <li class="test-"> <count>88</count> <a id='i1' href="link.html">first item</a></li> <li class="test-0"><count>77</count> <a id='i2' href="llink.html">first item2</a></li> <li class="test-1"><count>66</count> <a href="llink2.html">second item<span>vv</span></a></li> </ul> <div><a href="llink2.html">second item</a></div> </body> </html> """ page = etree.HTML(html) a = page.xpath("//li[starts-with(@class,'test')]/@class") # class以test开头的 print(a) a = page.xpath("//li[contains(@class,'1')]/@class") # class里包含1的 print(a) a = page.xpath("//a[contains(text(),'item2')]/text()") # a标签的内容包含item2的 print(a) # []里的and关系 a = page.xpath("//a[contains(text(),'item2') and @href='llink.html']/text()") print(a)
其中还包括通配符
*表示任意节点,@*表示任何属性, node()表示任意节点
a = page.xpath("//*/a/text()") # 所有的a标签都选出来了, 不管是div下的a还是li下的a a = page.xpath("//*/a[@*]/text()") # 这也是所有a, 你要是不服就把@*换成@id a = page.xpath("//ul/node()") # 里面包括文本节点(换行符之类的)
选取多个路径
a = page.xpath("//ul | //div") # ul或div
轴
轴可定义相对于当前节点的节点集。
语法
轴名称::选择语句
轴名称 | 结果 |
ancestor | 选选取当前节点的所有先辈(父、祖父等)。 |
ancestor-or-self | 选取当前节点的所有先辈(父、祖父等)以及当前节点本身。 |
attribute | 选取当前节点的所有属性。 |
child | 选取当前节点的所有子元素。 |
descendant | 选取当前节点的所有后代元素(子、孙等)。 |
descendant-or-self | 选取当前节点的所有后代元素(子、孙等)以及当前节点本身。 |
namespace | 选取当前节点的所有命名空间节点 |
parent | 选取当前节点的父节点。 |
preceding | 选取文档中当前节点的开始标签之前的所有节点。 |
preceding-sibling | 选取当前节点之前的所有同级节点。 |
self | 选取当前节点。 |
following | 选取文档中当前节点的结束标签之后的所有节点。 |
示例:
就随便来俩吧
a = page.xpath("//ul/child::li") # ul的子标签 a = page.xpath("//ul/li/child::a/attribute::href") # 取到href属性的值
取值
上卖我们一直用text()来取某个标签的文本, 下面来介绍其他几种
通过string取文本
page = etree.HTML(html) a = page.xpath("string(//ul/li)") print(a) a = page.xpath("//ul/li") for i in a: print(i.xpath("string(.)"))
通过@attr取属性
a = page.xpath("//a/@href") print(a)