Python JSON 数据解析
JSON(JavaScript Object Notation)是一种轻量级数据交换格式,它易于阅读和编写,同时也易于机器解析和生成。Python提供了内置的JSON模块,用于处理JSON数据。
1. 导入模块
import json
2. 序列化
import json
data = {
"name": "John",
"age": 30,
"city": "New York"
}
json_str = json.dumps(data) # json.dumps() 是 Python 的 json 模块中的一个函数,它的作用是将 Python 对象转换为 JSON 格式的字符串。
print(json_str)
3. 反序列化
json_str = '{"name": "John", "age": 30, "city": "New York"}'
data = json.loads(json_str) # json.loads() 是 Python json 模块中的一个函数,它的作用是将 JSON 格式的字符串转换为 Python 对象。
print(data)
4. 对象存文件
data = {
"name": "John",
"age": 30,
"city": "New York"
}
with open('data.json', 'w') as json_file:
json.dump(data, json_file)
5. 从文件加载
with open('data.json', 'r') as json_file:
data = json.load(json_file)
print(data)
6. 嵌套JSON数据
如果JSON数据包含嵌套结构,您可以使用递归来访
问和修改其中的值。
json_data = {
"name": "Alice",
"info": {
"age": 25,
"location": "Paris"
}
}
# 获取嵌套的值
age = json_data["info"]["age"]
# 修改嵌套的值
json_data["info"]["location"] = "New York"
# 将更改后的数据转换为JSON字符串
new_json_str = json.dumps(json_data)
7. JSON中列表
JSON可以包含列表,可以使用索引来访问列表元素。
json_data = {
"fruits": ["apple", "banana", "cherry"]
}
# 获取列表中的第一个水果
first_fruit = json_data["fruits"][0]
# 添加一个新水果到列表
json_data["fruits"].append("orange")
8. JSON中空值
JSON允许表示空值(null),在Python中,它通常转换为None
。
json_data = {
"value": None
}
字典和JSON格式不同之处
- 数据类型限制:
- JSON:支持的数据类型包括对象(类似于字典)、数组(类似于列表)、字符串、数字、布尔值和
null
。JSON 不支持 Python 特有的数据类型如tuple
、set
、bytes
等。 - Python 字典:可以包含多种 Python 特有的数据类型,比如
tuple
、set
、bytes
等。
- JSON:支持的数据类型包括对象(类似于字典)、数组(类似于列表)、字符串、数字、布尔值和
- 格式要求:
- JSON:数据必须以字符串的形式表示,键必须是双引号括起来的字符串,值可以是字符串、数字、布尔值、数组、对象或
null
。 - Python 字典:键可以是任意不可变的类型(如字符串、数字、元组),值可以是任意类型。键通常用单引号或双引号括起来,但 Python 允许在字典中使用不加引号的键。
- JSON:数据必须以字符串的形式表示,键必须是双引号括起来的字符串,值可以是字符串、数字、布尔值、数组、对象或
Python正则表达式
正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。re模块使 Python 语言拥有全部的正则表达式功能。正则表达式在网络爬虫、数据分析中有着广泛使用,掌握正则表达式能够达到事半功倍的效果。
模式 | 描述 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的末尾。 |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。 |
[…] | 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’ |
[^…] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。 |
re* | 匹配0个或多个的表达式。 |
re+ | 匹配1个或多个的表达式。 |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 |
re{n} | 匹配n个前面表达式。例如,"o{2}“不能匹配"Bob"中的"o”,但是能匹配"food"中的两个o。 |
re{n,} | 精确匹配n个前面表达式。例如,"o{2,}“不能匹配"Bob"中的"o”,但能匹配"foooood"中的所有o。"o{1,}“等价于"o+”。"o{0,}“则等价于"o*”。 |
re{n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 |
| | 匹配a或b |
(re) | 匹配括号内的表达式,也表示一个组 |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域。 |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域。 |
(?: re) | 类似 (…), 但是不表示一个组 |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 |
(?#…) | 注释. |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 … 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边。 |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功。 |
(?> re) | 匹配的独立模式,省去回溯。 |
\w | 匹配数字字母下划线 |
\W | 匹配非数字字母下划线 |
\s | 匹配任意空白字符,等价于 [\t\n\r\f]。 |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9]。 |
\D | 匹配任意非数字 |
\A | 匹配字符串开始 |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。 |
\z | 匹配字符串结束 |
\G | 匹配最后匹配完成的位置。 |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。 |
\B | 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。 |
\n, \t, 等 | 匹配一个换行符。匹配一个制表符, 等 |
\1…\9 | 匹配第n个分组的内容。 |
\10 | 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。 |
1.字符匹配
方法和功能
方法 | 功能 |
---|---|
match() | 判断一个正则表达式是否从开始处匹配一个字符串 |
search() | 遍历字符串,找到正则表达式匹配的第一个位置,返回匹配对象 |
findall() | 遍历字符串,找到正则表达式匹配的所有位置,并以列表的形式返回。如果给出的正则表达式中包含子组,就会把子组的内容单独返回,如果有多个子组就会以元组的形式返回。 |
finditer() | 遍历字符串,找到正则表达式匹配的所有位置,并以迭代器的形式返回 |
- hqyj匹配文本中的hqyj
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("hqyj",text)
print(data)#['hqyj', 'hqyj']
- [hqyj]匹配h或者q或者y或者j字符
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("[hqyj]",text)
print(data)#['h', 'q', 'y', 'j', 'h', 'q', 'y', 'j']
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("[hqyj]牛",text)
print(data)#['j牛']
- [^hqyj]匹配除了hqyj以外的其他字符
import re
text="hqyj牛皮6666,hqyj有个老师也牛皮666"
data=re.findall("[^hqyj]",text)
print(data)#['牛', '皮', '6', '6', '6', '6', ',', '有', '个', '老', '师', '也', '牛', '皮', '6', '6', '6']
- [a-z]匹配a~z的任意字符([0-9]也可以)
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall("[a-z]hqyj",text)
print(data)#['chqyj']
- .匹配除了换行符以外的任意字符
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall(".hqyj",text)
print(data)#[',hqyj', 'chqyj']
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall(".+hqyj",text) #贪婪匹配(匹配最长的)
print(data)#['hqyj牛皮6666,hqyj有个老师abchqyj']
import re
text="hqyj牛皮6666,hqyj有个老师abchqyj也牛皮666"
data=re.findall(".?hqyj",text)
print(data)#['hqyj', ',hqyj', 'chqyj']
特殊字符
特殊字符 | 含义 |
---|---|
\d | 匹配任何十进制数字;相当于类 [0-9] |
\D | 与 \d 相反,匹配任何非十进制数字的字符;相当于类 [^0-9] |
\s | 匹配任何空白字符(包含空格、换行符、制表符等);相当于类 [ \t\n\r\f\v] |
\S | 与 \s 相反,匹配任何非空白字符;相当于类 [^ \t\n\r\f\v] |
\w | 匹配任意一个文字字符,包括大小写字母、数字、下划线,等价于表达式[a-zA-Z0-9_] |
\W | 于 \w 相反 (注:re.ASCII 标志使得 \w 只能匹配 ASCII 字符) |
\b | 匹配单词的开始或结束 |
\B | 与 \b 相反 |
- \w 匹配字母数字下划线(汉字)
import re
text="华清_远见abc 华清hqyj远见 华清牛皮远见"
data=re.findall("华清\w+远见",text)
print(data)#['华清_远见', '华清hqyj远见', '华清牛皮远见']
- \d匹配数字
import re
text="hqyj66d6 a1h43d3fd43s43d4 "
data=re.findall("d\d",text) # 只匹配一个数字
print(data)#['d6', 'd3', 'd4', 'd4']
import re
text="hqyj66d6 a1h43d3fd43s43d4 "
data=re.findall("d\d+",text)
print(data)#['d6', 'd3', 'd43', 'd4']
- \s匹配任意空白符 包括空格,制表符等等
import re
text="hqyj666 jack karen 666"
data=re.findall("\sj\w+\s",text)
print(data)#[' jack ']
2.数量控制
*重复0次或者更多次
import re
text="华清远见 华清666远见"
data=re.findall("华清6*远见",text)
print(data)#['华清远见', '华清666远见']
+重复1次或者更多次
import re
text="华清远见 华清666远见 华清6远见"
data=re.findall("华清6+远见",text)
print(data)#['华清666远见', '华清6远见']
?重复1次或者0次
import re
text="华清远见 华清666远见 华清6远见"
data=re.findall("华清6?远见",text)
print(data)#['华清远见', '华清6远见']
{n}重复n次,n是数字
import re
text="华清远见 华清666远见 华清6远见"
data=re.findall("华清6{3}远见",text)
print(data)#['华清666远见']
{n,}重复n次或者更多次
import re
text="华清远见 华清666远见 华清6远见 华清66远见"
data=re.findall("华清6{2,}远见",text)
print(data)#['华清666远见', '华清66远见']
{n,m}重复n到m次
import re
text="华清远见 华清666远见 华清6远见 华清66远见"
data=re.findall("华清6{0,2}远见",text)
print(data)#['华清远见', '华清6远见', '华清66远见']
3.分组
- ()提取兴趣区域
import re
text="谢帝谢帝,我要迪士尼,我的电话号码18282832341,qq号码1817696843"
data=re.findall("号码(\d{10,})",text)
print(data)#['18282832341', '1817696843']
import re
text="谢帝谢帝,我要迪士尼,我的电话号码18282832341,qq号码1817696843"
data=re.findall("(\w{2}号码(\d{10,}))",text)
print(data)#['18282832341', '1817696843']
- (|)提取兴趣区域(| = or)
import re
text="第一名张三 第一名物理149分 第一名数学150分 第一名英语148分 第一名总分740分"
data=re.findall("第一名(\w{2,}|\w{2,}\d{2,}分)",text)
print(data)#['张三', '物理149分', '数学150分', '英语148分', '总分740分']
4.开始和结束
- ^开始
import re
text = "hqyj66abc hqyj123"
data = re.findall("^hqyj\d+", text)
print(data) #['hqyj66']
- $结尾
import re
text = "hqyj66abc hqyj123"
data = re.findall("hqyj\d+$", text)
print(data) #['hqyj123']
5.特殊字符
由于正则表达式中* . \ {} () 等等符号具有特殊含义,如果你指定的字符正好就是这些符号,需要用\进行转义
import re
text = "数学中集合的写法是{2}"
data = re.findall("\{2\}", text)
print(data) #['{2}']
6.re模块的常用方法
re.findall
获取匹配到的所有数据
import re
text="hqyj66d6 a1h43d3fd43s43d4 "
data=re.findall("d\d+",text)
print(data)#['d6', 'd3', 'd43', 'd4']
re.match
从字符串的起始位置匹配,成功返回一个对象否则返回none。
匹配成功返回对象,对象的方法:
方法 | 功能 |
---|---|
group() | 返回匹配的字符串 |
start() | 返回匹配的开始位置 |
end() | 返回匹配的结束位置 |
span() | 返回一个元组表示匹配位置(开始,结束) |
import re
# 在起始位置匹配,并返回一个包含匹配 (开始,结束) 的位置的元组
print(re.match('www', "www.python.com").span())#(0, 3)
print(re.match('www', "www.python.com").start())#0
print(re.match('www', "www.python.com").end())#3
# 不在起始位置匹配
print(re.match('com', "www.python.com"))# None
re.search
扫描整个字符串并返回第一个成功匹配的字符串。成功返回一个对象否则返回none
import re
# 在起始位置匹配
print(re.search('www', 'www.hqyj.com').span())#(0, 3)
# 不在起始位置匹配
print(re.search('com', 'www.hqyj.com').span())#(9, 12)
re.sub
替换匹配成功的字符
类似与字符串的replace函数
import re
text = "以前华清远见在四川大学旁边,现在华清远见在西南交大旁边"
data = re.sub("华清远见","北京华清远见科技集团成都中心", text)
print(data)#以前北京华清远见科技集团成都中心在四川大学旁边,现在北京华清远见科技集团成都中心在西南交大旁边
re.split
根据匹配成功的位置对字符串进行分割
import re
text = "python is very easy"
data = re.split("\s{1,}", text)
print(data)#['python', 'is', 'very', 'easy']
re.finditer
类似findall 但是不会全部返回出来 而是返回迭代器(比如匹配成功了10万个 全部返回就很吃内存了)
import re
text = "python is very easy"
data = re.findall("\w+", text)
print(data)#['python', 'is', 'very', 'easy']
import re
text = "python is very easy"
data = re.finditer("\w+", text)
print(data)
for el in data:
print(el.group())
7.常见的一些正则
QQ号:[1 - 9][0 - 9]{4, }(腾讯QQ号从10000开始)
帐号(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
身份证号(15位、18位数字):^\d{15}|\d{18}$
短身份证号码(数字、字母x结尾):^([0-9]){7,18}(x|X)?$ 或 ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
Python日期和时间
Python 的 time 模块下有很多函数可以转换
- 常见日期格式。
time 模块时间处理的和转换时间格式的常用API: [官网链接](time — 时间访问和转换 — Python 3.12.2 文档)
time.time() - 获取当前时间的时间戳(以秒为单位,浮点数形式,精确到小数点后若干位)
import time # 引入time模块
ticks = time.time()
print ("当前时间戳为:", ticks)#时间戳单位最适于做日期运算。但是1970年之前的日期就无法以此表示了。太遥远的日期也不行,UNIX和Windows只支持到2038年
time.sleep(secs) - 让程序暂停执行指定秒数。
import time
# 让程序暂停3秒
time.sleep(3)
print("3秒后执行到这里...")
time.ctime(timestamp=None) - 将时间戳转换为易读的本地时间格式。
import time
# 获取当前时间的ctime格式
current_time = time.ctime()
print("当前时间 (ctime):", current_time)
# 或者使用特定时间戳
timestamp = 1647708000 # 这是一个示例时间戳
converted_time = time.ctime(timestamp)
print("时间戳转ctime格式:", converted_time)
time.localtime([secs]) - 将时间戳转换为本地时区的struct_time元组。
import time
# 获取当前时间的struct_time元组
local_time_tuple = time.localtime()
print("当前时间 (struct_time):", local_time_tuple)
# 或者使用特定时间戳
timestamp = time.time()
converted_tuple = time.localtime(timestamp)
print("时间戳转struct_time:", converted_tuple)
time.strftime(format[, t]) - 格式化本地时间。
import time
# 获取当前时间并格式化为“年-月-日 时:分:秒”
formatted_time = time.strftime('%Y-%m-%d %H:%M:%S')
print("格式化当前时间:", formatted_time)
# 使用特定时间戳
timestamp = time.time()
custom_format = time.strftime("%Y%m%d_%H%M%S", time.localtime(timestamp))
print("格式化后的时间戳:", custom_format)
格式化符号:
- %y 两位数的年份表示(00-99)
- %Y 四位数的年份表示(000-9999)
- %m 月份(01-12)
- %d 月内中的一天(0-31)
- %H 24小时制小时数(0-23)
- %I 12小时制小时数(01-12)
- %M 分钟数(00=59)
- %S 秒(00-59)
- %a 本地简化星期名称
- %A 本地完整星期名称
- %b 本地简化的月份名称
- %B 本地完整的月份名称
- %c 本地相应的日期表示和时间表示
- %j 年内的一天(001-366)
- %p 本地A.M.或P.M.的等价符
- %U 一年中的星期数(00-53)星期天为星期的开始
- %w 星期(0-6),星期天为星期的开始
- %W 一年中的星期数(00-53)星期一为星期的开始
- %x 本地相应的日期表示
- %X 本地相应的时间表示
- %Z 当前时区的名称
- %% %号本身
属性(time模块本身没有属性,但可以通过其提供的函数生成的对象来访问属性)
对于struct_time对象(由time.localtime()或time.gmtime()等返回),它是一个元组,可以按索引访问各个时间元素:
属性 | 值 |
---|---|
tm_year | 年 |
tm_mon | 月:1 到 12 |
tm_mday | 日:1 到 31 |
tm_hour | 时:0 到 23 |
tm_min | 分:0 到 59 |
tm_sec | 秒:0 到 61 (60或61 是闰秒) |
tm_wday | 星期:0 到 6 (0是周一) |
tm_yday | 一年中的第几天,1 到 366 |
tm_isdst | 是否为夏令时,值有:1(夏令时)、0(不是夏令时)、-1(未知),默认 -1 |
import time
local_time = time.localtime()
# 访问struct_time的属性(索引)
year = local_time.tm_year
month = local_time.tm_mon
day = local_time.tm_mday
hour = local_time.tm_hour
minute = local_time.tm_min
second = local_time.tm_sec
print(f"当前日期和时间:{
year}-{
month}-{
day} {
hour}:{
minute}:{
second}")
Python网络
Python requests 是一个常用的 HTTP 请求库,可以方便地向网站发送 HTTP 请求,并获取响应结果。
使用 requests 发送 HTTP 请求需要先下载并导入 requests 模块:
import requests
# 导入 requests 包
import requests
response = requests.get('https://www.baidu.com')# 发送请求
print(response.content) # 获取响应内容
response2 = requests.get('http://localhost:7001/test')# 发送请求
print(response2.json()) # 获取json数据并解析
每次调用 requests 请求之后,会返回一个 response 对象,该对象包含了具体的响应信息,如状态码、响应头、响应内容等:
response的属性或方法 | 说明 |
---|---|
apparent_encoding | 编码方式 |
close() | 关闭与服务器的连接 |
content | 返回响应的内容,以字节为单位 |
cookies | 返回一个 CookieJar 对象,包含了从服务器发回的 cookie |
elapsed | 返回一个 timedelta 对象,包含了从发送请求到响应到达之间经过的时间量,可以用于测试响应速度。比如 r.elapsed.microseconds 表示响应到达需要多少微秒。 |
encoding | 解码 r.text 的编码方式 |
headers | 返回响应头,字典格式 |
history | 返回包含请求历史的响应对象列表(url) |
is_permanent_redirect | 如果响应是永久重定向的 url,则返回 True,否则返回 False |
is_redirect | 如果响应被重定向,则返回 True,否则返回 False |
iter_content() | 迭代响应 |
iter_lines() | 迭代响应的行 |
json() | 返回结果的 JSON 对象 (结果需要以 JSON 格式编写的,否则会引发错误) |
links | 返回响应的解析头链接 |
next | 返回重定向链中下一个请求的 PreparedRequest 对象 |
ok | 检查 “status_code” 的值,如果小于400,则返回 True,如果不小于 400,则返回 False |
raise_for_status() | 如果发生错误,方法返回一个 HTTPError 对象 |
reason | 响应状态的描述,比如 “Not Found” 或 “OK” |
request | 返回请求此响应的请求对象 |
status_code | 返回 http 的状态码,比如 404 和 200(200 是 OK,404 是 Not Found) |
text | 返回响应的内容,unicode 类型数据 |
url | 返回响应的 URL |
requests的方法
方法 | 描述 |
---|---|
delete(url, args) | 发送 DELETE 请求到指定 url |
get(url, params, args) | 发送 GET 请求到指定 url |
head(url, args) | 发送 HEAD 请求到指定 url |
patch(url, data, args) | 发送 PATCH 请求到指定 url |
post(url, data, json, args) | 发送 POST 请求到指定 url |
put(url, data, args) | 发送 PUT 请求到指定 url |
request(method, url, args) | 向指定的 url 发送指定的请求方法 |
requests.get(url, params ={key: value}, args)
- url 请求 url。
- **params ** 参数为要发送到指定 url 的 JSON 对象。
- args 为其他参数,比如 cookies、headers、verify等。
import requests
# 图片URL地址
image_url = 'http://localhost:7001/public/1.png'
# 发送GET请求获取图片数据
response = requests.get(image_url)
# 检查请求是否成功(HTTP状态码为200)
if response.status_code == 200:
# 将图片数据写入本地文件
with open('image.jpg', 'wb') as f:
f.write(response.content)
print("图片已成功下载并保存为 image.jpg")
else:
print(f"无法下载图片,响应状态码:{
response.status_code}")
requests.post(url, data={key: value}, json={key: value}, args)
- url 请求 url。
- data 参数为要发送到指定 url 的字典、元组列表、字节或文件对象。
- json 参数为要发送到指定 url 的 JSON 对象。
- args 为其他参数,比如 cookies、headers、verify等。
import requests
headers = {
'User-Agent': 'Mozilla/5.0'} # 设置请求头
params = {
'key1': 'value1', 'key2': 'value2'} # 设置查询参数
data = {
'username': 'jack', 'password': '123456'} # 设置请求体
response = requests.post('http://localhost:7001/test', headers=headers, params=params, data=data)
print(response.text)