一.time与datetime模块
1.time模块的三种形式
import time
1.时间戳:从1970年到现在经过的秒数
作用:用于时间间隔的计算
print(time.time()) #1585531244.1986158
2.按照某种格式显示的时间
作用:用于展示时间
print(time.strftime('%Y-%m-%d %H:%M:%S %p'))
print(time.strftime('%Y-%m-%d %X'))
# 2020-03-30 09:20:44 AM
# 2020-03-30 09:20:44
3.结构化时间
作用:用于获取时间的某一部分
#localtime([secs])
# 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
res=time.localtime()
print(res) # time.struct_time(tm_year=2020, tm_mon=3, tm_mday=30, tm_hour=9, tm_min=20, tm_sec=44, tm_wday=0, tm_yday=90, tm_isdst=0)
print(res.tm_year) # 2020
print(res.tm_yday) #90
2.datetime的模块
import datetime
print(datetime.datetime.now())
print(datetime.datetime.now()+datetime.timedelta(days=3))
print(datetime.datetime.now()+datetime.timedelta(weeks=3))
# 2020-03-30 15:11:01.141467
# 2020-04-02 15:11:01.141467
# 2020-04-20 15:11:01.141467
3.时间模块需要掌握的操作
1.时间格式的转换
结构化的时间(struct_time)-->时间戳
import time
s_time=time.localtime()
# mktime(t) : 将一个struct_time转化为时间戳
print(time.mktime(s_time))
时间戳-->结构化的时间(struct_time)
import time
t_time=time.localtime()
print(time.localtime(t_time))
补充:世界标准时间与本地时间
print(time.localtime()) # tm_hour=15
print(time.gmtime()) # tm_hour=7 # 世界标准时间
结构化的时间(struct_time)-->格式化的字符串形式的时间
s_time=time.localtime()
# strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
time.gmtime()返回)转化为格式化的时间字符串。
print(time.strftime('%Y-%m-%d %H:%M:%S',s_time))
#2020-03-30 15:28:27
真正需要掌握的只有一条:format string<------>timestamp
'1988-03-03 11:11:11'+7
format string--->struct_time--->timestamp
# time.strptime(string[, format])
# 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
struct_time=time.strptime('1988-03-03 11:11:11','%Y-%m-%d %H:%M:%S')
print(struct_time)
timestamp=time.mktime(struct_time)+7*86400
print(timestamp)
format string<---struct_time<---timestamp
res=time.strftime('%Y-%m-%d %X',time.localtime(timestamp))
print(res)
#sleep(secs)
#线程推迟指定的时间运行,单位为秒。
time.sleep(3)
了解
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Mon Mar 30 15:50:38 2020'。
# 如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime())#Mon Mar 30 15:50:38 2020
# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime()) # Mon Mar 30 15:52:16 2020
print(time.ctime(time.time())) #Mon Mar 30 15:52:16 2020
import datetime
print(datetime.datetime.now()) # 2020-03-30 15:54:06.155174
print(datetime.datetime.utcnow()) # 2020-03-30 07:54:06.155174
print(datetime.datetime.fromtimestamp(333333)) # 1970-01-05 04:35:33
二.random模块
import random
print(random.random()) #大于0且小于1之间的小数
print(random.randint(1,3)) #[1,3] #大于等于1且小于等于3之间的整数
print(random.randrange(1,3)) # # [1,3) #大于等于1且小于3之间的整数
print(random.sample([111,'aaa','ccc','ddd'],2)) # 列表元素任意2个组合
print(random.choice([1,23,[4,5]])) # 1或者23或者[4,5]
print(random.uniform(1,3)) # 大于1小于3的小数
import random
item=[1,3,5,7,9]
random.shuffle(item) # 打乱item的顺序,相当于"洗牌"
print(item)
#随机验证码
import random
def make_code(size=6):
res=''
for i in range(size):
s1=chr(random.randint(65,90))
s2=str(random.randint(0,9))
res+=random.choice([s1,s2])
return res
print(make_code())
三.os模块
os模块是与操作系统交互的一个接口
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下为"\t\n",Linux下为"\n"
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的大小
import os
# 获取某一个文件夹下所有的子文件以及子文件夹的名字
res=os.listdir('.')
print(res)
size=os.path.getsize(r'/Users/linhaifeng/PycharmProjects/s14/day22/01 时间模块.py')
print(size)
os.remove() 删除一个文件
os.rename("oldname","newname") 重命名文件/目录
# 应用程序----》"ls /"
os.system("ls /")
# 规定:key与value必须都为字符串
os.environ['aaaaaaaaaa']='111'
print(os.environ)
print(os.path.dirname(r'/a/b/c/d.txt')) # /a/b/c
print(os.path.basename(r'/a/b/c/d.txt')) # d.txt
print(os.path.isfile(r'笔记.txt'))
print(os.path.isfile(r'aaa'))
print(os.path.isdir(r'aaa'))
print(os.path.join('a','/','b','c','d')) #/b\c\d
os路径处理 推荐使用
BASE_DIR=os.path.dirname(os.path.dirname(__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)
print(res.resolve())
BASE_DIR=os.path.normpath(os.path.join(
__file__,
'..',
'..'
))
print(BASE_DIR)
四.sys模块
sys.argv 命令行参数List,第一个元素是程序本身路径
sys.exit(n) 退出程序,正常退出时exit(0)
sys.version 获取Python解释程序的版本信息
sys.maxint 最大的Int值
sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform 返回操作系统平台名称
# python3.8 run.py 1 2 3
# sys.argv获取的是解释器后参数值
print(sys.argv)
src_file=input('源文件路径: ').strip()
dst_file=input('目标文件路径: ').strip()
src_file=sys.argv[1]
dst_file=sys.argv[2]
# 判断
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)
# python3.8 run.py src_file dst_file
进度条
#进度条的效果
[# ]
[## ]
[### ]
[#### ]
#指定宽度
print('[%-15s]' %'#')
print('[%-15s]' %'##')
print('[%-15s]' %'###')
print('[%-15s]' %'####')
#打印%
print('%s%%' %(100)) #第二个%号代表取消第一个%的特殊意义
#可传参来控制宽度
print('[%%-%ds]' %50) #[%-50s]
print(('[%%-%ds]' %50) %'#')
print(('[%%-%ds]' %50) %'##')
print(('[%%-%ds]' %50) %'###')
import time
res=''
for i in range(50):
res+='#'
time.sleep(0.5)
print('\r[%-50s]' % res,end='')
import time
def progress(percent):
if percent > 1:
percent = 1
res = int(50 * percent) * '#'
print('\r[%-50s] %d%%' % (res, int(100 * percent)), end='')
recv_size=0
total_size=1025011
while recv_size < total_size:
time.sleep(0.01) # 下载了1024个字节的数据
recv_size+=1024 # recv_size=2048
# 打印进度条
# print(recv_size)
percent = recv_size / total_size # 1024 / 333333
progress(percent)
五.shutil模块
高级的 文件、文件夹、压缩包 处理模块
shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中
import shutil
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)
拷贝文件和权限
import shutil
shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst)
拷贝文件和状态信息
import shutil
shutil.copy2('f1.log', 'f2.log')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹
import shutil
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件
import shutil
shutil.rmtree('folder1')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。
import shutil
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')
六 json&pickle模块
1.什么是序列化&反序列化
序列化 :将对象(变量)从内存中变成可存储或传输的过程
反序列化:把变量内容从序列化的对象重新读到内存里
内存中的数据类型---->序列化---->特定的格式(json格式或者pickle格式)
内存中的数据类型<----反序列化<----特定的格式(json格式或者pickle格式)
# {'aaa':111}--->序列化str({'aaa':111})----->"{'aaa':111}"
a=str({'aaa':111})
print(a,type(a)) # {'aaa': 111}
#{'aaa':111}<---反序列化eval("{'aaa':111}")<-----"{'aaa':111}"
b=eval(a)
print(b,type(b)) #{'aaa': 111}
2.为何要序列化
序列化得到结果=>特定的格式的内容有两种用途:
1.持久保存状态 (可用于存储=》用于存档)
2.跨平台数据交互 (传输给其他平台使用)
强调:
针对用途1的特定一格式:是一种专用的格式=》pickle只有python可以识别
针对用途2的特定一格式:应该是一种通用、能够被所有语言识别的格式=》json
3.如何序列化与反序列化
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))
# [1, "aaa", true, false]
import json
# 序列化的结果写入文件的复杂方法
json_res=json.dumps([1,'aaa',True,False])
with open('test.json','wt',encoding='utf-8') as f:
f.write(json_res)
# 序列化的结果写入文件的简单方法
with open('test.json','wt',encoding='utf-8') as f:
json.dumps([1,'aaa',True,False],f)
# 从文件读取json格式的字符串进行反序列化操作的复杂方法
with open('text.json','rt',encoding='utf-8') as f:
json_res=f.read()
l=json.loads(json_res)
print(l,type(l))
# [1, 'aaa', True, False]
# 从文件读取json格式的字符串进行反序列化操作的简单方法
with open('text.json','rt',encoding='utf-8') as f:
l=json.loads(f)
print(l,type(l))
# [1, 'aaa', True, False]
json验证: json格式兼容的是所有语言通用的数据类型,不能识别某一语言的所独有的类型
json.dumps({1,2,3,4,5})
# TypeError: Object of type set is not JSON serializable
json强调:一定要搞清楚json格式,不要与python混淆
l=json.loads('[1,2,"aaa",true,false]')
#l=json.loads("[1,2,1.3,'aaa',true,false]") #json 不认单引号
print(l[0]) #1
了解
l=json.loads(b'[1,"aaa",true,false]')
print(l,type(l))
# [1, 'aaa', True, False]
with open('test.json',mode='rb') as f:
l=json.load(f)
res=json.dumps({'name':'哈哈哈'})
print(res,type(res))
# {"name": "\u54c8\u54c8\u54c8"}
res=json.loads('{"name": "\u54c8\u54c8\u54c8"}')
print(res,type(res))
# {'name': '哈哈哈'}
4.猴子补丁
猴子补丁的核心就是用自己的代码替换所用模块的源代码
# 在入口处打猴子补丁
import json
import ujson
def monkey_patch_json():
json.__name__ = 'ujson'
json.dumps = ujson.dumps
json.loads = ujson.loads
monkey_patch_json() # 在入口文件出运行
# 后续代码中的应用
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.dumps()
# json.loads()
# json.loads()
# json.loads()
5.pickle模块
import pickle
res=pickle.dumps({1,2,3,4,5})
print(res,type(res))
# b'\x80\x04\x95\x0f\x00\x00\x00\x00\x00\x00\x00\x8f\x94(K\x01K\x02K\x03K\x04K\x05\x90.'
s=pickle.loads(res)
print(s,type(s))
# {1, 2, 3, 4, 5}
Pickle的问题和所有其他编程语言特有的序列化问题一样,就是它只能用于Python,并且可能不同版本的Python彼此都不兼容,因此,只能用Pickle保存那些不重要的数据,不能成功地反序列化也没关系。
七 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()
八 xml模块(了解)
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单
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')
自己创建xml文档
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成的格式
九 configparser模块
#文件text.ini内容
[section1]
k1=v1
k2:v2
user=egon
age=18
is_admin=true
salary=31
[section2]
k1=v1
import configparser
config=configparser.ConfigParser()
config.read('text.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.查看标题section1下user的值=>字符串格式
res=config.get('section1','user')
print(res,type(res)) # egon
# 5.查看标题section1下is_admin的值=>整数格式
res=config.getboolean('section1','is_admin')
print(res,type(res)) #True
# 6.查看标题section1下age的值=>布尔值格式
res=config.getint('section1','age')
print(res,type(res)) #18
# 7.查看标题section1下salary的值=>浮点型格式
res=config.getfloat('section1','salary')
print(res,type(res)) #31.0
改写
import configparser
config=configparser.ConfigParser()
config.read('a.cfg',encoding='utf-8')
#删除整个标题section2
config.remove_section('section2')
#删除标题section1下的某个k1和k2
config.remove_option('section1','k1')
config.remove_option('section1','k2')
#判断是否存在某个标题
print(config.has_section('section1'))
#判断标题section1下是否有user
print(config.has_option('section1',''))
#添加一个标题
config.add_section('egon')
#在标题egon下添加name=egon,age=18的配置
config.set('egon','name','egon')
config.set('egon','age',18) #报错,必须是字符串
#最后将修改的内容写入文件,完成最终的修改
config.write(open('a.cfg','w'))
十 hashlib模块
1.什么是哈希hash
hash一类算法,该算法接受传入的内容,经过运算得到一串hash值
hash值的特点:
I 只要传入的内容一样,得到的hash值必然一样
II 不能由hash值返解成内容
III 不管传入的内容有多大,只要使用的hash算法不变,得到的hash值长度是一定
2.hash的用途
用途1:特点II用于密码密文传输与验证
用途2:特点I、III用于文件完整性校验
3.如何用
import hashlib
m=hashlib.md5()
m.update('hello'.encode('utf-8'))
m.update('world'.encode('utf-8'))
res=m.hexdigest()
print(res) #fc5e038d38a57032085441e7fe7010b0
m1=hashlib.md5('he'.encode('utf-8'))
m1.update('llo'.encode('utf-8'))
m1.update('wor'.encode('utf-8'))
m1.update('ld'.encode('utf-8'))
res=m1.hexdigest()
print(res) #fc5e038d38a57032085441e7fe7010b0
模拟撞库破解密码
import hashlib
passwds=[
'alex3714',
'alex1313',
'alex94139413',
'alex123456',
'123456alex',
'a123lex',
]
def make_passwd_dic(passwds):
dic={}
for passwd in passwds:
m=hashlib.md5(passwd.encode('utf-8'))
dic[passwd]=m.hexdigest()
return dic
def break_code(cryptograph,passwd_dic):
for k,v in passwd_dic.items():
if v == cryptograph:
print('密码是:%s' %k)
cryptograph='aee949757a2e698417463d47acac93df'
break_code(cryptograph,make_passwd_dic(passwds))
提升撞库的成本=>密码加盐
import hashlib
m=hashlib.md5()
m.update('天王'.encode('utf-8'))
m.update('alex3714'.encode('utf-8'))
m.update('盖地虎'.encode('utf-8'))
print(m.hexdigest())
十一 subprocess模块
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) # b'123 ; ls / ; ls /root\r\n'
err_res=obj.stderr.read()
print(err_res.decode('utf-8'))
十二 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配置
"""
import os
# 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][task_id:%(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': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,日志轮转
'formatter': 'standard',
# 可以定制日志文件路径
# BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # log文件的目录
# LOG_PATH = os.path.join(BASE_DIR,'a1.log')
'filename': 'a1.log', # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
'other': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 保存到文件
'formatter': 'test',
'filename': 'a2.log',
'encoding': 'utf-8',
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
'专门的采集': {
'handlers': ['other',],
'level': 'DEBUG',
'propagate': False,
},
},
}
3.使用
import settings
# !!!强调!!!
# 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
# from logging import config
# from logging import getLogger
# 2、也可以使用如下导入
import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.
# 3、加载配置
logging.config.dictConfig(settings.LOGGING_DIC)
# 4、输出日志
logger1=logging.getLogger('用户交易')
logger1.info('egon儿子alex转账3亿冥币')
# logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应
# logger2.debug('专门采集的日志')
十三 re模块
1.什么是正则
正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。
(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
2.常用匹配模式(元字符)
import re
# w与W
print(re.findall('\w','aAbc123_*()-='))
# ['a', 'A', 'b', 'c', '1', '2', '3', '_']
print(re.findall('\W',' aAbc123_*()-= '))
# [' ', '*', '(', ')', '-', '=', ' ']
#s与S
print(re.findall('\s','aA\rbc\t\n12\f3_*()-= ')) ##\n \t都是空,都可以被\s匹配
# ['\r', '\t', '\n', '\x0c', ' ']
print(re.findall('\S','aA\rbc\t\n12\f3_*()-= '))
# ['a', 'A', 'b', 'c', '1', '2', '3', '_', '*', '(', ')', '-', '=']
#\n与\t
print(re.findall(r'\n','hello egon \n123')) #['\n']
print(re.findall(r'\t','hello egon\t123')) #['\t']
#d与D
print(re.findall('\d','aA\rbc\t\n12\f3_*()-= '))
# ['1', '2', '3']
print(re.findall('\D','aA\rbc\t\n12\f3_*()-= '))
# ['a', 'A', '\r', 'b', 'c', '\t', '\n', '\x0c', '_', '*', '(', ')', '-', '=', ' ']
#A与Z
print(re.findall('\Aalex','alexis alex sb')) #['alex'] #\A==>^
print(re.findall('\Aalex',' alexis alex sb')) #[]
print(re.findall('sb\Z',' alexis alexsb sb')) #['sb'] #\Z==>$
print(re.findall('sb\Z',' alexis alexsb sb ')) #[]
#^与$
print(re.findall('sb$','alexis alexsb sb')) #['sb']
print(re.findall('^alex','alexis alexsb sb')) #['alex']
print(re.findall('sb$',"""alex
alexis
alex
sb
"""))
# ['sb']
print(re.findall('^alex$','alexis alex sb')) #[]
print(re.findall('^alex$','al ex')) #[]
print(re.findall('^alex$','alex')) #['alex']
重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
1、.:匹配除了\n之外任意一个字符,指定re.DOTALL之后才能匹配换行符
print(re.findall('a.b','a1b a2b a b abbbb a\nb a\tb a*b'))
# ['a1b', 'a2b', 'a b', 'abb', 'a\tb', 'a*b']
print(re.findall('a.b','a1b a2b a b abbbb a\nb a\tb a*b',re.DOTALL))
# ['a1b', 'a2b', 'a b', 'abb', 'a\nb', 'a\tb', 'a*b']
2、*:左侧字符重复0次或无穷次,性格贪婪
print(re.findall('ab*','a ab abb abbbbbbbb bbbbbbbb'))
# ['a', 'ab', 'abb', 'abbbbbbbb']
3、+:左侧字符重复1次或无穷次,性格贪婪
print(re.findall('ab+','a ab abb abbbbbbbb bbbbbbbb'))
# ['ab', 'abb', 'abbbbbbbb']
4.?:左侧字符重复0次或1次
print(re.findall('ab?','a ab abb abbbbb bbbbbb'))
#['a', 'ab', 'ab', 'ab']
5、{n,m}:左侧字符重复n次到m次
# {0,} => *
# {1,} => +
# {0,1} => ?
# {n}单独一个n代表只出现n次,多一次不行少一次也不行
print(re.findall('ab{2,5}','a ab abb abbb abbbb abbbbbbbb bbbbbbbb'))
# ['abb','abbb','abbbb','abbbbb']
# 取出小数和整数
print(re.findall('\d+\.?\d*',"asdfasdf123as1111111.123dfa12adsf1asdf3"))
# ['123', '1111111.123', '12', '1', '3']
[]匹配指定字符一个
print(re.findall('a\db','a1111111b a3b a4b a9b aXb a b a\nb',re.DOTALL))
# ['a3b', 'a4b', 'a9b']
print(re.findall('a[501234]b','a1111111b a3b a4b a9b aXb a b a\nb',re.DOTALL))
# ['a3b','a4b']
print(re.findall('a[0-5]b','a1111111b a3b a4b a9b aXb a b a\nb',re.DOTALL))
#['a3b', 'a1b', 'a0b', 'a4b']
print(re.findall('a[0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a\nb',re.DOTALL))
# ['axb', 'a3b', 'a1b', 'a0b', 'a4b', 'a9b', 'aXb']
print(re.findall('a[^0-9a-zA-Z]b','a1111111b axb a3b a1b a0b a4b a9b aXb a b a\nb',re.DOTALL))# []内的^代表的意思是取反
# ['a b','a/nb']
print(re.findall('a-b','a-b aXb a b a\nb',re.DOTALL))
# ['a-b']
print(re.findall('a[-0-9\n]b','a-b a0b a1b a8b aXb a b a\nb',re.DOTALL))
#['a-b','a0b','a1b','a8b','a\nb']
1