Python学习第二十三天

数据解析

主要的作用是解析HTML、XML,urllib是用来爬取数据我们将数据爬取后,我们需要将爬取的数据部分进行解析功能。

分类:xpath、jsonpath、bs4(beautiful soup)

xpath

官网概念

xpath没有官网是由一些社区维护发布的、官网目前可以认定为W3C(万维网)在维护,也可以通过其他的学习网站进行学习。

安装

bash 复制代码
# lxml支持了xpath
pip install lxml

作用

  • 主要用于 XML 和 HTML 文档的节点定位。

  • 语法强大,支持复杂的查询和条件过滤。

  • 适用于需要精确查找的场景。

使用

python 复制代码
from lxml import etree
# 解析本地文件 如果报错 需要看下meta是否有结尾 检查自己的html中是不是有没有结尾的<meta charset="utf-8" /> 注意必须要有结尾/>
tree = etree.parse('test_xpath.html')
# 用法
# /	从根节点开始选取
value = tree.xpath("/html/body/ul/li")
print(f"/从根节点开始选取:{value}") # [<Element li at 0x22cf8c3df80>, <Element li at 0x22cf8c3dfc0>, <Element li at 0x22cf8c3e000>]
# //从当前节点开始,递归选取所有匹配的节点,无论它们在文档中的位置
value = tree.xpath("//ul")
print(f"//从当前节点开始,递归选取所有匹配的节点,无论它们在文档中的位置:{value}") # [<Element ul at 0x23ccd56dc40>]
# .	选取当前节点
value = tree.xpath(".")
print(f".选取当前节点:{value}") # [<Element html at 0x19bff2afcc0>]
# ..	选取当前节点的父节点
value = tree.xpath("..//ul")
print(f"..选取当前节点的父节点:{value}") # [<Element ul at 0x19bff39d980>]
# @	选取属性
value = tree.xpath("//ul/li/@style")
print(f"@选取属性:{value}") # ['font-size: 10px', 'font-size: 20px', 'font-size: 30px']
# *	匹配任何元素节点
value = tree.xpath("//ul/*")
print(f"*匹配任何元素节点:{value}") # [<Element li at 0x1a20b761500>, <Element li at 0x1a20b761540>, <Element li at 0x1a20b7616c0>, <Element a at 0x1a20b761640>]
# @*匹配任何属性节点
value = tree.xpath("//ul/li/@*")
print(f"@*匹配任何属性节点:{value}") # ['font-size: 10px', 'font-size: 20px', 'font-size: 30px']
# node()匹配任何类型的节点(元素、属性、文本等)
value = tree.xpath("//ul/li/node()")
print(f"node()匹配任何类型的节点(元素、属性、文本等):{value}") # ['python', 'java', 'js']
# text()选取节点的文本内容
value = tree.xpath("//ul/li/text()")
print(f"text()选取节点的文本内容:{value}")  # ['python', 'java', 'js']
# []用于过滤节点,括号内为条件
value = tree.xpath("//li[@id='java']")
print(f"[]用于过滤节点,括号内为条件:{value}") # [<Element li at 0x1ee12a8d780>]
# |	用于组合多个路径,返回所有匹配的节点
value = tree.xpath("//ul/li/text()|//ul/a/text()")
print(f"|	用于组合多个路径,返回所有匹配的节点:{value}") # ['python', 'java', 'js', 'test_a']
# position()返回节点在节点集中的位置
value = tree.xpath("//ul/li[position()<2]")
print(f"position()	返回节点在节点集中的位置:{value}") # [<Element li at 0x206623c2180>] 返回第一个li
# last()返回节点集中最后一个节点
value = tree.xpath("//ul/li[last()]") # [<Element li at 0x134ce211bc0>]
print(f"last()返回节点集中最后一个节点:{value}") # [<Element li at 0x13428cd1e40>] li最后一个
# contains(str1, str2)	判断str1是否包含str2,返回布尔值
value = tree.xpath("//ul/li[contains(text(),'java')]")
print(f"contains(str1, str2)判断str1是否包含str2,返回布尔值:{value}") # [<Element li at 0x1e48dbc1c00>]
# starts-with(str1, str2)	判断str1是否以str2开头,返回布尔值
value = tree.xpath("//ul/li[starts-with(text(),'p')]")
print(f"starts-with(str1, str2)判断str1是否以str2开头,返回布尔值:{value}") # [<Element li at 0x230bb061c80>]
# not(expression)对表达式取反
value = tree.xpath("//ul/li[not(text()='java')]/text()")
print(f"not(expression)对表达式取反:{value}") # ['python', 'js']
# and逻辑与操作
value = tree.xpath("//ul/li[text()='java'  and position()<3 ]")
print(f"and逻辑与操作:{value}") # [<Element li at 0x1946f761ec0>]
# or逻辑或操作
value = tree.xpath("//ul/li[text()='java'  or text()='python' ]/text()")
print(f"or逻辑或操作:{value}") # ['python', 'java']

语法

语法 描述
/ 从根节点开始选取。
// 从当前节点开始,递归选取所有匹配的节点,无论它们在文档中的位置。
. 选取当前节点。
.. 选取当前节点的父节点。
@ 选取属性。
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点(元素、属性、文本等)。
text() 选取节点的文本内容。
[] 用于过滤节点,括号内为条件。
| 用于组合多个路径,返回所有匹配的节点。
position() 返回节点在节点集中的位置。
last() 返回节点集中最后一个节点。
contains(str1, str2) 判断 str1 是否包含 str2,返回布尔值。
starts-with(str1, str2) 判断 str1 是否以 str2 开头,返回布尔值。
not(expression) 对表达式取反。
and 逻辑与操作。
or 逻辑或操作。

jsonpath

官网概念

其实jsonpath主要是对于xpath的一个补充、因为xpath处理的是html或者xml,所以当需要解析json时来使用jsonpath。

安装

bash 复制代码
# 支持一般的语法
pip install jsonpath
# 支持函数 length()、min()等
pip install jsonpath-ng

作用

  • 主要用于 JSON 数据的查询和提取。

  • 语法简单,适合处理嵌套的 JSON 结构。

  • 适用于 API 返回的 JSON 数据处理。

使用

python 复制代码
import jsonpath,json
from django.template.defaultfilters import length
# 官网:https://pypi.org/project/jsonpath-ng/ 注意了 必须要使用ext下才可以使用函数  否则会一直报错 这里说的是 表达式内直接写函数 `len`|`sub(/foo\\+(.*)/, \\1)`|`split(+, 2, -1)`|`sorted`
from jsonpath_ng.ext import parse
# 将json加载成jsonobject对象 之后对于jsonobject进行处理
obj = json.load(open("test_jsonpath.json",'r',encoding='utf-8'))
# $	根节点
value = jsonpath.jsonpath(obj,"$.store")
print(f"$根节点:{value}") # $.store输出全部 $.clothing不是根目录 输出false
# @	当前节点 通常于过滤连用[]
value = jsonpath.jsonpath(obj,"$.store.clothing[?(@.price > 10)]")
print(f"@当前节点:{value}") # [{'name': '绿色衣服', 'color': 'green', 'remark': '一件漂亮的绿色衣服', 'price': 179.99}]
# .key	选择当前节点的key子节点
value = jsonpath.jsonpath(obj,"$.store.clothing")
print(f".key选择当前节点的key子节点:{value}") # 太长了
# ['key']	选择当前节点的key子节点(支持特殊字符)
value = jsonpath.jsonpath(obj,"$.store['food']")
print(f"['key']	选择当前节点的key子节点(支持特殊字符):{value}") # [[{'name': '大面包', 'price': 1.5}, {'name': '烤鸡', 'price': 20}]]
# ..key	递归查找所有key节点
value = jsonpath.jsonpath(obj,"$.store..['food']")
print(f"..key	递归查找所有key节点:{value}") # [[{'name': '大面包', 'price': 1.5}, {'name': '烤鸡', 'price': 20}]]
# 通配符 *
value = jsonpath.jsonpath(obj,"$.store.clothing[*].name")
print(f"通配符 *:{value}") # ['红色衣服', '蓝色衣服', '绿色衣服']
# 数组索引 [n]	选择数组中的第n个元素(从 0 开始)
value = jsonpath.jsonpath(obj,"$.store.clothing[0].name")
print(f"数组索引 [n]	选择数组中的第n个元素(从 0 开始):{value}") # ['红色衣服']
# [start:end:step]	选择数组中的切片(支持 Python 切片语法)
value = jsonpath.jsonpath(obj,"$.store.clothing[0:1,1].name")
print(f"[start:end:step]选择数组中的切片(支持 Python 切片语法):{value}") # ['红色衣服', '蓝色衣服']
# [?(表达式)]使用过滤表达式筛选数组元素
value = jsonpath.jsonpath(obj,"$.store.clothing[?(@.name == '绿色衣服')]")
print(f" [?(表达式)]使用过滤表达式筛选数组元素:{value}") # [{'name': '绿色衣服', 'color': 'blue', 'remark': '一件漂亮的绿色衣服', 'price': 179.99}]
# =~	正则表达式匹配

# len	返回数组或字符串的长度 函数这些需要jsonpath-ng库才可以支持 否则会返回False 安装pip install jsonpath-ng
try:
    jsonpath_expr = parse('$.store.clothing.`len`')
except Exception as e:
   raise e
# 下面的部分为 jsonpath_ng模块中的规定匹配写法
matches = [match.value for match in jsonpath_expr.find(obj)]
#或者 print(f"length()返回数组或字符串的长度:{length(matches)}") 这种方式就不用引入ext那个包了  引入 jsonpath_ng即可
print(f"`len`返回数组或字符串的长度:{matches}")
# min	返回数组中的最小值
try:
    jsonpath_expr = parse('$.store.clothing[?(@.price < 10)].price')
except Exception as e:
   raise e
# 下面的部分为 jsonpath_ng模块中的规定匹配写法
matches = [match.value for match in jsonpath_expr.find(obj)]
price = min(matches)
print(f"min()返回数组或字符串的长度:{price}")
# max()	返回数组中的最大值
price = max(matches)
print(f"max()返回数组中的最大值:{price}")
# sum()	返回数组中的总和
price = sum(matches)
print(f"sum()返回数组中的总和:{price}")
# sorted	排序
try:
    jsonpath_expr = parse('$.store.clothing[?(@.price < 10)].`sorted`')
except Exception as e:
   raise e
matches = [match.value for match in jsonpath_expr.find(obj)]
print(f"`sorted`排序:{matches}")

语法

语法 描述
根节点
$ 根节点。
当前节点
@ 当前节点。
子节点
.key 选择当前节点的 key 子节点。
['key'] 选择当前节点的 key 子节点(支持特殊字符)。
递归查找
..key 递归查找所有 key 节点。
通配符
* 匹配任何属性名或数组索引。
数组索引
[n] 选择数组中的第 n 个元素(从 0 开始)。
[start:end:step] 选择数组中的切片(支持 Python 切片语法)。
[?(表达式)] 使用过滤表达式筛选数组元素。
组合路径
key1.key2 选择 key1 下的 key2 子节点。
key1[*].key2 选择 key1 下所有元素的 key2 子节点。
过滤表达式
== 等于。
!= 不等于。
< 小于。
<= 小于等于。
> 大于。
>= 大于等于。
=~ 正则表达式匹配。
in 包含于。
nin 不包含于。
&& 逻辑与。
| 逻辑或
函数
length() 返回数组或字符串的长度。
min() 返回数组中的最小值。
max() 返回数组中的最大值。
sum() 返回数组中的总和。

对比

功能 JSONPath XPath
根节点 $ /
当前节点 @ .
父节点 无直接支持 ..
子节点 .key['key'] /nodename//nodename
递归查找 ..key //nodename
通配符 * *
属性选择 无直接支持(需通过过滤表达式) @attr
数组索引 [n] [n]
数组切片 [start:end:step] 无直接支持
过滤表达式 [?(表达式)] [表达式]
逻辑运算符 &&,| and, or
比较运算符 ==, !=, <, <=, >, >= =, !=, <, <=, >, >=
正则表达式 =~ matches()
函数 length(), min(), max(), avg(), sum() text(), contains(), starts-with(), position(), last()
组合路径 key1.key2key1[*].key2 /path1/path2//path1//path2
文本内容 无直接支持 text()

Beautiful Soup

官网概念

Beautiful Soup 是一个 可以从 HTML 或 XML 文件中提取数据的 Python 库。它能用你喜欢的解析器和习惯的方式实现 文档树的导航、查找、和修改。它会帮你节省数小时甚至数天的工作时间。(主要的作用是解析HTML,获取指定的标签内容)。

安装

bash 复制代码
# 需要安装requests 联合使用
pip install beautifulsoup,requests

使用

python 复制代码
import requests,re
from bs4 import BeautifulSoup
#
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story1">...</p>
<p class="story2">2222</p>
<div data-foo="value">foo!</div>
"""
soup = BeautifulSoup(html_doc, 'html.parser')

# 获取title标签
print(soup.title)

# 获取title标签的名称 不是标签内部的
print(soup.title.name)

# 获取title标签的名称 是标签内部的
print(soup.title.string)

# parent的名称
print(soup.title.parent.name)

# 获取 第一个p标签
print(soup.p)

# 获取第一个p标签的class['title']
print(soup.p['class'])

# 获取第一个a标签
print(soup.a)

# 获取所有的a标签 find_all(标签名)
print(soup.find_all("a"))

# 获取所有的p标签
print(soup.find_all("p"))

# 使用多个引入正则re
print(soup.find_all(href=re.compile("elsie"), id='link1'))

# 获取自定义标签内容
print(soup.find_all(attrs={"data-foo": "value"}))

# 按css来搜索
print(soup.find_all("a", class_="sister"))

语法

方法或属性 描述
初始化
BeautifulSoup(html, 'html.parser') 创建 BeautifulSoup 对象,解析 HTML 文档。
BeautifulSoup(html, 'lxml') 使用 lxml 解析器创建 BeautifulSoup 对象(需安装 lxml 库)。
BeautifulSoup(html, 'html5lib') 使用 html5lib 解析器创建 BeautifulSoup 对象(需安装 html5lib 库)。
查找元素
soup.find(tag) 查找第一个匹配的标签。
soup.find_all(tag) 查找所有匹配的标签,返回列表。
soup.select(css_selector) 使用 CSS 选择器查找元素,返回列表。
soup.find(tag, attrs={}) 根据标签和属性查找元素。
soup.find_all(tag, attrs={}) 根据标签和属性查找所有匹配的元素。
获取内容
tag.text 获取标签的文本内容。
tag.get_text() 获取标签的文本内容(与 tag.text 相同)。
tag.string 获取标签的文本内容(仅当标签内没有子标签时有效)。
tag['attr'] 获取标签的属性值。
tag.get('attr') 获取标签的属性值(推荐使用,避免属性不存在时报错)。
tag.contents 获取标签的直接子节点列表。
tag.children 获取标签的直接子节点迭代器。
tag.descendants 获取标签的所有后代节点迭代器。
导航文档树
tag.parent 获取标签的父节点。
tag.parents 获取标签的所有祖先节点迭代器。
tag.next_sibling 获取标签的下一个兄弟节点。
tag.previous_sibling 获取标签的上一个兄弟节点。
tag.next_element 获取文档中的下一个节点(不一定是兄弟节点)。
tag.previous_element 获取文档中的上一个节点(不一定是兄弟节点)。
修改文档
tag.name = 'new_tag' 修改标签的名称。
tag['attr'] = 'value' 修改标签的属性值。
tag.append(new_tag) 在标签内追加新标签或字符串。
tag.insert(index, new_tag) 在标签内插入新标签或字符串。
tag.replace_with(new_tag) 替换当前标签。
tag.decompose() 删除当前标签及其内容。
tag.clear() 删除当前标签的内容,保留标签本身。
其他方法
soup.prettify() 格式化输出 HTML 文档。
soup.encode() 将文档编码为字节字符串。
soup.decode() 将字节字符串解码为文档。

对比

特性/工具 XPath JSONPath BeautifulSoup
用途 用于在 XML 和 HTML 文档中定位元素 用于在 JSON 数据中定位元素 用于解析和操作 HTML/XML 文档
语法 基于路径表达式 基于路径表达式 基于 Python 对象的 API
数据格式 XML、HTML JSON HTML、XML
定位元素 通过节点路径、属性、文本等 通过键、索引、条件等 通过标签名、属性、CSS 选择器等
示例 /bookstore/book[1]/title $.store.book[0].title soup.find('div', class_='title')
灵活性 高,支持复杂查询 中,适合 JSON 结构 高,支持多种查找方式
学习曲线
适用场景 XML/HTML 文档解析 JSON 数据解析 HTML/XML 文档解析和操作
跨语言支持 是(多种编程语言支持) 是(多种编程语言支持) 仅限 Python
性能
扩展性

选择建议

  • 如果需要处理 XML/HTML 文档并需要复杂的查询,选择 XPath。

  • 如果需要处理 JSON 数据,选择 JSONPath。

  • 如果需要解析和操作 HTML/XML 文档,并且使用 Python,选择 BeautifulSoup。

相关推荐
How_doyou_do几秒前
项目实战-25年美赛MCM/ICM-基于数学建模与数据可视化的动态系统模型
python·数学建模·数据可视化
MayByte13 分钟前
全连接神经网络学习笔记
笔记·神经网络·学习
大白的编程日记.28 分钟前
【Linux学习笔记】基础IO之理解文件
linux·笔记·学习
晓13131 小时前
第四章 OpenCV篇—图像梯度与边缘检测—Python
人工智能·python·opencv·计算机视觉·pycharm
小鹿撞出了脑震荡1 小时前
「OC」源码学习——objc_class的bits成员探究
学习·ios·objective-c
蹦蹦跳跳真可爱5891 小时前
Python----神经网络(《Going deeper with convolutions》论文解读和GoogLeNet网络)
网络·人工智能·pytorch·python·神经网络
牛奶咖啡131 小时前
学习设计模式《八》——原型模式
学习·设计模式·原型模式·浅度克隆·深度克隆·c#的克隆·原型管理器
reasonsummer1 小时前
【办公类-99-05】20250508 D刊物JPG合并PDF便于打印
python·pdf
坐吃山猪2 小时前
WebFlux与HttpStreamable关系解析
python
soso(找工作版2 小时前
【链表扫盲】FROM GPT
python·gpt·链表