数据解析: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 元素的节点集
or price=9.80 or price=9.70 如果 price 是 9.80,则返回 true。如果 price 是 9.50,则返回 false。
and price>9.00 and price<9.90 如果 price 是 9.80,则返回 true。如果 price 是 8.50,则返回 false。
mod 计算除法的余数(取余) 5 mod 2 结果是 1

其他

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

功能函数

函数 用法 解释
starts-with xpath(’//div[starts-with(@id, “ma”)]’) 选取id值以ma开头的div节点
contains xpath(’//div[contains(@id, “ma”)]’) 选取id值包含ma的div节点
and xpath(’//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 itema>li>
         <li class="item-1"><a href="link2.html">second itema>li>
         <li class="item-inactive"><a href="link3.html">third itema>li>
         <li class="item-1"><a href="link4.html">fourth itema>li>
         <li class="item-0"><a href="link5.html">fifth itema>
         
     ul>
 div>



<html><body><div>
     <ul>
         <li class="item-0"><a href="link1.html">first itema>li>
         <li class="item-1"><a href="link2.html">second itema>li>
         <li class="item-inactive"><a href="link3.html">third itema>li>
         <li class="item-1"><a href="link4.html">fourth itema>li>
         <li class="item-0"><a href="link5.html">fifth itema>
         
     li>ul>
div>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标签里的文本    

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&keywords=&tid=87&lid=0">22989-腾讯云web前端高级工程师a>td>
					<td>技术类td>
					<td>2td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45567&keywords=&tid=87&lid=0">21882-腾讯医典Android开发工程师(深圳)a>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45566&keywords=&tid=87&lid=0">21882-腾讯医典IOS开发工程师(深圳)a>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45555&keywords=&tid=87&lid=0">18427-理财通后台开发工程师a><span class="hot"> span>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45545&keywords=&tid=87&lid=0">TEG13-高级系统测试工程师(深圳)a>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45547&keywords=&tid=87&lid=0">SD9-手游客户端开发工程师(深圳)a><span class="hot"> span>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45554&keywords=&tid=87&lid=0">PCG04-PCG研发部前端架构师(深圳)a>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45544&keywords=&tid=87&lid=0">PCG17-QQ钱包客户端开发(深圳)a>td>
					<td>技术类td>
					<td>1td>
					<td>深圳td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="even">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45534&keywords=&tid=87&lid=0">22989-高级AI后台开发工程师(上海/深圳)a>td>
					<td>技术类td>
					<td>2td>
					<td>上海td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="odd">
		    		<td class="l square"><a target="_blank" href="position_detail.php?id=45535&keywords=&tid=87&lid=0">22989-高级AI前端研发工程师(上海/深圳)a>td>
					<td>技术类td>
					<td>2td>
					<td>上海td>
					<td>2018-11-11td>
		    	tr>
		    			    	<tr class="f">
		    		<td colspan="5">
		    			<div class="left"><span class="lightblue total">1379span>个职位div>
		    			<div class="right"><div class="pagenav"><a href="javascript:;" class="noactive" id="prev">上一页a><a class="active" href="javascript:;">1a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=10#a">2a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=20#a">3a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=30#a">4a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=40#a">5a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=50#a">6a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=60#a">7a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=70#a">...a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=1370#a">138a><a href="position.php?lid=&tid=87&keywords=请输入关键词&start=10#a" id="next">下一页a><div class="clr">div>div>div>
		    			<div class="clr">div>
		    		td>
		    	tr>
		    tbody>table>

你可能感兴趣的:(网络爬虫,python,html,css,js,java)