ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## **解析库-XPath的基本使用(1)** #### **1.XPth常用规则** 表中列举了XPath的几个常用规则。 |名称|参数描述| |:---- |:---| | nodename | 选取此节点的所有子节点 | / |从当前节点选取直接子节点 |//|从当前节点选取子孙节点 |.|选取当前节点 |..|选取当前节点的父节点 |@|选取属性 示例: //title[@lang=' eng'] 这就是一个XPath规则,它代表选择所有名称为title,同时属性lang 的值为eng的节点。 后面会通过Python的lxml库,利用XPath进行HTML的解析。 #### **2.实例** ~~~ from lxml import etree text = ''' <div> <ul> <li class=" item-0"><a href="link1.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 href="link5.html">fifth item</a> </ul> </div> ''' html = etree .HTML(text) #构造XPath 解析对象 #这里我们调用tostring()方法即可输出修正后的HTML代码,但是结果是bytes类型。这里利用decode()方法将其转成str类型,结果如下: result = etree.tostring(html) print(result.decode('utf-8')) ~~~ #### **3.获取所有的节点** ~~~ from lxml import etree text = ''' <div> <ul> <li class=" item-0"><a href="link1.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 href="link5.html">fifth item</a> </ul> </div> ''' html = etree .HTML(text) #构造XPath 解析对象 #这里我们调用tostring()方法即可输出修正后的HTML代码,但是结果是bytes类型。这里利用decode()方法将其转成str类型,结果如下: result = etree.tostring(html) result.decode('utf-8') result = html.xpath(' //*') #匹配所有的节点 print(result) result = html.xpath('//li') #匹配所有的li节点 print(result) ~~~ #### **4.子节点** &nbsp;&nbsp;&nbsp;&nbsp;我们通过/或//即可查找元素的子节点或子孙节点。假如现在想选择li节点的所有直接a子节点, 可以这样实现: ~~~ result = html.xpath('//li/a') print(result) ~~~ 注意:如果使用 ~~~ result = html.xpath('//ul/a') print(result) ~~~ 这样是无法获取任何到输出结果的 #### **5.父节点** &nbsp;&nbsp;&nbsp;&nbsp;我们知道通过连续的/或//可以查找子节点或子孙节点,那么假如我们知道了子节点,怎样来查 找父节点呢?这可以用..来实现。 ~~~ #比如,现在首先选中href 属性为link4.html的a节点,然后再获取其父节点,然后再获取其class属性,相关代码如下: result = html.xpath('//a[@href="link4.html"]/../@class') print(result) 运行结果如下: [' item-1'] ~~~ #### **6.节点属性** &nbsp;&nbsp;&nbsp;&nbsp;在选取的时候,我们还可以用@符号进行属性过滤。比如,这里如果要选取class为item-1 的li 节点,可以这样实现: ~~~ result = html.xpath('//li[@class="item-0"]') print(result) ~~~ &nbsp;&nbsp;&nbsp;&nbsp;这里我们通过加入[@class=" item-0"],限制了节点的class属性为item-0,而HTML文本中符合 条件的li节点有两个,所以结果应该返回两个匹配到的元素。结果如下: [<Element li at 0x10a399288>, <Element li at 0x10a3992c8>] 可见,匹配结果正是两个。 #### **7.文本获取** &nbsp;&nbsp;&nbsp;&nbsp;我们用XPath中的text()方法获取节点中的文本,接下来尝试获取前面li节点中的文本,相关 代码如下: ~~~ result = html .xpath('//li[@class="item-0"]/text()') print(result) 输出结果为: ['\n'] ~~~ 为什么会只匹配一个到换行符??? &nbsp;&nbsp;&nbsp;&nbsp;因为XPath中 text()前面是/,而此处/的含义是选取直接子节点,很明显li的直接子节点都是a节点,文本都是在 a节点内部的,所以这里匹配到的结果就是被修正的li节点内部的换行符,因为自动修正的li节点 的尾标签换行了。 即选中的是这两个节点: ``` <li class=" item-0" ><a href="link1.html">first item</a></li> <li class="item-0"><a href= "link5.html">fifth item</a> ``` 其中一个节点因为自动修正,li节点的尾标签添加的时候换行了,所以提取文本得到的唯一结果 就是li节点的尾标签和a节点的尾标签之间的换行符。 <span style="color:red;">正确的操作方法:</span> ~~~ 因此,如果想获取li节点内部的文本,就有两种方式,一种是先选取a节点再获取文本,另一 种就是使用//。接下来,我们来看下二者的区别。 首先,选取到a节点再获取文本,代码如下: result = html.xpath(' //li[@class="item-0" ]/a/text()') print(result) 运行结果如下: ['first item', 'fifth item'] ~~~ ~~~ 这里我们是逐层选取的,先选取了li节点,又利用/选取了其直接子节点a,然后再选取其文本, 得到的结果恰好是符合我们预期的两个结果。 再来看下用另一种方式(即使用// )选取的结果,代码如下: result = html.xpath('//li[@class="item-0" ]//text()') print(result) 运行结果如下: ['first item', 'fifth item', '\n'] ~~~