Xpath介绍
xpath是XML路径语言,它可以用来确定xml文档中的元素位置,通过元素路径来完成对元素的查找。xpath是一种非常强大的定位方式。
- xml是一种可扩展标记语法的文本格式,xpath可以方便的定位xml中的元素和其他属性值。lxml是python中的一个第三方模块,它包含了将html文本转成xml对象,和对对象执行xpath的功能
- Xpath(XML Path Language)是一种xml的查询语言,他能在xml树状结构中寻找节点。Xpath用于在xml文档中通过元素和属性进行导航
HTML树状结构图
HMTL的结构就是树形结构,HTML是根节点,所有的其他元素节点都是从根节点发出的。其他的元素都是这棵树上的节点,每个节点还可能有属性和文本。而路径就是指某个节点到另一个节点的路线。
节点之间的关系
- 父节点(Parent) :HTML是body和head节点的父节点;
- 子节点(Child) :head和body是HTML的子节点;
- 兄弟节点(Sibling) :拥有相同的父节点,head和body就是兄弟节点。title和div不是兄弟节点,因为他们不是同一个父节点;
- 祖先节点(Ancestor) :body是form的祖先节点,爷爷辈及以上;
- 后代节点(Descendant) :form是HTML的后代节点,孙子辈及以下。
Xpath中的绝对路径与相对路径
Xpath中的绝对路径从HTML根节点开始算,相对路径从任意节点开始。通过开发者工具,我们可以拷贝到 Xpath 的绝对路径和相对路径代码:
虽然绝对路径相比之下看起来更加直观,清楚,但是相对路径却更加简便
绝对路径
Xpath 中最直观的定位策略就是绝对路径。
以百度中的输入框和按钮为例,通过拷贝出来的 full Xpath:
/html/body/div[2]/div[1]/div[5]/div/div/form/span[1]/input
绝对路径是从根节点/html开始往下,一层层的表示出来直到需要的节点为止.如果页面元素层级较多,绝对路径明显不是一个明智的选择。
相对路径
除了绝对路径,Xpath 中更常用的方式是相对路径定位方法,以“//”开头。相对路径可以从任意节点开始,一般我们会选取一个可以唯一定位到的元素开始写,可以增加查找的准确性。
//*[@id="kw"]
相对路径定位语法
| 表达式 | 说明 | 举例 |
|---|---|---|
| / | 从根节点开始选取 | /html/div/span |
| // | 从任意节点开始选取 | //input |
| . | 选取当前节点 | |
| .. | 选取当前节点的父节点 | //input/.. 会选取 input 的父节点 |
| @ | 选取属性或者根据属性选取 | //input[@data] 选取具备 data 属性的 input 元素 //@data 选取所有 data 属性 |
| * | 通配符,表示任意节点或任意属性 |
Xpath定位表达式
1.根据层级进行定位
# 从根节点开始定位
/html/body/form/div
# 从任意节点开始选取
//form/div
2.根据属性进行定位
# 属性定位是通过 @ 符号指定需要使用的属性。
# class属性定位
//form/span[@class="soutu"]
# ID属性定位
//input[@id="su"]
3.使用谓语定位
谓语用来查找某个特定的节点或者包含某个指定的值的节点。谓语嵌在中括号里[]
主要有数字下标、last()、position()。
注意:Xpath 中的下标从1开始。
# 元素下标定位
//form[@id="form"]/span[2]
定位到form标签下的第二个span标签
//form[@id="form"]/span[last()]
定位到form标签下的最后一个span标签
//form[@id="form"]/span[last()-1]
定位到form下的倒数第二个span标签
//form[@id="form"]/span[position()=2]
定位到from 下第二个span标签
//form[@id="form"]/span[position()<2]
定位到form下的 下标大于 2 的span标签
4.使用部分匹配函数定位(类似于模糊查询)
| 函数 | 说明 | 举例 |
|---|---|---|
| contains | 选取属性或者文本包含某些字符 | //div[contains(@id, 'data')] 选取 id 属性包含 data 的 div 元素 |
| starts-with | 选取属性或者文本以某些字符开头 | //div[starts-with(@id, 'data')] 选取 id 属性以 data 开头的 div 元素 |
| ends-with | 选取属性或者文本以某些字符结尾 | //div[ends-with(@id, 'require')] 选取 id 属性以 require 结尾的 div 元素 |
Xpath实战
import requests
from lxml import etree
def get_response(url):
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
}
response = requests.get(url,headers=headers)
return response.text
# with open('链家.html','w',encoding='utf-8')as f:
# f.write(response)
#
# data = open('链家.html','r',encoding='utf-8').read()
# 根据响应的网页 解析数据
def get_data(data):
# 获取树形结构 把html转换成etree对象
html = etree.HTML(data)
# {title:标题,position:位置,info:信息,price:总价}
# [{},{},{}]
list_info = []
for horse in html.xpath('//div[@class="info clear"]'):
dict_info = {}
# 标题
title = horse.xpath('./div[1]/a/text()')[0]
# 位置
position = '-'.join(horse.xpath('./div[2]/div/a/text()'))
# 信息
info = horse.xpath('./div[3]/div/text()')[0]
# 总价
price = horse.xpath('./div[6]/div[1]/span/text()')[0] + '万'
# 单价
unitPrice = horse.xpath('./div[6]/div[2]/span/text()')[0]
# print(unitPrice)
dict_info['title'] = title
dict_info['position'] = position
dict_info['info'] = info
dict_info['price'] = price
dict_info['unitPrice'] = unitPrice
list_info.append(dict_info)
return list_info
def sava_data(list_info,i):
with open(f'第{i}页.txt','w',encoding='utf-8')as f:
f.write(str(list_info))
if __name__ == '__main__':
num = 10
for i in range(1,num+1):
print('-------------------di{}页数据'.format(i))
url = 'https://cs.lianjia.com/ershoufang/pg{}/'.format(i)
data = get_response(url)
list_info = get_data(data)
# 存储
sava_data(list_info,i)