数据解析:xpath(xml)的使用,大白话总结、常用语法、及一些小细节

大概介绍

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

XML文档中的节点跟HTML是一样的,用xpath来解析网页数据是非常合适的。

浏览器xpath插件

Chrome插件XPath Helper
Firefox插件Try XPath

使用//标签名 获取整个页面当中的某个节点元素,然后通过子节点、属性、谓词进行提取。

'//div[@class="abc"]'

/和//的区别

/如果是在最前面,代表从根节点选取,否则选择某节点下的节点。

/代表只获取直接子节点,//是获取子孙节点。

'//div[@class="abc"]/a[2]'   表示在整个页面(根节点)寻找class="abc"的div标签下的第二个a标签

匹配不包含某属性的元素

'/p[not(@*)]'            不包含任何属性
'//div/a[not(@class)]'   不包含class属性

详细使用讲解

相关文档

  1. xpath介绍

  2. 关于xml的介绍

  3. xml-dom-节点

语法

XPath使用路径表达式来选取XML文档中的节点或节点集。
节点是通过沿着路径(path)或者步(steps)来选取的。

选取节点
表达式作用
nodename选取此节点的所有子节点。
/从根节点选取。
//从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
.选取当前节点。
选取当前节点的父节点。
@选取某个节点的属性。
例子说明
bookstore选取bookstore元素下的所有子节点。
/bookstore选取根元素下所有的bookstore节点;注:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book选取属于bookstore的子元素的所有book元素。
//book选取所有book节点,而不管它们在文档中的位置。
bookstore//book选择属于bookstore元素的后代的所有book元素,而不管它们位于bookstore之下的什么位置。
//@lang选取名为lang的所有属性。
./a选取当前节点下的a标签。
谓语

谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。

表达式说明
/bookstore/book[1]选取bookstore下的第一个book子元素。
/bookstore/book[last()]选取属于bookstore子元素的最后一个book元素。
/bookstore/book[last()-1]选取bookstore下的倒数第二个book子元素。
/bookstore/book[position() < 3]选取bookstore下前面两个book子元素。
//book[@price]选取所有拥有price属性的book元素。
//book[@price=10]选取所有属性price等于10的book元素。
/bookstore/book[price>35.00]选取bookstore元素的所有book元素,且其中的price元素的值须大于35.00。
/bookstore/book[price>35.00]/title选取bookstore元素中的book元素的所有title元素,且其中的price元素的值须大于35.00。

注意:谓词中的下标是从1开始的,不是从0开始的

选取未知节点 通配符
例子说明
*匹配任意元素节点。
@*匹配节点中的任何属性节点(只要带有属性的节点都会被匹配)。
node()匹配任何类型的节点。
/bookstore/*选取bookstore元素下的所有子元素。
//*选取文档中的所有元素。
//book[@*]选取所有带有属性的book元素。
选取若干路径 选取多个路径

通过在路径表达式中使用“|”运算符,可以选取若干个路径。

例子说明
//bookstore/book | //book/title选取所有book元素以及book元素下所有的title元素。
//title | //price选取文档中的所有title和price元素。
/bookstore/book/title | //price选取属于bookstore元素的book元素的所有title元素,以及文档中所有的price元素。

运算符

XPath 表达式可返回节点集、字符串、逻辑值以及数字。

多个属性条件可以用'//div[@属性1="" and 属性2=""]'这种方式
属性还可以用 = != > < 这种运算符,具体可以参考一些文档

'//tr[position()>1 and position()<12]'      获取第2个到第12个tr标签
运算符作用例子说明
|计算两个节点集//book | //cd返回所有拥有 book 和 cd 元素的节点集
orprice=9.80 or price=9.70如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。
andprice>9.00 and price<9.90如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。
mod计算除法的余数(取余)5 mod 2结果是 1

其他

+ - * div(除法) = != < <= > >=

功能函数

函数用法解释
starts-withxpath(’//div[starts-with(@id, “ma”)]’)选取id值以ma开头的div节点
containsxpath(’//div[contains(@id, “ma”)]’)选取id值包含ma的div节点
andxpath(’//div[contains(@id, “ma”) and contains(@id, “in”)]’)选取id值包含ma和in的div节点
text()xpath(’//div[contains(text(), “ma”)]’)选取节点文本包含ma的div节点

contains

某个元素的属性包含了多个值,可以使用contains函数(模糊匹配)

例如在网页中某标签的属性:class=“job_detail container gclearfix”

用xpath匹配:

'//div[contains(@class, "job_detail")]'
# 或者
'//div[contains(@class, "container gclearfix")]'
# 都可以匹配到

text()

在selenium中使用find_element_by_xpath() 这种方法时,经常会无法使用text()
selenium以定位为主,需要获取网页中文本、标签属性值以及一些元素时,可以先定位到标签上,再用etree解析

selenium之后会讲到


使用lxml解析HTML代码

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

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

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

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

1、解析html字符串:使用’lxml.etree.HTML’进行解析

我们可以利用它来解析HTML代码,并且在解析HTML代码的时候,如果HTML代码不规范,会自动进行补全。

<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>
         <!--注意,此处缺少一个 </li> 闭合标签-->
     </ul>
 </div>

<!--解析后-->

<html><body><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>
         <!--注意,此处缺少一个 </li> 闭合标签-->
     </li></ul>
</div></body></html>

<!--不仅补全了li标签,还添加了body、html标签-->

2、解析html文件:使用’lxml.eterr.parse’进行解析

除了直接使用字符串进行解析,lxml还支持从文件中读取内容。

这个方法默认使用的是’XML’解析器,如果碰到一些不规范的html代码 会出现解析错误,这时就要自己创建-定义html解析器

from lxml import etree   # 引入模块

parser = etree.HTMLParser(encoding='utf-8')
# .parse默认是xml解析器,所以要自己定义解析器,防止遇到不规范的html代码导致解析错误

html = etree.parse('tencent.html', parser=parser)
# 返回的是etree对象,之后的操作都可以通过html.操作
# 解析文件用.parse(),如果解析网页返回的html或者粘贴到python代码里的字符串,用.HTML()

print(etree.tostring(html, encoding='utf-8').decode('utf-8'))  # 解码
# 通过tostring方法可以把解析后的HTML文档 按字符串序列化,不解码是字节数据

解析结果也是经过规范化的,会自动加上一些标准的HTML标签

案例

  1. 获取所有tr标签
trs = html.xpath('//tr')
print(trs)
for tr in trs:
# xpath返回的是一个列表,这里需要遍历并使用tostring方法,指定编码格式 解码
    print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))
  1. 获取第二个tr标签
tr = html.xpath('//tr[2]')[0]
print(tr)
print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))

tr[2]表示只取第二个tr标签,[2]是谓词。
因为xpath返回的是个列表,后面加个[0]相当于直接把它匹配到的第一个值取出来了:取零。
因为需要匹配的结果只有一个,只需要第一个符合条件的;所以可以用这种取零方式直接取值。
html代码里是已经确定有要查找的tr标签,所以这里不用担心列表越界

  1. 获取所有class等于even的tr标签
trs = html.xpath('//tr[@class="even"]')
for tr in trs:
    print(etree.tostring(tr, encoding='utf-8').decode('utf-8'))
  1. 获取所有a标签的href属性
aList = html.xpath('//a[@target="_blank" and @href]')
for a in aList:
    print(etree.tostring(a, encoding='utf-8').decode('utf-8'))
'''
用[]是代表获取拥有某个属性的某个标签
用/或者//是直接取出某个标签下某个属性所对应的值
'''
aList = html.xpath('//a[@target="_blank"]/@href')
for a in aList:
    print('https://hr.tencent.com/' + a)
# 这里不需要指定编码格式再解码了,因为获取到的是字符串(href里面的url链接)
  1. 获取所有的职位信息(纯文本)
# trs = html.xpath('//tr[position()>1 and @class!="f"]')
'''position()是设置tr标签出现位置,设置需要取的范围'''
# trs = html.xpath('//tr[position()>1 and position()<12]')
trs = html.xpath('//tr[@class!="h" and @class!="f"]')
positions = []
for tr in trs:
    # 在某个标签下,再次执行xpath函数,获取这个标签下的子孙元素
    # 应该在//或/前面加.,代表是在当前元素下获取,不加.的话就会在整个网页代码寻找匹配的标签
    href = tr.xpath('.//a/@href')[0]  # 两个斜杠//代表获取子孙节点(在整个tr标签下查找a标签)
    url = 'https://hr.tencent.com/' + href
    title = tr.xpath('./td[1]//text()')[0]
    category = tr.xpath('./td[2]/text()')[0]
    nums = tr.xpath('./td[3]/text()')[0]
    address = tr.xpath('./td[4]/text()')[0]
    # time = tr.xpath('./td[5]/text()')[0]
    time = tr.xpath('./td[5]')[0].text
    '''
    td标签是在tr标签子节点的,所以一个斜杠即可./td[1]代表获取第一个
    .text和text()可以拿到标签里面的文本
    '''

    position = {
        'url': url,
        '职位': title,
        '分类': category,
        '工作经验': nums,
        '地区': address,
        '发布时间': time
    }
    positions.append(position)

print(positions)

总结:

lxml结合xpath注意事项:

  1. 使用xpath语法,应该使用Element.xpath方法,来执行xpath的选择
    Element是英文元素的意思。xpath返回的结果永远是一个列表
如:html.xpath('//tr[position()>1]')
  1. 获取某个标签的属性:用/或者//这种路径方式,不要用[],[]匹配到的是整个标签代码

  2. 获取标签里面文本是通过xpath中的text()方法,文本指的是:<开始标签> 这里的文本 </结束标签>

如:<a>a标签里的文本</a>    <h1>h1标签里文本</h1> ...
  1. 在某个标签下,再次执行xpath函数,获取这个标签下的子元素或子孙元素,应该在//或/前面加“.”,代表是在当前元素下获取,不加“.”的话就会在整个网页代码寻找匹配的标签



案例中的html文件

<table class="tablelist" cellpadding="0" cellspacing="0">
		    	<tbody><tr class="h">
		    		<td class="l" width="374">职位名称</td>
		    		<td>职位类别</td>
		    		<td>人数</td>
		    		<td>地点</td>
		    		<td>发布时间</td>
		    	</tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45570&amp;keywords=&amp;tid=87&amp;lid=0">22989-腾讯云web前端高级工程师</a></td>
					<td>技术类</td>
					<td>2</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45567&amp;keywords=&amp;tid=87&amp;lid=0">21882-腾讯医典Android开发工程师(深圳)</a></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45566&amp;keywords=&amp;tid=87&amp;lid=0">21882-腾讯医典IOS开发工程师(深圳)</a></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45555&amp;keywords=&amp;tid=87&amp;lid=0">18427-理财通后台开发工程师</a><span class="hot">&nbsp;</span></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45545&amp;keywords=&amp;tid=87&amp;lid=0">TEG13-高级系统测试工程师(深圳)</a></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45547&amp;keywords=&amp;tid=87&amp;lid=0">SD9-手游客户端开发工程师(深圳)</a><span class="hot">&nbsp;</span></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45554&amp;keywords=&amp;tid=87&amp;lid=0">PCG04-PCG研发部前端架构师(深圳)</a></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45544&amp;keywords=&amp;tid=87&amp;lid=0">PCG17-QQ钱包客户端开发(深圳)</a></td>
					<td>技术类</td>
					<td>1</td>
					<td>深圳</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45534&amp;keywords=&amp;tid=87&amp;lid=0">22989-高级AI后台开发工程师(上海/深圳)</a></td>
					<td>技术类</td>
					<td>2</td>
					<td>上海</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45535&amp;keywords=&amp;tid=87&amp;lid=0">22989-高级AI前端研发工程师(上海/深圳)</a></td>
					<td>技术类</td>
					<td>2</td>
					<td>上海</td>
					<td>2018-11-11</td>
		    	</tr>
		    			    	<tr class="f">
		    		<td colspan="5">
		    			<div class="left"><span class="lightblue total">1379</span>个职位</div>
		    			<div class="right"><div class="pagenav"><a href="javascript:;" class="noactive" id="prev">上一页</a><a class="active" href="javascript:;">1</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=10#a">2</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=20#a">3</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=30#a">4</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=40#a">5</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=50#a">6</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=60#a">7</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=70#a">...</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=1370#a">138</a><a href="position.php?lid=&amp;tid=87&amp;keywords=请输入关键词&amp;start=10#a" id="next">下一页</a><div class="clr"></div></div></div>
		    			<div class="clr"></div>
		    		</td>
		    	</tr>
		    </tbody></table>
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值