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。

相关推荐
Jelena技术达人9 分钟前
Python爬虫获取1688商品(按图搜索)接口的返回数据说明
爬虫·python·图搜索算法
Jelena技术达人12 分钟前
使用Python爬虫获取1688商品(按图搜索)接口
爬虫·python·图搜索算法
杨超越luckly1 小时前
Python应用指南:利用高德地图API获取POI数据(关键词版)
大数据·python·数据挖掘·数据分析·html
九亿AI算法优化工作室&2 小时前
SA模拟退火算法优化高斯回归回归预测matlab代码
人工智能·python·算法·随机森林·matlab·数据挖掘·模拟退火算法
小杜不吃糖2 小时前
llama源码学习·model.py[6]TransformerBlock类
学习·llama
Blossom.1182 小时前
基于Python的机器学习入门指南
开发语言·人工智能·经验分享·python·其他·机器学习·个人开发
郝YH是人间理想3 小时前
Python面向对象
开发语言·python·面向对象
藍海琴泉3 小时前
蓝桥杯算法精讲:二分查找实战与变种解析
python·算法
云上艺旅7 小时前
K8S学习之基础四十七:k8s中部署fluentd
学习·云原生·容器·kubernetes
mqwguardain8 小时前
python常见反爬思路详解
开发语言·python