Week05 周总结
Week05 周总结
正则表达式
什么是正则表达式
利用一些'特殊符号'的组合去字符串中筛选出想要的数据
正则表达式之字符组
点击查看代码
'''
# 单个字符组默认一次只匹配一个字符
- 表范围
'''
# 匹配0到9之间的任意一个数字
[0123456789] [0-9]
# 匹配a到z A到Z之间任意一个
[a-z] [A-Z]
# 匹配任意一个数字或者大小写字母
[0-9a-zA-Z]
正则表达式之特殊符号
点击查看代码
# 特殊符号默认也是一次匹配一个字符
. 匹配除换行符以外的任意字符
\w 匹配数字、字母、下划线(后续筛选变量名可能用到)
\W 匹配非字母或数字或下划线
\d 匹配任意的数字
\D 匹配非数字
\t 匹配一个制表符(tab键)
^ 匹配字符串的开始 eg:^9 找9并且这个9必须在开头
$ 匹配字符串的结尾 eg:9$ 找9并且这个9必须在末尾
a|b 匹配a或者b 管道符就是or(或)的意思
() 给正则表达式分组 不影响正则匹配
[] 字符组的概念(里面所有的数据都是或的关系)
[^] ^出现在了中括号的里面意思是取反操作
正则表达式之量词
点击查看代码
"""量词必须跟在表达式的后面 不能单独使用 目的是增加匹配的字符数"""
# 注意量词默认都是贪婪匹配(尽可能多的匹配)
* 重复零次或者多次(默认就是多次:越多越好)
+ 重复一次或者多次(默认就是多次:越多越好)
? 重复零次或者一次(默认就是一次:越多越好)
{n} 重复n次
{n,} 重复最少n次最多多次(越多越好)
{n,m} 重复n到m次(越多越好)
取消转义
点击查看代码
\n \n False
\\n \n True
\\\\n \\n True
'''在python中还可以在字符串的前面加r取消转义 更加方便'''
贪婪匹配与非贪婪匹配
点击查看代码
<.*> 贪婪匹配
res5 = re.findall('<.*>', '<script>alert(123)</script>')
print(res5)
# ['<script>alert(123)</script>']
<.*?> 非贪婪匹配
res6 = re.findall('<.*?>', '<script>alert(123)<script>')
print(res6)
# ['<script>', '<script>']
'''量词默认都是贪婪匹配 如果想修改为非贪婪匹配 只需要在量词的后面加?即可
贪婪非贪婪通常都是利用左右两边的条件作为筛选依据'''
re模块
# 在python中无法直接使用正则 需要借助于模块
1.内置的re模块
2.第三方的其他模块
import re
主要函数
1. re.findall() # 结果是所有符合条件的数据 并且组成列表
点击查看代码
# findall(正则表达式,待匹配的文本)
res = re.findall('fast', 'run fast hit fast win fast')
print(res) # ['fast', 'fast', 'fast'] 结果是所有符合条件的数据 并且组织成了列表
2. re.search() # 查找到一个符合条件的数据就结束 没有则返回None
点击查看代码
# search(正则表达式,待匹配的文本)
res1 = re.search('fast', 'run fast hit fast win fast')
print(res1) # 查找到一个符合条件的数据就结束 没有则返回None
print(res1.group()) # fast 没有则无法调用group() 直接报错
3. re.match() # 从字符串的开头匹配 如果没有则直接返回None 如果符合也只获取一个就结束
点击查看代码
# match(正则表达式,待匹配的文本)
res2 = re.match('ru', 'run fast hit fast win fast')
print(res2) # None 从字符串的开头匹配 如果没有则直接返回None 类似于给正则自动加了^ 如果符合也只获取一个就结束
print(res2.group()) # ru 没有则无法调用group() 直接报错
4. re.finditer() # 将所有符合条件的数据作为一个迭代器对象返回
点击查看代码
# finditer(正则表达式,待匹配的文本)
res3 = re.finditer('fa', 'run fast hit fast win fast')
print(res3) # 结果是一个迭代器对象 为了节省空间
print([obj.group() for obj in res3]) # ['fa', 'fa', 'fa']
5. re.compile() # 提前定义正则 生成一个正则表达式对象
点击查看代码
obj = re.compile('\d+') # 提前写好后续需要经常使用的正则
print(re.findall(obj,'1a2b3c4d5e')) # 写一遍之后 直接反复调用即可 ['1', '2', '3', '4', '5']
print(re.findall(obj,'lt666lb')) # 写一遍之后 直接反复调用即可 ['666']
print(re.findall(obj,'7k7kxyx')) # 写一遍之后 直接反复调用即可 ['7', '7']
补充
1. findall默认是分组优先展示
正则表达式中如果有括号分组 那么在展示匹配结果的时候
默认只演示括号内正则表达式匹配到的内容!!!
点击查看代码
res = re.findall('csb', 'nscsbcsbsnsbsb')
res1 = re.findall('cs(b)', 'nscsbcsbsnsbsb')
res2 = re.findall('(c)(s)(b)', 'nscsbcsbsnsbsb')
print(res) # ['csb', 'csb']
print(res1) # ['b', 'b']
print(res2) # [('c', 's', 'b'), ('c', 's', 'b')]
也可以取消分组有限展示的机制
(?: ) 括号前面加问号冒号
点击查看代码
res3 = re.findall('cs(?:b)', 'nscsbcsbsnsbsb')
res4 = re.findall('(c)(?:s)(?:b)', 'nscsbcsbsnsbsb')
print(res3) # ['csb', 'csb']
print(res4) # ['c', 'c']
2. 可以通过索引的方式单独获取分组内匹配到的数据
点击查看代码
res5 = re.search('csb', 'nscsbcsbsnsbsb')
res6 = re.search('c(s)(b)', 'nscsbcsbsnsbsb')
# print(res5)
# print(res6)
print(res5.group()) # csb
print(res6.group()) # csb
print(res6.group(1)) # s
print(res6.group(2)) # b
'''针对search和match有几个分组 group方法括号内最大就可以写几'''
3. 分组之后还可以给组起别名
点击查看代码
res7 = re.search('c(?P<sss>s)(?P<bbb>b)', 'nscsbcsbsnsbsb')
print(res7.group('sss')) # s
print(res7.group('bbb')) # b
collections模块
计数器(Counter)
双端队列(deque)
默认字典(defaultdict)
有序字典(OrderedDict)
具名元组(namedtuple)
计数器(Counter)
res = 'RUN FAST, HIT FAST, WIN FAST'
# 统计字符串中所有字符的出现次数
1.传统写法
new_dict = {}
for i in res:
if i not in new_dict:
new_dict[i] = 1
else:
new_dict[i] += 1
print(new_dict)
# {'R': 1, 'U': 1, 'N': 2, ' ': 5, 'F': 3, 'A': 3, 'S': 3, 'T': 4, ',': 2, 'H': 1, 'I': 2, 'W': 1}
2. Counter
from collections import Counter
r = Counter(res)
print(r)
# Counter({' ': 5, 'T': 4, 'F': 3, 'A': 3, 'S': 3, 'N': 2, ',': 2, 'I': 2, 'R': 1, 'U': 1, 'H': 1, 'W': 1})
print(r.get('F')) # 5 可以当成字典使用
双端队列(deque)
队列: 先进先出 默认是只有一端只能进另外一端只能出
双端队列: 两端都可以进出
1. 队列
import queue
q = queue.Queue(3) # 指定最大存放元素个数 3
# 存放元素
q.put(111)
q.put(222)
q.put(333)
# q.put(444) # 如果队列满了 继续添加则原地等待 相当于一直等待不往下运行
# 获取元素
print(q.get())
print(q.get())
print(q.get())
# print(q.get()) # 如果队列空了 继续获取则原地等待 相当于一直等待不往下运行
2. 双端队列
from collections import deque
d = deque([1, 2, 3])
d.append(4)
print(d) # deque([1, 2, 3, 4])
d.appendleft(0) # 从左加
print(d) # deque([0, 1, 2, 3, 4])
print(d.pop()) # 4 默认从右弹出元素
print(d.popleft()) # 0 从左弹出元素
默认字典(defaultdict)
有如下值集合 [11,22,33,44,55,67,77,88,99],
将所有大于 66 的值保存至字典的第一个key中,将小于 66 的值保存至第二个key的值中。
1. 普通字典
l1 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
new_dict = {'k1': [], 'k2': []}
for i in l1:
if i > 66:
new_dict['k1'].append(i)
else:
new_dict['k2'].append(i)
print(new_dict)
# {'k1': [77, 88, 99], 'k2': [11, 22, 33, 44, 55, 66]}
2. 默认字典
from collections import defaultdict
l2 = [11, 22, 33, 44, 55, 66, 77, 88, 99]
new_dict2 = defaultdict(list) # 字典所有的值默认都是列表{'': [], '': []}
for i in l2:
if i > 66:
new_dict2['k1'].append(i)
else:
new_dict2['k2'].append(i)
print(new_dict2)
# defaultdict(<class 'list'>, {'k2': [11, 22, 33, 44, 55, 66], 'k1': [77, 88, 99]})
有序字典(OrderedDict)
1. 普通字典:内部是无序的
d1 = dict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])
print(d1)
# {'k2': 'v2', 'k1': 'v1', 'k3': 'v3'}
# 内部无序 每次打印顺序都可能与上一次不同
print(d1.keys())
# dict_keys(['k1', 'k2', 'k3'])
2. 有序字典
from collections import OrderedDict
d2 = OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])
print(d2)
# OrderedDict([('k1', 'v1'), ('k2', 'v2'), ('k3', 'v3')])
d2['k1'] = 111
print(d2)
# OrderedDict([('k1', 111), ('k2', 'v2'), ('k3', 'v3')])
print(d2.keys())
# odict_keys(['k1', 'k2', 'k3'])
具名元组(namedtuple)
具名元组
# 生成可以使用名字来访问元素内容的tuple
from collections import namedtuple
# 1.先产生一个元组对象模板
point = namedtuple('长宽高', 'x, y, z')
# 2.创建数据
p1 = point('5cm', '1cm', '4cm')
p2 = point(7, 8, 9)
print(p1, p2)
# 长宽高(x='5cm', y='1cm', z='4cm') 长宽高(x=7, y=8, z=9)
print(p1.x) # 5cm
print(p1.y) # 1cm
time模块
time模块的常用方法:
1.time.sleep(secs)
推迟指定的时间运行,单位为秒
2.time.time()
获取当前时间戳
三种用于表示时间的格式(彼此之间可以转换)
1. 时间戳
距离1970年1月1日0时0分0秒至此相差的秒数
time.time()
2. 结构化时间
该时间类型主要是给计算机看的
time.localtime()

3.格式化时间
人最容易接收的一种时间格式 2000/1/21 11:11:11
time.strftime()
-
时间类型的转换
格式化时间 <==> 结构化时间 <==> 时间戳
# 时间戳<-->结构化时间
gmtime
localtime
# 结构化时间<-->格式化时间
strftime
strptime
time.strptime("2017-03-16","%Y-%m-%d")
time.strptime("2017/03","%Y/%m") 前后必须一致
ps:UTC时间比我所在的区域时间早八个小时(时区划分)

点击查看代码
# 时间字符串
print(time.strftime('%Y-%m-%d %X'))
print(time.strftime("%Y-%m-%d %H-%M-%S"))
# 时间元组:localtime将一个时间戳转换为当前时区的struct_time
print(time.localtime())
# print(time.gmtime())
# time.struct_time(tm_year=2022, tm_mon=3, tm_mday=29, tm_hour=19, tm_min=18, tm_sec=47, tm_wday=1, tm_yday=88, tm_isdst=0)
# 时间戳-->结构化时间
time.localtime()
time.gmtime()
# 结构化时间-->时间戳
time_tuple = time.localtime(20000000000)
print(time.mktime(time_tuple))
# 结构化时间-->字符串时间
# time.strftime("格式定义","结构化时间") 结构化时间参数若不传,则显示当前时间
print(time.strftime("%Y-%m-%d %X"))
'2022-03-29 19:32:13'
print(time.strftime("%Y-%m-%d", time.localtime(2000000000)))
'2033-05-18'
# 字符串时间-->结构化时间
#time.strptime(时间字符串,字符串对应格式)
print(time.strptime("2022-03-29", "%Y-%m-%d"))
'time.struct_time(tm_year=2022, tm_mon=3, tm_mday=29, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=88, tm_isdst=-1)'
print(time.strptime("03/29/2022", "%m/%d/%Y"))
'time.struct_time(tm_year=2022, tm_mon=3, tm_mday=29, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=88, tm_isdst=-1)'

点击查看代码
# 结构化时间 --> %a %b %d %H:%M:%S %Y串
# time.asctime(结构化时间) 如果不传参数,直接返回当前时间的格式化串
print(time.asctime(time.localtime(200000000))) # Tue May 4 03:33:20 1976
print(time.asctime()) # Tue Mar 29 19:42:59 2022
# 时间戳 --> %a %b %d %H:%M:%S %Y串
# time.ctime(时间戳) 如果不传参数,直接返回当前时间的格式化串
print(time.ctime(200000000)) # Tue May 4 03:33:20 1976
print(time.ctime()) # Tue Mar 29 19:45:21 2022
datetime模块
import datetime
print(datetime.date.today()) # 2022-03-29
print(datetime.datetime.today()) # 2022-03-29 19:49:46.418044
print(datetime.datetime.utcnow()) # 获取的是世界时间 格林威治时间
"""
date 意思就是年月日
datetime 意思就是年月日 时分秒
"""
res = datetime.datetime.today()
print(res.year)
print(res.month)
print(res.day)
print(res.hour)
print(res.minute)
print(res.second)
print(res.weekday()) # 1 星期0-6
print(res.isoweekday()) # 2 星期1-7
# 时间差
ctime = datetime.datetime.today()
time_tel = datetime.timedelta(days=3)
print(ctime) # 2022-03-29 20:04:15.002104
print(ctime + time_tel) # 2022-04-01 20:04:15.002104
"""
针对时间计算的公式
日期对象 = 日期对象 +/- timedelta对象
timedelta对象 = 日期对象 +/- 日期对象
"""
练习
练习
'''
将以下字符串转换成datetime类型:
'2017/9/30'
'2017年9月30日星期六'
'2017年9月30日星期六8时42分24秒'
'9/30/2017'
'9/30/2017 8:42:50'
'''
from datetime import datetime
d1 = datetime.strptime('2017/9/30', '%Y/%m/%d')
print(d1)
d2 = datetime.strptime('2017年9月30日星期六', '%Y年%m月%d日星期六')
print(d2)
d3 = datetime.strptime('2017年9月30日星期六8时42分24秒', '%Y年%m月%d日星期六%H时%M分%S秒')
print(d3)
d4 = datetime.strptime('9/30/2017', '%m/%d/%Y')
print(d4)
d5 = datetime.strptime('9/30/2017 8:42:50', '%m/%d/%Y %H:%M:%S')
print(d5)
'''
将以下datetime类型转换成字符串:
2017年9月28日星期4,10时3分43秒
Saturday, September 30, 2017
9/30/2017 9:22:17 AM
September 30, 2017
'''
d6 = datetime(2017,9,28,10,3,43)
print(d6.strftime('%Y年%m月%d日%A,%H时%M分%S秒'))
d7 = datetime(2017,9,30)
print(d7.strftime('%A,%B %d,%Y'))
d8 = datetime(2017,9,30,9,22,17)
print(d8.strftime('%m/%d/%Y %H:%M:%S %p'))
d9=datetime(2017,9,30)
print(d9.strftime('%B %d,%Y'))
'''
用系统时间输出以下字符串:
今天是2017年9月30日
今天是这周的第?天
今天是今年的第?天
今周是今年的第?周
今天是当月的第?天
'''
# 获取当前系统时间
m=datetime.now()
print(m.strftime('今天是%Y年%m月%d日'))
print(m.strftime('今天是这周的第%w天'))
print(m.strftime('今天是今年的第%j天'))
print(m.strftime('今周是今年的第%W周'))
print(m.strftime('今天是当月的第%d天'))
random模块
import random
print(random.random()) # 随机产生一个小数 0 ≤ n < 1.0
print(random.uniform(1, 3)) # 随机产生一个小数 1.0 ≤ n ≤ 3.0
print(random.randint(1, 9)) # 随机产生一个整数 1 ≤ n ≤ 9
print(random.randrange(1, 10, 2)) # 随机产生一个奇数 1 ≤ n ≤ 9
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
random.shuffle(l) # 打乱顺序
print(l)
print(random.choice(l)) # 随机单选
print(random.sample(l, 2)) # 随机多选 第二个参数控制个数
练习:随机生成验证码功能
点击查看代码
def random_code(n=4):
r_code = ''
for i in range(n):
r_nums = str(random.randint(0, 9))
r_upper = chr(random.randint(65, 90))
r_lower = chr(random.randint(97, 122))
res = random.choice([r_nums, r_upper, r_lower])
r_code += res
return r_code
print(random_code(6))
print(random_code(8))
os模块
# 该模块主要用于和系统打交道
import os
1.创建目录
点击查看代码
os.mkdir() # 只支持单级目录
os.mkdir(r'dirname') # 使用相对路径创建一个dirname文件夹
os.mkdir(r'dirname1/dirname2') # 报错
os.makedirs() # 支持单级和多级目录
os.makedirs(r'dirname') # makedirs可以创建单级目录
os.makedirs(r'dirname1/dirname2') # 也可以创建多级目录
2.删除目录
点击查看代码
os.rmdir()
os.rmdir(r'dirname') # 可以删除单级目录
os.rmdir(r'dirname1/dirname2') # 只能删除空的单级目录 即dirname2目录下不能其他文件或目录
os.removedirs()
os.removedirs(r'dirname1') # 可以删除单级目录
os.removedirs(r'dirname1/dirname2') # 删除目录后如果外层的目录也为空则继续删除 删除dirname2后如果dirname1为空则继续删除dirname1
3. 查看某个路径下所有的文件名称(文件、文件夹)
点击查看代码
os.listdir() # 组成列表
print(os.listdir()) # 默认当前路径
print(os.listdir(r'E:\PycharmProjects\Runfast''))
4. 删除文件、重命名文件
点击查看代码
os.remove(r'a.txt') # 删除
os.rename(r'a.txt', r'aa.txt') # 重命名
5. 获取当前路径、切换路径
点击查看代码
print(os.getcwd()) # 获取当前路径
os.chdir(r'dirname1/dirname2') # 切换路径
print(os.getcwd())
6. 软件开发目录规范 启动脚本兼容性操作
点击查看代码
os.path.dirname(__file__) # 动态获取当前执行文件所在的绝对路径
os.path.dirname(os.path.dirname(__file__)) # 每嵌套一层就往上切换一层
print(os.path.abspath(__file__)) # 动态获取当前执行文件自身的路径
7. 判断路径、文件是否存在
点击查看代码
print(os.path.exists(r'aaa')) # True 判断所给的路径是否存在
print(os.path.exists(r'bbb.py'))
print(os.path.isdir(r'aaa')) # True 判断路径是否是一个文件夹
print(os.path.isfile(r'bbb.py')) # True 判断路径是否是一个文件
8. 拼接路径
点击查看代码
base_dir = 'aaa'
exe_dir = 'b.py'
'''拼接成py文件的路径'''
print(base_dir + '/' + exe_dir) # 路径分隔符在不同的系统下是不一样的 使用加号的话兼容性极差
res = os.path.join(base_dir, exe_dir) # 能够自动识别当前操作系统的分隔符
print(res)
9. 获取文件大小(字节 bytes)
点击查看代码
print(os.path.getsize(r'aaa')) # 100bytes
print(os.path.getsize(r'b.txt')) # 10bytes
练习:选择指定文本文件并打开浏览
点击查看代码
# 展示某个文件下所有的文件名称 用户选择哪个就打开哪个
import os
# 1.先获取目标文件路径(动态获取 也可以省事先写死)
target_path = os.path.dirname(__file__)
full_path = os.path.join(target_path, 'dirname')
# 2.列举该路径下所有的文件名称
file_name_list = os.listdir(full_path) # ['','','','']
while True:
# 3.循环展示每个文件名称
for i, j in enumerate(file_name_list, start=1):
print(i, j)
# 4.获取用户选择的编号
target_num = input('请输入您想要查看的文件编号>>>:').strip()
# 5.判断是否是纯数字
if target_num.isdigit():
# 6.如果是纯数字 转换成整型
target_num = int(target_num)
# 7.判断数字在不在数量范围内
if target_num in range(1, len(file_name_list) + 1):
# 8.获取文件名称
file_name = file_name_list[target_num - 1]
# 9.拼接完整路径
full_file_path = os.path.join(full_path, file_name)
# 10.文件操作打开文件
with open(full_file_path, 'r', encoding='utf8') as f:
print(f.read())
else:
print('没有该编号的文件')
else:
print('编号只能是数字')
sys模块
"""该模块主要是跟python解释器打交道"""
import sys
# 1.列举当前执行文件所在的sys.path
print(sys.path)
# 2.获取解释器版本信息
print(sys.version)
# 3.获取平台信息
print(sys.platform)
# 4.自定义命令行操作
print(sys.argv)
点击查看代码
"""
cmd终端可以使用windows+r并输入cmd唤起
也可以在pycharm直接使用快捷方式Terminal
模拟cmd并自动切换到当前执行文件所在的路径下
"""
# if len(sys.argv) == 3: # 这里的判断也可以变成异常捕获的形式
# username = sys.argv[1]
# password = sys.argv[2]
# if username == 'cc' and password == '123':
# print('可以正常执行该文件')
# else:
# print('用户名或密码错误 没有该文件的执行权限')
# else:
# print('请输入用户名和密码 不能漏写或多写')
try:
username = sys.argv[1]
password = sys.argv[2]
except Exception:
print('请输入用户名和密码')
else:
if username == 'cc' and password == '123':
print('可以正常执行该文件')
else:
print('用户名或密码错误 没有该文件的执行权限')
json模块
'''json是一个序列化模块 主要用于跨语言传输数据'''
json.dumps() 序列化
将python数据类型转换成json格式字符串
json.loads() 反序列化
将json格式字符串转换成对应的数据类型

json格式数据的具体特征
数据基于网络传输肯定是二进制格式
在python中bytes类型的数据可以直接看成是二级制数据
python中哪些数据可以转成bytes类型(编码encode())
只有字符串可以!!!
# 由上述推论可知 json格式数据 本质应该属于字符串类型
'''双引号是json格式数据独有的标志符号!!!'''
具体操作
点击查看代码
d = {'k1': 'v1', 'k2':'v2'}
res = json.dumps(d) # 将字典转成json格式字符串
print(res, type(res)) # {"k1": "v1", "k2": "v2"} <class 'str'>
d = json.loads(res) # 将json格式字符串转成对应数据类型(此处为字典)
print(d, type(d)) # {'k1': 'v1', 'k2': 'v2'} <class 'dict'>

在文件中操作
点击查看代码
"""
如果json模块需要配合文件一起使用的话 有固定的方法
json.dump()
将其他数据类型直接写入文件(自动转json格式字符串)
json.load()
将文件数据直接转成对应的数据类型(自动反序列化)
"""
d = {'k1': 'v1', 'k2': 'v2'}
# 将上述字典写入文件
with open(r'a.txt', 'w', encoding='utf8') as f:
# f.write(d) 写入文件的数据类型必须是str 不能为dict
# f.write(str(d)) 可通过str()转换为str类型
# f.write(json.dumps(d)) 再序列化写入
json.dump(d, f)
# 将文件内容获取出来
with open(r'a.txt', 'r', encoding='utf8') as f:
# data = f.read()
# res = json.loads(data)
# print(res, type(res))
data = json.load(f)
print(data, type(data))
不是所有的数据类型都支持序列化
点击查看代码
+-------------------+---------------+
| Python | JSON |
+===================+===============+
| dict | object |
+-------------------+---------------+
| list, tuple | array |
+-------------------+---------------+
| str | string |
+-------------------+---------------+
| int, float | number |
+-------------------+---------------+
| True | true |
+-------------------+---------------+
| False | false |
+-------------------+---------------+
| None | null |
+-------------------+---------------+
'''集合就不行'''
subprocess模块
import subprocess
# dir在终端的意思就是查看当前路径下所有的文件名称
res = subprocess.Popen('dir',
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
print('stdout', res.stdout.read().decode('gbk')) # 获取正确命令执行之后的结果
print('stderr', res.stderr.read().decode('gbk')) # 获取错误命令执行之后的结果
"""
该模块可以实现远程操作其他计算机的功能
动态获取命令执行并返回结果
eg:类似于Xshell软件的功能
"""
hashlib加密模块
# 什么是加密
将明文(人看得懂)数据通过一些手段变成密文数据(人看不懂)
密文数据的表现形式一般都是一串没有规则的字符串
# 加密算法
加密算法有很多种>>>(将明文变密文的内部规则)
算法的难易程度可以根据产生密文的长短来判断
越长意味着算法越复杂
# 使用加密的场景
涉及到隐私数据的时候 应该考虑使用加密
最为常见的就是对用户的密码加密 防止密码泄露
基本使用
点击查看代码
import hashlib
# 1.指定算法>>>:md5算法(最为常见 一般的业务需求足够了)
md5 = hashlib.md5()
# 2.将明文数据传递给算法对象
md5.update(b'hello') # 只能接收bytes类型
"""如果字符串中是纯数字和英文 那么直接在前面加b转成bytes类型"""
# 3.获取加密之后的密文数据
res = md5.hexdigest()
print(res) # 5d41402abc4b2a76b9719d911017c592
# 在传入数据的时候 只要内容一致 那么算法的结果肯定一致
md5 = hashlib.md5()
md5.update(b'hello')
md5.update(b'world')
md5.update(b'jason')
print(md5.hexdigest()) # 8faebe82e744992e51c86845cac3e1b7
md5.update(b'helloworldjason')
print(md5.hexdigest()) # 8faebe82e744992e51c86845cac3e1b7
补充
1.加密之后的结果是无法直接反解密的
2.加盐处理 # 增加破解的难度
import hashlib
md5 = hashlib.md5()
# 加盐处理(添加一些额外的干扰项)
md5.update('你追我'.encode('utf8'))
md5.update(b'123')
print(md5.hexdigest()) # ce850e70febde5f3506fec0479dc0f96
3.动态加盐
干扰项动态变化
可以是用户名的一部分 也可以当前时间...
加密应用场景
点击查看
1.密码加密如何比对
用户输入的还是明文但是到了程序里面之后会采用相同的加密算法变成密文
之后拿着密文与跟数据库里面的密文比对如果一致就是密码正确不一致就是错误
2.文件内容一致性校验
作为软件的提供者 我们在提供安全软件的同时会对给该软件内容做加密处理得到一个该安全软件独有的密文
用户在下载软件之后也会对内容做相同的加密之后比对两次密文是否一致
如果是表示中途没有被修改 如果不是表示中途被修改过 可能存在病毒
针对大文件一致性校验的优化策略
如果一个文件有10G 那么如果全部读取并加密速度太慢
这个时候可以考虑对文件内容进行切片读取并加密的操作
logging模块
'''日志模块就是在程序的各个环境记录 便于后续的查看'''
日志等级
点击查看代码
import logging
# 日志按照重要程度分为五个级别:默认只有达到warning警告级别及以上才会记录日志
logging.debug('debug message') # 10
logging.info('info message') # 20
logging.warning('warning message') # 30
logging.error('error message') # 40
logging.critical('critical message') # 50
基本使用
点击查看代码
import logging
file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8', )
# 所有的格式不需要记忆 后续几乎都是拷贝加修改
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
handlers=[file_handler, ],
level=logging.ERROR
)
logging.error('警告')
日志模块的主要组成部分
点击查看代码
import logging
# 1.logger对象:产生日志 (无包装的产品)
logger = logging.getLogger('转账记录')
# 2.filter对象:过滤日志 (剔除不良品)
# 针对过滤功能完全可以不看 因为handler自带了基本的过滤操作
# 3.handler对象:控制日志的输出位置(文件、终端...) (产品分类)
hd1 = logging.FileHandler('a1.log',encoding='utf-8') # 输出到文件中
hd2 = logging.FileHandler('a2.log',encoding='utf-8') # 输出到文件中
hd3 = logging.StreamHandler() # 输出到终端
# 4.format对象:控制日志的格式 (包装)
fm1 = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
)
fm2 = logging.Formatter(
fmt='%(asctime)s - %(name)s: %(message)s',
datefmt='%Y-%m-%d',
)
# 5.给logger对象绑定handler对象
logger.addHandler(hd1)
logger.addHandler(hd2)
logger.addHandler(hd3)
# 6.给handler绑定formmate对象
hd1.setFormatter(fm1)
hd2.setFormatter(fm2)
hd3.setFormatter(fm1)
# 7.设置日志等级
logger.setLevel(10) # debug
# 8.记录日志
logger.debug('写了半天 好累啊 好热啊!!!')
配置字典
点击查看代码
import logging
import logging.config
# 定义日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
# 定义日志输出格式 结束
# 自定义文件路径
logfile_path = 'a3.log'
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {}, # 过滤日志
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
}, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
# '注册记录': {
# 'handlers': ['console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
# 'level': 'WARNING',
# 'propagate': True, # 向上(更高level的logger)传递
# }, # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
},
}
# 使用日志字典配置
# logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
# logger1 = logging.getLogger('转账记录')
# logger2 = logging.getLogger('注册记录')
# logger1.debug('好好的 不要浮躁 努力就有收获')
# logger2.warning('尊敬的VIP客户 晚上好 您又来啦')
logging.config.dictConfig(LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger('红浪漫顾客消费记录')
'''loggers配置中使用空字符串作为字典的键 兼容性最好!!!'''
logger1.debug('奥利奥 给力给 奥里给')
配置字典如何在项目中使用
点击查看代码
# 按照软件开发目录规范编写使用
日志字典数据应该放在哪个py文件内
字典数据是日志模块固定的配置 写完一次之后几乎都不需要动
它属于配置文件
"""配置文件中变量名推荐全大写"""
该案例能够带你搞明白软件开发目录规范中所有py文件的真正作用
def get_logger(msg):
# 记录日志
logging.config.dictConfig(settings.LOGGING_DIC) # 自动加载字典中的配置
logger1 = logging.getLogger(msg)
# logger1.debug(f'{username}注册成功') # 这里让用户自己写更好
return logger1
第三方模块
点击查看代码
# 如何利用工具
需要使用python解释器提供的pip工具
pip的路径在python解释器文件夹内的scripts目录下
'''
如果下载终端中直接使用pip目录 需要添加环境变量
python解释器的路径: D:\python36
pip工具的路径: D:\python36\scripts
我们在使用pip工具的时候 为了区分版本会人为的将python3的pip工具
写成pip3 python2的pip工具写成pip
'''
# 如何查看当前解释器下载的第三方模块(通常都是借助于编辑器查看)
settings
project
python interprter
会列举出所有的第三方模块
纯净的解释器默认只有两个
pip
setuptools
# 如何下载第三方模块
方式1:直接使用命令行(cmd终端直接敲)
pip3 install 模块名 '''该方式默认下载的是最新版本'''
pip3 install 模块名==版本号 '''自定义下载版本号'''
ps:pip工具默认是从国外的仓库下载模块 速度会比较慢 可以修改
pip3 install 模块名 -i 仓库地址 # 命令行临时修改地址
"""
针对仓库地址 直接百度搜索pip源即可获得
(1)阿里云http://mirrors.aliyun.com/pypi/simple/
(2)豆瓣http://pypi.douban.com/simple/
(3)清华大学https://pypi.tuna.tsinghua.edu.cn/simple/
(4)中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
(5)华中科技大学http://pypi.hustunique.com/
"""
方式2:利用编程软件提供的快捷方法
还是今日到查看下载的第三方模块界面
双击任意一个模块名称或者左下角加号按钮
在搜索框中输入你想要下载的模块即可
并且可以在左侧勾选specify version选择版本
# pycharm可以换源
左下方点击manage repositoires管理地址即可
"""
在下载第三方模块的时候可能会报错
1.报错信息中含有timeout关键字
原因是你当前计算机的网络不稳定 重新执行多次或者切换网络
2.报错信息中没有太多的关键字 并且很长
拷贝最后一行错误信息 去百度
格式: pip3下载模块名报错错误信息
"""
openpyxl模块
excel文件的版本及后缀
2003版本之前 excel的文件后缀是xls
2003版本之后 excel的文件后缀是xlsx、csv
在python中能够处理excel文件的模块有很多 其中最出名的有
xlrd、xlwt分别控制excel文件的读写 能够兼容所有版本的文件
openpyxl针对03版本之前的兼容性可能不好 但是功能更加强大
如何创建excel文件
点击查看代码
from openpyxl import Workbook
wb = Workbook() # 创建excel文件
wb1 = wb.create_sheet('学员名单') # 创建工作簿
wb2 = wb.create_sheet('缴费名单') # 创建工作簿
wb3 = wb.create_sheet('消费记录') # 创建工作簿
wb4 = wb.create_sheet('线上赌场', 0) # 还可以指定工作簿位置
wb1.title = '学员名单名称修改'
wb.save('111.xlsx') # 保存excel文件
如何写数据
点击查看代码
# 写普通数据方式1
wb1['A3'] = 666
# 写普通数据方式2
wb1.cell(row=3, column=4, value=999)
# 批量写普通数据
wb1.append(['id','username','password'])
# 写公式数据(也可以在python代码中处理完毕以普通数据写入)
wb1['A6'] = '=sum(A4:A5)'
如何读数据
点击查看代码
from openpyxl import load_workbook
wb = load_workbook('1.xlsx',read_only=True,data_only=True)
print(wb.sheetnames) # 获取1.xlsx中所有的工作薄名称 结果是列表数据类型
wb1 = wb['test'] # 拿到工作薄test对象
# 第一种取值方式
print(wb1['A3'].value) # 不是结果 需要再点value
print(wb1['A6'].value) # 获取用函数统计的数据,发生无法取到值
"""
第一需要加一个参数
第二需要人为的先去修改一下用程序产生的excel表格(不可能用程序产生excel文件之后又直接再用程序去读入,这样没有任何实际意义 通常用程序创建好表格后给人看,人讲自己修改的表格再交由程序处理)
"""
print(wb1.cell(row=3,column=4).value) # 第二种取值方式
# 获取一行行的数据
for row in wb1.rows: # 拿到每一行的数据
for data in row: # 拿到一行行数据里面每一个单元格的数据
print(data.value)
# 获取一列列的数据(如果想获取 必须把readonly去掉)
for column in wb1.columns: # 拿到每一列的数据
for r in column: # 拿到一列列数据里面每一个单元格的数据
print(r.value)
# 获取最大的行数和列数
print(wb1.max_row)
print(wb1.max_column)

浙公网安备 33010602011771号