常用模块 1. time模块 2. datetime模块 3. 时间模块需要掌握的操作 4. random模块 5. os模块 6. sys模块 7. shutil模块 8. json和pickle模块 9. xml和shelve模块(了解) 10. configparser模块 11. hashlib模块 12. subprocess模块 13. logging模块 14. re模块

常用模块
1. time模块
2. datetime模块
3. 时间模块需要掌握的操作
4. random模块
5. os模块
6. sys模块
7. shutil模块
8. json和pickle模块
9. xml和shelve模块(了解)
10. configparser模块
11. hashlib模块
12. subprocess模块
13. logging模块
14. re模块

1.1 时间的格式

1) 时间戳(timestamp):

​ 从1970年到现在经过的秒数

作用:

​ 用于时间间隔的计算

print(time.time())#1585550344.012155

2) 按照某种格式显示的时间(format string):

作用 : 展示时间 2020-03-30 11:11:11

print(time.strftime('%Y-%m-%d %H:%M:%S %p'))
print(time.strftime('%Y-%m-%d %X'))
print(time.strftime('%Y-%m-%d %H %p'))

#2020-03-30 14:39:04 PM
#2020-03-30 14:39:04
#2020-03-30 14 PM

3) 结构化的时间(struct_time):

作用 : 用于单独获取时间的某一部分

res = time.localtime()
print(res)  
# time.struct_time(tm_year=2020, tm_mon=3, tm_mday=30, tm_hour=14, tm_min=41, tm_sec=27, tm_wday=0, tm_yday=90, tm_isdst=0)
print(res.tm_year)  	# 年:2020
print(res.tm_yday)  	# 今年的第90天
print(res.tm_hour)  	# 时:14
print(res.tm_min)  		# 分:41
print(res.tm_sec)  		# 秒:27
print(res.tm_mday)  	# 这个月的第30天
print(res.tm_mon)  		# 月:3
print(res.tm_wday)  	# 星期(0-6):0(星期一)
print(res.tm_zone)  	# 当前的时间区域

2. datetime模块

print(datetime.datetime.now())
print(datetime.datetime.now() + datetime.timedelta(days=3))
#计算3天后的时间
print(datetime.datetime.now() + datetime.timedelta(weeks=1))
#计算7天后的时间

3. 时间模块需要掌握的操作

3.1 时间格式的转换

struct_time->时间戳

import time
s_time=time.localtime()
print(s_time)
print(time.mktime(s_time))

时间戳->struct_time

tp_time=time.time()
print(time.localtime(tp_time))

世界标准时间与本地时间

print(time.localtime())# 上海时区(东八区)
print(time.gmtime()) # 世界标准时间,了解
print(time.localtime(333333333))
print(time.gmtime(333333333))

struct_time->格式化的字符串形式的时间

s_time=time.localtime()
print(time.strftime('%Y-%m-%d %H:%M:%S',s_time))
#2020-03-30 14:58:30
print(time.strftime('%Y-%m-%d %H:%M:%S'))
#2020-03-30 14:58:30
print(time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S'))
#time.struct_time(tm_year=1988, tm_mon=3, tm_mday=3, tm_hour=11, tm_min=11, tm_sec=11, tm_wday=3, tm_yday=63, tm_isdst=-1)

3.2 format string<------>timestamp

'1988-03-03 11:11:11'+7
# format string--->struct_time--->timestamp
struct_time=time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S')
timestamp=time.mktime(struct_time)+7*86400
print(timestamp)#573966671.0

# format string<---struct_time<---timestamp
res=time.strftime('%Y-%m-%d %X',time.localtime(timestamp))
print(res)#1988-03-10 11:11:11

了解知识:

import time
print(time.asctime())# Mon Mar 30 15:03:54 常用于Linux操作系统

import datetime
print(datetime.datetime.now())
print(datetime.datetime.fromtimestamp(333333))
# 时间戳直接转成日期格式 1970-01-05 04:35:33

4. random模块

4.1 常用命令

import random

print(random.random())
#(0,1)----float    大于0且小于1之间的小数
print(random.randint(1, 3)) 
# [1,3]    大于等于1且小于等于3之间的整数

print(random.randrange(1, 3)) 
# [1,3)    大于等于1且小于3之间的整数

print(random.choice([111, 'aaa', [4, 5]])) 
# 1或者23或者[4,5]

print(random.sample([111, 'aaa', 'ccc','ddd'],2))#任意2个组合
print(random.sample([111, 'aaa', 'ccc','ddd'],3))#任意三个组合

print(random.uniform(1, 3)) 
# 大于1小于3的小数,如1.927109612082716

item = [1, 3, 5, 7, 9]
random.shuffle(item)  # 打乱item的顺序,相当于"洗牌"
print(item)

4.2 应用案例:随机验证码

import random
#随机生成4位大写字母+数字的验证码
def make_code(size=4):
    res=''
    for i in range(size):
        s1=chr(random.randint(65,90))#从26大写字母中随机取出一个
        s2=str(random.randint(0,9))#从10个数字中随机取出一个
        res+=random.choice([s1,s2])#随机取出一个,加到res中
    return res
print(make_code(6))

ps:
    小写字母则加入:s2 = chr(random.randint(97,122))

5. os模块

5.1 常用命令

os.getcwd() 获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname")  改变当前脚本工作目录;相当于shell下cd
os.curdir  返回当前目录: ('.')
os.pardir  获取当前目录的父目录字符串名:('..')
os.makedirs('dirname1/dirname2')    可生成多层递归目录
os.removedirs('dirname1')    若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname')    生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname')    删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname')    列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove()  删除一个文件
os.rename("oldname","newname")  重命名文件/目录
os.stat('path/filename')  获取文件/目录信息
os.sep    输出操作系统特定的路径分隔符,win下为"\",Linux下为"/"
os.linesep    输出当前平台使用的行终止符,win下为"	
",Linux下为"
"
os.pathsep    输出用于分割文件路径的字符串 win下为;,Linux下为:
os.name    输出字符串指示当前使用平台。win->'nt'; Linux->'posix'
os.system("bash command")  运行shell命令,直接显示
os.environ  获取系统环境变量
os.path.abspath(path)  返回path规范化的绝对路径
os.path.split(path)  将path分割成目录和文件名二元组返回
os.path.dirname(path)  返回path的目录。其实就是os.path.split(path)的第一个元素
os.path.basename(path)  返回path最后的文件名。如何path以/或结尾,那么就会返回空值。即os.path.split(path)的第二个元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是绝对路径,返回True
os.path.isfile(path)  如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path)  如果path是一个存在的目录,则返回True。否则返回False
os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
os.path.getatime(path)  返回path所指向的文件或者目录的最后存取时间
os.path.getmtime(path)  返回path所指向的文件或者目录的最后修改时间
os.path.getsize(path) 返回path的大小

5.2 常用命令解析

os.listdir() 获取某一个文件夹下的子文件和文件名

# 获取某一个文件夹下所有的子文件以及子文件夹的名字
res=os.listdir('../../week4')
['day16', 'day17', 'day18', 'day19', 'day20']
res=os.listdir('.')
#['01 时间模块.py', '02 random模块.py', '03 os模块.py', '04 sys模块.py', 'day21 笔记.md', 'run.py', '作业(3).txt', '笔记.txt']
print(res)

os.path.getsize() 查看文件大小

size=os.path.getsize(r'作业(3).txt')#218
print(size)

os.remove()  #删除一个文件
os.rename("作业(3).txt","作业.txt")  #重命名文件/目录

print(os.listdir('.'))
['01 时间模块.py', '02 random模块.py', '03 os模块.py', '04 sys模块.py', 'day21 笔记.md', 'run.py', '作业.txt', '笔记.txt']

os.environ 获取系统环境变量

# 规定:key与value必须都为字符串

os.environ['aaaaaaaaaa']='111'
print(os.environ)

文件相关操作

print(__file__)
#E:/python学习/week5/day21/03 os模块.py
print(os.path.abspath(__file__)) #返回path规范化的绝对路径
#E:老男孩python学习week5day21 3 os模块.py

print(os.path.dirname(r'/a/b/c/d.txt'))#路径的文件夹
print(os.path.basename(r'/a/b/c/d.txt'))#路径的文件名
#/a/b/c
#d.txt
print(os.path.split('/a/b/c/d.txt'))        
# 会把路径和文件切分开:('/a/b/c', 'd.txt')
print(os.path.split(__file__))              
# 会把路径和文件切分开:('E:/python学习/week5/day21', '03 os模块.py')

print(os.path.isabs(r'../week5'))    # 判断是否为绝对路径

print(os.path.isfile(r'笔记.txt'))
print(os.path.isfile(r'aaa'))
print(os.path.isdir(r'aaa'))
#True
#False
#True
print(os.path.join('a','s','b','c','d'))#文件拼接
print(os.path.join('a','/','b','c','d'))
print(os.path.join('a','C:','b','c','d'))
#ascd
#/bcd
#C:bcd

规定起始目录

# 推荐用这种
BASE_DIR=os.path.dirname(os.path.dirname(__file__))
print(BASE_DIR)
# 不推荐用这种
BASE_DIR=os.path.normpath(os.path.join(
    __file__,
    '..',
    '..'
))
print(BASE_DIR)
# 在python3.5之后,推出了一个新的模块pathlib  
#模块功能清晰,但版本太新,不推荐
from pathlib import Path

res = Path(__file__).parent.parent
print(res)
res=Path('/a/b/c') / 'd/e.txt'
print(res)#acde.txt

print(res.resolve())# 格式规范化,把 / 变成 :E:acde.txt

6. sys模块

6.1 常用命令

import sys
sys.argv           #命令行参数List,第一个元素是程序本身路径
sys.exit(n)        #退出程序,正常退出时exit(0)
sys.version        #获取Python解释程序的版本信息
sys.maxint         #最大的Int值
sys.path           #返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform       #返回操作系统平台名称

6.2 常用命令解析

sys.argv 命令行参数List,第一个元素是程序本身路径

# python3.8 run.py 1 2 3
# sys.argv在Python解释器内,接受外界传来的值,获取的是解释器后参数值
print(sys.argv)
#['E:/python学习/week5/day21/run.py','1','2','3']

文件拷贝的原始方法

src_file = input('原文件路径:').strip()
dst_file = input('新文件路径:').strip()

with open(r'%s'%src_file, mode='rb') as read_f,
    open(r'%s'%dst_file, mode='wb') as write_f:
    for line in read_f:
        write_f.write(line)

文件拷贝的新方法

src_file = sys.argv[1]
dst_file = sys.argv[2]
['E:/python学习/week5/day21/run.py','a.txt','b.txt']
with open(r'%s'%src_file, mode='rb') as read_f,
    open(r'%s'%dst_file, mode='wb') as write_f:
    for line in read_f:
        write_f.write(line)
# 在run.py所在的文件夹下,按住shift,右键,选择“在此处打开power shell”,输入
# 格式:python3 run.py 原文件路径 新文件路径
# python3 run.py D:1.docx D:2.docx   #拷贝成功

6.3 应用:进度条

#基础知识
# print('[%-50s]' %'#')
# print('[%-50s]' % '##')
# print('[%-50s]' % '###')

# 输出:
[#                                                 ]
[##                                                ]
[###                                               ]
import time
#进度条显示
res = ''
for i in range(50):
    res += '#'
    time.sleep(0.2)
    print('
 [%-50s]' % res, end='')
    
# 输出:  [##################################################]
    
#进阶
import time
recv_size = 0
total_size = 25600

while recv_size < total_size:
    # 模拟网速
    time.sleep(0.2)
    # 下载了1024个字节的数据
    recv_size += 1024
    # 打印进度条
    # print(recv_size)
    percent = recv_size / total_size    # 1024 / 25600
    if percent > 1:
        percent = 1
    res = int(50 * percent) * '>'
    print('
 [%-50s] %d%%' % (res,percent*100), end='')
    
#函数最终版
import time

def progress(percent):
    if percent > 1:
        percent = 1
    res = int(50 * percent) * '>'
    print('
 [%-50s] %d%%' % (res,percent*100), end='')

recv_size = 0
total_size = 25600

while recv_size < total_size:
    time.sleep(0.2)
    recv_size += 1024
    percent = recv_size / total_size    # 1024 / 25600
    progress(percent)

7. shutil模块

​ 高级的 文件、文件夹、压缩包 处理模块

7.1 基本使用

import shutil
shutil.copyfile( src, dst)   #从源src复制到dst中去。 如果当前的dst已存在的话就会被覆盖掉

shutil.move( src, dst)  #移动文件或重命名

shutil.copymode( src, dst) #只是会复制其权限其他的东西是不会被复制的

shutil.copystat( src, dst) #复制权限、最后访问时间、最后修改时间

shutil.copy( src, dst)  #复制一个文件到一个文件或一个目录

shutil.copy2( src, dst)  #在copy上的基础上再复制文件最后访问时间与修改时间也复制过来了,类似于cp –p的东西

shutil.copy2( src, dst)  #如果两个位置的文件系统是一样的话相当于是rename操作,只是改名;如果是不在相同的文件系统的话就是做move操作

shutil.copytree( olddir, newdir, True/Flase) #把olddir拷贝一份newdir,如果第3个参数是True,则复制目录时将保持文件夹下的符号连接,如果第3个参数是False,则将在复制的目录下生成物理副本来替代符号连接

shutil.rmtree( src )   #递归删除一个目录以及目录内的所有内容

7.2 高级使用

shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中

shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

shutil.copyfile(src, dst)拷贝文件

shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在

shutil.copymode(src, dst) 仅拷贝权限。内容、组、用户均不变

shutil.copymode('f1.log', 'f2.log') #目标文件必须存在

shutil.copystat(src, dst) 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log') #目标文件必须存在

shutil.copy(src, dst) 拷贝文件和权限

shutil.copy('f1.log', 'f2.log')

shutil.copy2(src, dst) 拷贝文件和状态信息

shutil.copy2('f1.log', 'f2.log')

shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹

shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) 
#目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除 

shutil.copytree('f1', 'f2', symlinks=True, ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))

'''
通常的拷贝都把软连接拷贝成硬链接,即对待软连接来说,创建新的文件
'''

shutil.rmtree(path[, ignore_errors[, onerror]]) 递归的去删除文件

shutil.rmtree('folder1')

shutil.move(src, dst) 递归的去移动文件,它类似mv命令,其实就是重命名。

shutil.move('folder1', 'folder3')

shutil.make_archive(base_name, format,...)

创建压缩包并返回文件路径,例如:zip、tar

创建压缩包并返回文件路径,例如:zip、tar

base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如 data_bak                       =>保存至当前路径
如:/tmp/data_bak =>保存至/tmp/
format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir: 要压缩的文件夹路径(默认当前目录)
owner: 用户,默认当前用户
group: 组,默认当前组
logger: 用于记录日志,通常是logging.Logger对象

#将 /data 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
  
  
#将 /data下的文件打包放置 /tmp/目录
import shutil
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()

# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()

zipfile压缩解压缩

import tarfile

# 压缩
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close()


# 解压
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close()

tarfile压缩解压缩

8. json和pickle模块

8.1 什么是序列化和反序列化

内存中的数据类型---->序列化---->特定的格式(json格式或者pickle格式)
内存中的数据类型<----反序列化<----特定的格式(json格式或者pickle格式)

土办法:

 {'aaa':111}--->序列化str({'aaa':111})----->"{'aaa':111}"
 {'aaa':111}<---反序列化eval("{'aaa':111}")<-----"{'aaa':111}"

8.2 为何要序列化

序列化得到结果=>特定的格式的内容有两种用途
1、可用于存储=》用于存档
2、传输给其他平台使用=》跨平台数据交互
python java
列表 特定的格式 数组

强调:
针对用途1=》:可是一种专用的格式=》pickle只有python可以识别
针对用途2=》:应该是一种通用、能够被所有语言识别的格式=》json

8.3 如何序列化和反序列化

示范1

import json
# 序列化
json_res=json.dumps([1,'aaa',True,False])
# print(json_res,type(json_res)) # "[1, "aaa", true, false]"

# 反序列化
l=json.loads(json_res)
print(l,type(l))

示范2

# 序列化的结果写入文件的复杂方法
json_res=json.dumps([1,'aaa',True,False])
with open('test.json',mode='wt',encoding='utf-8') as f:
    f.write(json_res)

# 将序列化的结果写入文件的简单方法
with open('test.json',mode='wt',encoding='utf-8') as f:
    json.dump([1,'aaa',True,False],f)


# 从文件读取json格式的字符串进行反序列化操作的复杂方法
with open('test.json',mode='rt',encoding='utf-8') as f:
    json_res=f.read()
    l=json.loads(json_res)
    print(l,type(l))

# 从文件读取json格式的字符串进行反序列化操作的简单方法
with open('test.json',mode='rt',encoding='utf-8') as f:
    l=json.load(f)
    print(l,type(l))

8.4 json强调

json格式兼容的是所有语言通用的数据类型,不能识别某一语言的所独有的类型

一定要搞清楚json格式,不要与python混淆

json.dumps({1,2,3,4,5})#json中没有Python集合的概念
# 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads
l=json.loads('[1, "aaa", true, false]')
l=json.loads("[1,1.3,true,'aaa', true, false]")
print(l[0])

8.5 json了解知识

#在python解释器2.7与3.6之后都可以json.loads(bytes类型),但唯独3.5不可以
l = json.loads(b'[1, "aaa", true, false]')
print(l, type(l))

with open('test.json',mode='rb') as f:
    l=json.load(f)


res=json.dumps({'name':'哈哈哈'})
print(res,type(res))

res=json.loads('{"name": "u54c8u54c8u54c8"}')
print(res,type(res))

8.6 猴子补丁和ujson

什么是猴子补丁?

​ 猴子补丁的核心就是用自己的代码替换所用模块的源代码

猴子补丁的功能(一切皆对象)

  拥有在模块运行时替换的功能, 例如: 一个函数对象赋值给另外一个函数对象(把函数原本的执行的功能给替换了)

猴子补丁的应用

#json 在dumps和loads的运行速度不如ujson,可以在程序入口处将两个方法替换为ujson中的dumps和loads方法
#在入口处打猴子补丁,即run.py
import json
import ujson

def monkey_patch_json():
    json.__name__ = 'ujson'
    json.dumps = ujson.dumps
    json.loads = ujson.loads

monkey_patch_json() # 在入口文件出运行

#import ujson as json # 不行,只需要替换两个方法,而不是全部替换

# 后续代码中的应用,使用不发生改变
json.dumps()
json.dumps()
json.loads()
json.loads()

8.7 pickle模块

import pickle
res=pickle.dumps({1,2,3,4,5})
print(res,type(res))

s=pickle.loads(res)
print(s,type(s))

9. xml和shelve模块(了解)

9.1 shelve模块

shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;

key必须为字符串,而值可以是python所支持的数据类型

import shelve

f=shelve.open(r'sheve.txt')
# f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
# f['stu2_info']={'name':'gangdan','age':53}
# f['school_info']={'website':'http://www.pypy.org','city':'beijing'}

print(f['stu1_info']['hobby'])
f.close()

9.2 xml模块

xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是xml。

xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:

# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子节点找,只找一个
# print(root.findall('country')) #在root的子节点找,找所有
import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)
 
#遍历xml文档
for child in root:
    print('========>',child.tag,child.attrib,child.attrib['name'])
    for i in child:
        print(i.tag,i.attrib,i.text)
 
#只遍历year 节点
for node in root.iter('year'):
    print(node.tag,node.text)
#---------------------------------------

import xml.etree.ElementTree as ET
 
tree = ET.parse("xmltest.xml")
root = tree.getroot()
 
#修改
for node in root.iter('year'):
    new_year=int(node.text)+1
    node.text=str(new_year)
    node.set('updated','yes')
    node.set('version','1.0')
tree.write('test.xml')
 
 
#删除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)
 
tree.write('output.xml')
#在country内添加(append)节点year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
    for year in country.findall('year'):
        if int(year.text) > 2000:
            year2=ET.Element('year2')
            year2.text='新年'
            year2.attrib={'update':'yes'}
            country.append(year2) #往country节点下添加子节点

tree.write('a.xml.swap')

10. configparser模块

用于读取某些特定格式的配置文件(例如:ini,cft结尾的)

#配置文件如下:
# 注释1: 注释2

[section1]
k1 = v1
k2:v2
user=egon
age=18
is_admin=true
salary=31
[section2]
k1 = v1
import configparser
#将配置文件加载到内存
config=configparser.ConfigParser()
config.read('test.ini')

# 1、获取sections
print(config.sections())
#['section1', 'section2']

# 2、获取某一section下的所有options
print(config.options('section1'))
#['k1', 'k2', 'user', 'age', 'is_admin', 'salary']

# 3、获取items
print(config.items('section1'))
# [('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]

# 4、获取指定配置信息
res=config.get('section1','user')
print(res,type(res))

res=config.getint('section1','age')
print(res,type(res))

res=config.getboolean('section1','is_admin')
print(res,type(res))

res=config.getfloat('section1','salary')
print(res,type(res))

11. hashlib模块

1 什么是哈希hash

hash一类算法,该算法接受传入的内容,经过运算得到一串hash值

hash值的特点:

  • I 只要传入的内容一样,得到的hash值必然一样
  • II 不能由hash值返解成内容
  • III 不管传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是一定

2 hash的用途

用途1:特点II用于密码密文传输与验证
用途2:特点I、III用于文件完整性校验

3 如何用

hash算法就像一座工厂,工厂接收你送来的原材料(可以用m.update()为工厂运送原材料),经过加工返回的产品就是hash值

import hashlib

m=hashlib.md5()
m.update('hello'.encode('utf-8'))
m.update('world'.encode('utf-8'))
res=m.hexdigest() # 'helloworld'
print(res)

m1=hashlib.md5('he'.encode('utf-8'))
m1.update('llo'.encode('utf-8'))
m1.update('w'.encode('utf-8'))
m1.update('orld'.encode('utf-8'))
res=m1.hexdigest()# 'helloworld'
print(res)
'''
注意:把一段很长的数据update多次,与一次update这段长数据,得到的结果一样
但是update多次为校验大文件提供了可能。
'''

4 应用

示例1:模拟撞库

#alex3714的m5哈希值
cryptograph='aee949757a2e698417463d47acac93df'
import hashlib

# 制作密码字段
passwds=[
    'alex3714',
    'alex1313',
    'alex94139413',
    'alex123456',
    '123456alex',
    'a123lex',
]

dic={}
for p in passwds:
    res=hashlib.md5(p.encode('utf-8'))
    dic[p]=res.hexdigest()

# 模拟撞库得到密码
for k,v in dic.items():
    if v == cryptograph:
        print('撞库成功,明文密码是:%s' %k)
        break

示例2:提升撞库的成本=>密码加盐(对密码添加额外字段)

import hashlib

m=hashlib.md5()

m.update('天王'.encode('utf-8'))
m.update('alex3714'.encode('utf-8'))
m.update('盖地虎'.encode('utf-8'))
print(m.hexdigest())

#对于一个很大的文件,并不是将全部内容进行加密
#而是选取文件的几个部分组成的数据,进行加密,
#这样能很好的提升文件校验效率
#m.update(文件所有的内容)
#m.hexdigest()

f=open('a.txt',mode='rb')
f.seek()
f.read(2000) # 巨琳
m1.update(文见的一行)

m1.hexdigest()

12. subprocess模块

subprocess模块,主要执行子进程,用于执行系统命令的模块

注意:其返回值的编码类型,与所使用的操作系统有关,

windows -》gbk, mac-》utf-8

import subprocess

obj=subprocess.Popen('echo 123 ; ls / ; ls /root',shell=True,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
                 )
# print(obj)
# res=obj.stdout.read()
# print(res.decode('utf-8'))

err_res=obj.stderr.read()
print(err_res.decode('utf-8'))

13. logging模块

1 日志级别和基本配置

import logging

# 一:日志配置
logging.basicConfig(
    # 1、日志输出位置:1、终端 2、文件
    # filename='access.log', # 不指定,默认打印到终端

    # 2、日志格式
    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',

    # 3、时间格式
    datefmt='%Y-%m-%d %H:%M:%S %p',

    # 4、日志级别
    # critical => 50
    # error => 40
    # warning => 30
    # info => 20
    # debug => 10
    level=30,
)

# 二:输出日志
logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')

'''
# 注意下面的root是默认的日志名字
WARNING:root:警告warn
ERROR:root:错误error
CRITICAL:root:严重critical
'''

2 日志配置字典

"""
日志配置字典LOGGING_DIC
"""
# 1、定义三种日志输出格式,日志中可能用到的格式化串如下
# %(name)s Logger的名字
# %(levelno)s 数字形式的日志级别
# %(levelname)s 文本形式的日志级别
# %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
# %(filename)s 调用日志输出函数的模块的文件名
# %(module)s 调用日志输出函数的模块名
# %(funcName)s 调用日志输出函数的函数名
# %(lineno)d 调用日志输出函数的语句所在的代码行
# %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
# %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(thread)d 线程ID。可能没有
# %(threadName)s 线程名。可能没有
# %(process)d 进程ID。可能没有
# %(message)s用户输出的消息

# 2、强调:其中的%(name)s为getlogger时指定的名字
standard_format = '%(asctime)s - %(threadName)s:%(thread)d - 日志名字:%(name)s - %(filename)s:%(lineno)d -' 
                  '%(levelname)s - %(message)s'

simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'

test_format = '%(asctime)s] %(message)s'

# 3、日志配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    #  多个日志格式
    'formatters': {
    #定制的日志格式的名字
        'standard': {
            'format': standard_format
        },
        'simple': {
            'format': simple_format
        },
        'test': {
            'format': test_format
        },
    },
    'filters': {},
    # handlers是日志的接收者,控制日志的输出位置,不同的handler会将日志输出到不同的位置
    'handlers': {
        #打印到终端的日志
        'console': {
            'level': 'DEBUG',#日志的级别,也可以写成数字
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'simple'
        },
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            # 'maxBytes': 1024*1024*5,  # 日志大小 5M
            'maxBytes': 1000,
            'backupCount': 5,
            'filename': 'a1.log',  # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
            'encoding': 'utf-8',
            'formatter': 'standard',

        },
        #打印到文件的日志,收集info及以上的日志
        'other': {
            'level': 'DEBUG',
            'class': 'logging.FileHandler',  # 保存到文件
            'filename': 'a2.log', # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
            'encoding': 'utf-8',
            'formatter': 'test',

        },
    },
    # loggers是日志的产生者,产生不同级别的日志,产生的日志会传递给handler然后控制输出
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        'kkk': {
            'handlers': ['console','other'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
            'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
        },
        '终端提示': {
            'handlers': ['console',],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG',  # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
            'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
        },
        #真对多种相同的输出,靠不同的日志名去区分功能的,可以填''
        '': {
            'handlers': ['default', ],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG',  # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
            'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
        },
    },
}

3 logging的使用

import settings

# !!!强调!!!
# 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
# from logging import config
# from logging import getLogger

# 也可以使用如下导入
import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.

# logging.config.dictConfig(settings.LOGGING_DIC)
# print(logging.getLogger)

# 接下来要做的是:拿到日志的产生者即loggers来产生日志
# 第一个日志的产生者:kkk
# 第二个日志的产生者:bbb

# 但是需要先导入日志配置字典LOGGING_DIC
import settings
from logging import config,getLogger

config.dictConfig(settings.LOGGING_DIC)


# logger1=getLogger('kkk')
# logger1.info('这是一条info日志')

# logger2=getLogger('终端提示')
# logger2.info('logger2产生的info日志')

# logger3=getLogger('用户交易')
# logger3.info('logger3产生的info日志')

logger4=getLogger('用户常规')
logger4.info('logger4产生的info日志')

# 补充两个重要额知识
# 1、日志名的命名
#    日志名是区别日志业务归属的一种非常重要的标识

# 2、日志轮转
#    日志不能轻易的删除,不应该在一个文件里不断累加,
#    定期的将文件中的内容剪切走,(设置阈值,超过多少M执行)
#    日志记录着程序员运行过程中的关键信息

14. re模块

1 什么是正则?

 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。****(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

2 常用匹配模式(元字符)

http://blog.****.net/yufenghyc/article/details/51078107

常用模块
1. time模块
2. datetime模块
3. 时间模块需要掌握的操作
4. random模块
5. os模块
6. sys模块
7. shutil模块
8. json和pickle模块
9. xml和shelve模块(了解)
10. configparser模块
11. hashlib模块
12. subprocess模块
13. logging模块
14. re模块

# =================================匹配模式=================================
#一对一的匹配
# 'hello'.replace(old,new)
# 'hello'.find('pattern')

#正则匹配
import re
#w与W
print(re.findall('w','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
print(re.findall('W','hello egon 123')) #[' ', ' ']

#s与S
print(re.findall('s','hello  egon  123')) #[' ', ' ', ' ', ' ']
print(re.findall('S','hello  egon  123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']

#
 	都是空,都可以被s匹配
print(re.findall('s','hello 
 egon 	 123')) #[' ', '
', ' ', ' ', '	', ' ']

#
与	
print(re.findall(r'
','hello egon 
123')) #['
']
print(re.findall(r'	','hello egon	123')) #['
']

#d与D
print(re.findall('d','hello egon 123')) #['1', '2', '3']
print(re.findall('D','hello egon 123')) #['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' ']

#A与
print(re.findall('Ahe','hello egon 123')) #['he'],A==>^
print(re.findall('123','hello egon 123')) #['he'],==>$

#^与$
print(re.findall('^h','hello egon 123')) #['h']
print(re.findall('3$','hello egon 123')) #['3']

# 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
#.:匹配除了
之外任意一个字符,指定re.DOTALL之后才能匹配换行符
print(re.findall('a.b','a1b')) #['a1b']
print(re.findall('a.b','a1b a*b a b aaab')) #['a1b', 'a*b', 'a b', 'aab']
print(re.findall('a.b','a
b')) #[]
print(re.findall('a.b','a
b',re.S)) #['a
b']
print(re.findall('a.b','a
b',re.DOTALL)) #['a
b']同上一条意思一样

#*:左侧字符重复0次或无穷次,性格贪婪
print(re.findall('ab*','bbbbbbb')) #[]
print(re.findall('ab*','a')) #['a']
print(re.findall('ab*','abbbb')) #['abbbb']

#?:左侧字符重复0次或1次,性格贪婪
print(re.findall('ab?','a')) #['a']
print(re.findall('ab?','abbb')) #['ab']
#匹配所有包含小数在内的数字
print(re.findall('d+.?d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3']
#+:左侧字符重复1次或无穷次,性格贪婪
print(re.findall('ab+','a')) #[]
print(re.findall('ab+','abbb')) #['abbb']

#.*默认为贪婪匹配
print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b']

#.*?为非贪婪匹配:推荐使用
print(re.findall('a.*?b','a1b22222222b')) #['a1b']


#{n,m}左侧字符重复n次到m次,性格贪婪
# {0,} => *
# {1,} => +
# {0,1} => ?
# {n}单独一个n代表只出现n次,多一次不行少一次也不行
print(re.findall('ab{2}','abbb')) #['abb']
print(re.findall('ab{2,4}','abbb')) #['abb']
print(re.findall('ab{1,}','abbb')) #'ab{1,}' ===> 'ab+'
print(re.findall('ab{0,}','abbb')) #'ab{0,}' ===> 'ab*'

#[]匹配指定字符一个
print(re.findall('a[1*-]b','a1b a*b a-b')) #[]内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]内的^代表的意思是取反,所以结果为['a=b']
print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]内的^代表的意思是取反,所以结果为['a=b']

## print(re.findall('a\c','ac')) #对于正则来说a\c确实可以匹配到ac,但是在python解释器读取a\c时,会发生转义,然后交给re去执行,所以抛出异常
print(re.findall(r'a\c','ac')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
print(re.findall('a\\c','ac')) #同上面的意思一样,和上面的结果一样都是['a\c']

# print(re.findall('adb','a1111111b a3b a4b a9b aXb a b a
b',re.DOTALL))
# print(re.findall('a[501234]b','a1111111b a3b a4b a9b aXb a b a
b',re.DOTALL))
# print(re.findall('a[0-5]b','a1111111b a3b a1b a0b a4b a9b aXb a b a
b',re.DOTALL))
# print(re.findall('a[0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a
b',re.DOTALL))
#
# print(re.findall('a[^0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a
b',re.DOTALL))
# print(re.findall('a-b','a-b aXb a b a
b',re.DOTALL))
print(re.findall('a[-0-9
]b','a-b a0b a1b a8b aXb a b a
b',re.DOTALL))