【Python3 爬虫】U06_XPath语法和lxml模块

1.什么是XPath?

xpath(XML Path Language)是一门在XML和HTML文档中查找信息的语言,可用来在XML和HTML文档中对元素和属性进行遍历。

2.XPath开发工具

  • Chrome插件XPath Helper(启动快捷键:ctrl + shift + x)
  • Firedox插件Try XPath

3.XPath语法

3.1 选取节点

XPath使用路径表达式来选取XML文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。

表达式 描述 示例 结果
nodename 选取此节点的所有子节点 div 选取div下所有的子节点
/ 如果是在最前面,代表从根节点选取,否则表示选择某个节点下的某个节点 /bookstore 选取根元素下所有的bookstore节点
// 从全局节点中选择节点,随便在哪个位置 //book 从全局节点中找到所有的book节点
@ 选取某个节点的属性 //book[@price] 选择price属性的book节点

3.2 谓词

注意:谓词下标是从1开始的

谓词用来查找某个特定的节点或包含某个指定的值的节点,被嵌在方括号中
在下面的表格中,我们列出了带有谓词的的一些路径表达式,以及表达式的结果:

路径表达式 描述
/bookstore/book[1] 选取bookstore下的第一个子元素
/bookstore/book[last()] 选取bookstore下的倒数第二个book元素
/bookstore/book[position() < 3] 选取bookstore下前面两个子元素
//book[@price] 选取拥有price属性的元素
//nook[@price=10] 选取所有属性price等于10的book元素
//div[contains(@class,'job_detail')] class属性模糊匹配job_detail

3.3 通配符

通配符 描述 示例 结果
* 匹配任意节点 /bookstore/* 选取bookstore下的所有子元素
@* 匹配节点中的任何属性 //book[@*] 选取所有带有属性的book元素

3.4 选取多个路径

通过在路径表达式中使用"|"元素符,可以选取若干个路径
示例如下:

//bookstore/book | //book/title
# 选取所有book元素一级book下所有的title元素

3.4 运算符

运算符 描述 示例 返回值
计算两个节点集 //book
+ 加法 6 + 4 10
2 减法 6 - 4 2
* 乘法 6 * 4 24
div 除法 8 div 4 2
= 等于 price=9.9 如果price是9.9,则返回true。否则返回false
!= 不等于 price!=9.9 如果price是9.9,则返回false。否则返回true
< 小于 price<9.9 如果price小于9.9,则返回true。否则返回false
<= 小于或等于 price<=9.9 如果price小于等于9.9,则返回true。否则返回false
or price=9.9 or price=10 如果price等于9.9或者price等于10,则返回true,否则返回false
and price>9 and price<10 如果price大于9或者price小于10,则返回true,否则返回false
mod 求余数 5 mod 2 1

4.lxml库

lxml是一个HTML/XML的解析器。它的功能是如何解析和提取HTML/XML数据。
lxml和正则一样,使用c实现的,是一款高性能的Python HTML/XML解析器,我们可以利用之前学习的xPath,来快速定位元素以及节点信息。

4.1 基本使用

我们可以利用他来解析HTML代码,并且在解析HTML代码的时候,如果HTML代码不规范,则他会自动补全,实例代码如下:

from lxml import etree

text = """
<div> 
    <ul> 
        <li class="item-1"><a>主页</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>
"""

# 利用etree.HTML,将字符串解析为html文档
html = etree.HTML(text)

# 按字符串序列化HTML文档
result = etree.tostring(html,encoding='utf-8').decode()

print(result)

输出结果如下:

<html><body><div> 
    <ul> 
        <li class="item-1"><a>主页</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>  
    </li></ul> 
</div>
</body></html>

从上述结果可以看到,lxml会自动补全HTML。

4.2 从文件中读取html代码

除了直接使用字符串进行解析,lxml还支持从文件中读取内容,我们新建一个test.html文件,内容如下:

<div> 
    <ul> 
        <li class="item-1"><a>主页</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>

然后利用etree.parse()方法来读取文件。示例代码如下:

from lxml import etree

# 读取文件test.html
parser = etree.HTMLParser(encoding='utf-8') # 不规范的HTML代码则需要指定解析器
html = etree.parse('test.html',parser=parser)
result = etree.tostring(html,encoding='utf-8',pretty_print=True).decode()
print(result)

输出结果如下:

 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html>
  <body>
    <div>&#13;
    <ul>&#13;
        <li class="item-1"><a>主页</a></li>&#13;
        <li class="item-1"><a href="link2.html">second item</a></li>&#13;
        <li class="item-inactive"><a href="link3.html">third item</a></li>&#13;
        <li class="item-1"><a href="link4.html">fourth item</a></li>&#13;
        <li class="item-0"><a href="link5.html">fifth item</a>&#13;
    </li></ul>&#13;
</div>
  </body>
</html>

解析html文件:使用lxml.etree.parse进行解析。这个函数默认使用的是XML解析器,所以如果碰到一些不规范的HTML,代码就会解析,此时就需要自己创建HTML解析器。如:parser = etree.HTMLParser(encoding='utf-8')

5.lxml中使用xPath语法

5.1 获取所有的li标签

from lxml import etree
parser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('test.html',parser=parser)

print(type(html)) # 返回类型

result = html.xpath('//li')
print(result) # 打印<li>标签的元素集合

5.2 获取所有li元素下的所有class属性的值

from lxml import etree
parser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('test.html',parser=parser)

result = html.xpath('//li/@class')
print(result)

5.3 获取li标签下href为link4.html的a标签

from lxml import etree
parser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('test.html',parser=parser)

result = html.xpath('//li/a[@href="link4.html"]')
print(result)

5.4 获取ul标签下所有li标签

from lxml import etree
parser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('test.html',parser=parser)

result = html.xpath('//ul/li')
print(result)

5.5 通过text()获取所有a标签中的值

from lxml import etree
parser = etree.HTMLParser(encoding='utf-8')
html = etree.parse('test.html',parser=parser)

result = html.xpath('//li/a/text()')
print(result)
原文地址:https://www.cnblogs.com/OliverQin/p/12577798.html