Xpath入门到精通与案例详解
文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、Xpath介绍
● XPath(XML Path Language)是一种XML的查询语言,他能在XML树状结构中寻找节点。XPath 用于在 XML 文档中通过元素和属性进行导航
● xml是一种标记语法的文本格式,xpath可以方便的定位xml中的元素和其中的属性值。lxml是python中的一个第三方模块,它包含了将html文本转成xml对象,和对对象执行xpath的功能
1、结点的关系
xml_content = '''
<bookstore>
<book>
<title lang='eng'>Harry Potter</title>
<author>JK.Rowing</author>
<year>2005</year>
<price>29<price>
</book>
</bookstore>
'''
● 父(Parent) book元素是title、author、year、price元素的父
● 子(Children) title、author、year、price都是book元素的子
● 同胞(Sibling) title、author、year、price都是同胞
● 先辈(Ancestor) title元素的先辈是 book元素和bookstore元素
2、为什么学习Xpath
正则比较复杂,根据不同网页结构 灵活的选择解析方法
3、Xpath原理
X path根据路径找到数据的技术
xml path language
html是xml的一个子集
根据元素和属性进行导航
二、Xpath工具使用
xpath入门测试一
from lxml import etree
xml_content = '''
<html>
<head>
<title>Harry Potter</title>
</head>
<body>
<li class="author">JK.Rowing</li>
<li class="year">2005</li>
<li class="price">29</li>
<div>
<li class="book">harry potter</li>
</div>
<span>
<li class="price">29</li>
<div>
<li class="book">harry potter</li>
</div>
</span>
</body>
</html>
'''
tree = etree.HTML(xml_content)
# /表示层级关系 第一个/是根节点
bookstore_html = tree.xpath('/html')
# print(bookstore_html)
# text()获取文本内容的
title_html = tree.xpath('/html/head/title/text()')
# print(title_html)
# [0]把列表里面的数据取出
tit_html = tree.xpath('/html/head/title/text()')[0]
# print(author_html)
li_html = tree.xpath('/html/body/li/text()')
# [<Element li at 0x1f6b74c5488>, <Element li at 0x1f6b76fa3c8>, <Element li at 0x1f6b76fa448>]
# ['JK.Rowing', '2005', '29']
# print(li_html)
div_html = tree.xpath('/html/body/div/li/text()')
# print(div_html)
# //用于查找节点内部所有的子节点(后代)
li_div = tree.xpath('/html/body//li/text()')
# print(li_div)
div_li = tree.xpath('/html/body/div/li/text()')
# print(div_li)
span_li = tree.xpath('/html/body/span//li/text()')
# print(span_li)
# *可用匹配任意节点,看作一种通配符
div_span_li = tree.xpath('/html/body/*/li/text()')
print(div_span_li)
xpath入门测试二
from lxml import etree
# 网页源代码
html = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test2</title>
</head>
<body>
<div id="songs-list">
<h2 class="title">经典老歌</h2>
<p class="introduction">经典老歌列表</p>
<ul id="list" class="list-group">
<li><a href="/1.mp3" singer="任贤齐">沧海一声笑</a></li>
<li><a href="/2.mp3" singer="齐秦">往事随风</a></li>
<li><a href="/3.mp3" singer="beyond">光辉岁月</a></li>
<li><a href="/4.mp3" singer="陈慧琳">记事本</a></li>
<li><a href="/5.mp3" singer="邓丽君">但愿人长久</a></li>
</ul>
</div>
</body>
</html>
'''
tree = etree.HTML(html)
a_result = tree.xpath('/html/body/div/ul/li/a/text()')
# print(a_result)
# 一般用于没有属性值,或者说属性值重复 不太方便定位属性的就会使用位置定位
# 通过节点位置进行定位,定位到某些节点
# 节点下标从1开始
b_result = tree.xpath('/html/body/div/ul/li[1]/a/text()')
# print(b_result)
# 列表下标从零开始
c_result = tree.xpath('/html/body/div/ul/li/a/text()')[0]
# # print(c_result)
# 通过节点里面的属性值定位到具体的节点
d_result = tree.xpath('/html/body/div/ul/li/a[@href="/1.mp3"]/text()')
# print(d_result)
# 找到ul下面所有的li节点
e_result = tree.xpath('/html/body/div/ul/li')
# print(e_result)
for li in e_result:
# print(li)
# . 表示在当前li节点的基础上
# xpath 一般是把符合xpath语句的数据 放在列表里面统一返回
li_result = li.xpath('./a/text()')
# print(li_result)
# @href 用于获取属性值
a_href = li.xpath('./a/@href')
print(a_href)
三、Xpath语句介绍
符号 | 作用 |
---|---|
/ | 从根节点选取 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置 |
. | 选取当前节点 |
… | 选取当前节点的父节点 |
@ | 选取属性 |
* | 可用匹配任意节点,匹配当前节点下的任意节点,简单理解为通配符 |
text() | 获取当前选取节点的数据 |
位置定位
tree.xpath('')[列表下标]#通过列表下标定位
tree.xpath('/html/body/li[节点下标]')#通过节点下标定位
tree.xpath('/html/body/li[last()]')#选取最后一个
tree.xpath('/html/body/li[last()-1]')#选取倒数第二个
tree.xpath('/html/body/li/a[属性名=""]')#通过属性值筛选数据
四、lxml模块
lxml介绍
lxml 是 一个HTML/XML的解析器,主要的功能是如何解析和提取HTML/XML数据利用etree.HTML,将字符串转化为Element对象
lxml python 官方文档:http://lxml.de/index.html
可使用 pip 安装:pip install lxml
lxml 可以⾃动修正 html 代码
lxml下载
第三方模块 需要安装
pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simple
lxml的使用
使用:
1、代码导入etree: from lxml import etree
2、发请求 获得相应 拿到网页源代码(html)
3、tree = etree.HTML(html)
4、找数据:title = tree.xpath(xxxxx)
5、保存数据(csv)
五、豆瓣–案例详解
豆瓣案例–网址与需求
https://movie.douban.com/top250
爬取需求:详情页的url、图片的url、标题、评分、评价人数、引言
页面分析
一部影片的数据是放在一个li节点下面
这些所有li节点都是放在ol[class=“grid_view”]节点下面
详情页的url:先找到class="pic"的div节点下面的一个a节点 里面有一个href属性 放的是详情页的url
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[1]/a
标题,图片的url:先找到class="pic"的div节点下面的一个a节点,在a节点下面有一个img节点 里面能通过alt属性获得标题,src可以获得img的url
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[1]/a/img
评分:是class="rating_num"的span节点里面的文本
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[2]/div[2]/div/span[2]
评价人数:class="star"的div节点 再往下找到最后一个span节点 里面有评价人数
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[2]/div[2]/div/span[4]
引言:通过class="inq"的span节点获取引言
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[2]/div[2]/p[2]/span
翻页
翻页:
https://movie.douban.com/top250?start=0&filter= 第一页
https://movie.douban.com/top250?start=25&filter= 第二页
https://movie.douban.com/top250?start=50&filter= 第三页
动态更替start能够实现翻页 增长基数为25
代码演示
import time
from lxml import etree
import csv
import requests
# # 目标url
# url = "https://movie.douban.com/top250"
# # 请求头
# header = {
# "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
# "Chrome/97.0.4692.99 Safari/537.36 "
# }
"""
页面分析:
一部影片的数据是放在一个li节点下面
这些所有li节点都是放在ol节点下面grid_view
详情页的url:先找到class="pic"的div节点下面的一个a节点 里面有一个href属性 放的是详情页的url
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[1]/a
标题,图片的url:先找到class="pic"的div节点下面的一个a节点,在a节点下面有一个img节点 里面能通过alt属性获得标题,src可以获得img的url
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[1]/a/img
评分:是class="rating_num"的span节点里面的文本
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[2]/div[2]/div/span[2]
评价人数:class="star"的div节点 再往下找到最后一个span节点 里面有评价人数
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[2]/div[2]/div/span[4]
引言:通过class="inq"的span节点获取引言
/html/body/div[3]/div[1]/div/div[1]/ol/li[1]/div/div[2]/div[2]/p[2]/span
"""
"""
翻页:
https://movie.douban.com/top250?start=0&filter= 第一页
https://movie.douban.com/top250?start=25&filter= 第二页
https://movie.douban.com/top250?start=50&filter= 第三页
动态更替start能够实现翻页 增长基数为25
"""
class DoubanMovie():
def __init__(self):
header = ['排名', "详情页url", "图片url", "标题", "评分", "评价人数", "引言"]
self.file_obj = open('movie.csv', 'w', encoding='utf-8', newline='')
# 1、创建csv对象
self.Dictwrite = csv.DictWriter(self.file_obj, header)
# 2、写入表头
self.Dictwrite.writeheader()
def get_html(self, url, header):
res_obj = requests.get(url, headers=header)
html = res_obj.text
# print(html)
return html
def parse_data(self, html):
# 把网页源码加载成element对象 赋值给tree
tree = etree.HTML(html)
li_list = tree.xpath('//ol[@class="grid_view"]/li')
for li in li_list:
item = {}
# print(li)
# 基于已经找到的li节点继续往下
item['排名'] = li.xpath('.//div[@class="pic"]/em/text()')[0]
item['详情页url'] = li.xpath('.//div[@class="pic"]/a/@href')[0]
item['图片url'] = li.xpath('.//div[@class="pic"]/a/img/@src')[0]
item['标题'] = li.xpath('.//div[@class="pic"]/a/img/@alt')[0]
item['评分'] = li.xpath('.//span[@class="rating_num"]/text()')[0]
item['评价人数'] = li.xpath('.//div[@class="star"]/span/text()')[-1]
item['引言'] = li.xpath('.//span[@class="inq"]/text()')[0]
print(item)
try:
item['inq'] = li.xpath('.//span[@class="inq"]/text()')[0]
except:
item['inq'] = ''
print(item)
self.save_data(item)
def save_data(self, item):
self.Dictwrite.writerow(item)
def main(self):
# 目标url
url = "https://movie.douban.com/top250?start=0&filter="
# 请求头
header = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/97.0.4692.99 Safari/537.36 "
}
# 处理翻页
for i in range(5):
# 1、i=0
# 2、i=1
print("正在爬取第{}页数据".format(i + 1))
next_url = url.format(i * 25)
html = self.get_html(next_url, header)
self.parse_data(html)
time.sleep(2)
self.file_obj.close()
if __name__ == '__main__':
douban = DoubanMovie()
douban.main()