当我们使用urllib库或者request库获取到了页面html文件后,我们需要从这些html中获取到我们所需要的数据,这就需要使用数据解析了,今天来讲一讲如何使用Xpath和lxml来进行操作。

思维导图:点击这里

啥是XPath

xpath(XML路径语言)是一门在XML和HTML文档中查找信息的语言,可用于XML和HTML文档中对元素和属性进行遍历。说白了就是我们可以使用xpath来提取我们所需要的元素和属性。

XPath开发工具

在chrome中的应用商店中安装Xpath Helper插件

Xpath语法

官方文档:点击这里

路径选取:

这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似

表达式描述使用方法结果
节点名选取此节点的所有子节点,这里的节点其实就是标签book选取book下面的所有子节点
/如果是在最前面,表示从根节点选取,否则选取某节点下的某个节点(只有一层)/book选取book下面的所有直接子节点
//从全局节点中选取节点(随便在哪一层)//book在全局节点中,找到book
@选取某个节点的属性book[@price]选取包含price属性的book节点
.表示当前节点./a选取当前节点下的a标签
/text()获取文本//div/text()获取div标签下的文本

指定条件(谓语)

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

路径表达式描述
/bookstore/book[1]bookstore下的第一个子元素 (下标从1开始)
/bookstore/book[last()]挑选bookstore下的倒数第二个book元素
bookstore/book[position() < 3]选取bookstore下面前两个子元素
//book[@price]选取拥有price属性的bookstore元素
//book[@price = 10]选取拥有price属性值为10的bookstore元素
//div[contains(@id,'1234')]选取所有属性id中含有1234的div元素(模糊匹配)
//div[stars-with(@id, 'main')]选取所有属性中以main开头的div元素

通配符

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

高级用法

选取一个属性中的多个值:

假如有:<div class = "mp-city-list-container mp-privince-city" mp-role = "privinceCityList">

使用contains:div[contains(@class, "mp-city-list-container mp-privince-city")]

也可以直接选取其属性的第二个值

div[contains(@class, "mp-privince-city")]

使用“|”运算符(vertical bar),当然也可以直接使用or

选取所有bookstore元素以及book元素下的所有title元素

//bookstore/book | //book/title

lxml库

lxml是一个HTML / XML的解析器,主要的功能是如何解析和提取HTML / XML数据。

lxml和正则一样,也是用C实现的,是一种高性能的Python HTML / XML解析器,我们可以利用之前学习的XPath语法,来快速定位特定元素以及信息。

lxml python官方文档:http : //lxml.de/index.html

需要安装C语言库,可使用pip安装:pip install lxml

基本使用:

我们可以使用lxml来解析HTML代码,并且在解析HTML代码的时候,如果HTML代码不规范,比如多一个标签,少一个标签,他会自动帮我们补全,示例代码:

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">第四项</a></li>  
            <li class="item-0"><a href="link5.html">第五项</a>  
            </ul>  
</div>  
"""   
#利用 etree.HTML,将字符串解析为 HTML 文档   
httpElement = etree.HTML(text)   
print(type(httpElement))   # 看看httpElemet是什么类型
# 按字符串序列化 HTML 文档   
print(etree.tostring(httpElement, encoding='utf-8').decode('utf-8'))

可以看出,lxml会自动修改html代码,例子中不仅补全了li标签,还添加了body,html标签

从文件中读取html代码:

除了直接使用字符串来进行解析,lxml还支持从文件中读取内容,示例代码如下:

from lxml import etree
parser = etree.HTMLParser(encoding = 'utf-8') #使用html的解析器来解析html,默认是xml
htmlElement = etree.parse('result.html', parser = parser)  #第一个参数指定文件,第二个参数指定解析器,如果第二个参数为空,则默认指定xml的解析器
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))

在lxml中使用XPath语法

基本思路是,首先将html源码转换成_Element对象,然后使用xpath方法来进行解析。我们以上上面的html源码为例,来尝试写几个常用的需求,这几个常用的搞懂了,基本可以应付99%的场景。

源码:

<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">第四项</a></li>  
            <li class="item-0"><a href="link5.html">第五项</a>  
            </ul>  
</div>  

任务:

有以下几点要注意:

  1. requests 返回的 response 对象我们要先取其 text,然后使用 etree.HTML(text)将其生 成 htmlElement 对象,这个对象可以使用 xpath 方法
  2. html.xpath( ‘这里写 xpath 的语法一定别忘了引号’ )
  3. html.xpath()返回的一定是列表,因此一定别忘了如果只取一个元素也要加[0]
  4. 尽量不要在 xpath 的语法中使用位置,一般我们可以先取出全部的元素在列表中后 再从列表里面取。


立志成为一名攻城狮