本周内容回顾

  本周内容回顾

  • 正则表达式
  • 第三方模块

正则表达式

正则表达式不属于任何一个编程语言  是一个独立的学科

    主要用于数据的筛选和查找

1.前戏

  现在需要编写一个代码用来判断用户输入是否是中国手机号码

phone_id = input('请输入电话号码>>>>:').strip()
if phone_id.isdigit():
    if len(phone_id) == 11:
        if phone_id.startswith('13') or phone_id.startswith('15') or phone_id.startswith(
                '16') or phone_id.startswith('17') or phone_id.startswith('19'):
            print('合格的号码')
        else:
            print('开头不合法')
    else:
        print('电话号码必须是11位')
else:
    print('电话号码必须是纯数字')
# 这样也可以判断处电话号码是否合格 但是这样写太多了 可以使用正则表达式简便写
import re

phone_id = input('请输入电话号码>>>>:').strip()
if re.match('0?^(13|15|16|17|19)[0-9]{9}',phone_id):
    print(f'电话号码合格{phone_id}')
else:
    print('电话号码不合格')
# 这样就也可以判断电话号码是否合格 还可以省代码简便快捷
'''
总结:
    正则表达式就是通过一些特殊符号的组合产生一些特殊含义
    然后在字符串中筛选出符合条件的数据
'''

正则表达式之字符组

正则表达式线上测试网站: http://tool.chinaz.com/regex/

[0-9]        匹配数字0-9中的任意一个数字(包括0和9)
# 就是能够把一串字符串中的所有数字都提取出来一次只会针对一个数据

[A-Z]        匹配大写字母A-Z中的任意一个字母(包括A和Z)
# 就是能够用把一串字符串中的所有大写字母都提取出来一次只会针对一个数据

[a-z]        匹配小写字母a-z中的任意一个字母(包括a和z)
# 就是能够把一串字符串中所有的小写字母都提取出来一次只会针对一个数据
如果括号中多个数据值那么他们批次是或的关系 
  [0-9a-zA-Z]   
  就是数字、小写字母、大写字母都可以 

''' 字符组在没有量词修饰的情况下一次只会针对一个数据值 '''

正则表达式之特殊符号

'''
.       匹配除换行符之外的任意一个字符
\w      匹配字母或数字或下划线
\W      匹配除字母或数字或下划线之外的任意一个字符
\d      匹配数字
^       匹配字符串的开头
$       匹配字符串的结尾
    ps: ^和 $组合使用可以明确的限制想要查找的具体数据   ^数据$
a|b     匹配a字符或b字符
    ps: |管道符在很多场景中都是表示或
()      给正则表达式分组 不影响正则表达式的匹配
    ps: 用于给正则表达式起别名 分组获取对应的数据
[]      匹配字符组中的字符
[^]     匹配除了字符组中字符的所有字符
'''
# 在没有量词修饰的情况下一个字符一次只会针对一个数据值

正则表达式之量词

'''
*       重复零次或更多次(默认更多次)
+       重复一次或更多次(默认更多次)
?       重复零次或一次(默认更多次)
{n}     重复n次
{n,}    重复n次或更多次
{n,m}   重复n到m次
在正则表达式中所有的量词默认匹配的都是贪婪匹配(就是尽可能多的取值)
'''
# 量词不能单独使用 必须跟在表达式后面 并且只能影响紧挨的着的左边的那一个

正则表达式之练习题

'''
正则                      待匹配的字符                      匹配结果
海.                      海燕海娇海东                     海燕 海娇 海东        三条结果       匹配所有"海." 的字符 
^海.                     海燕海娇海东                     海燕                 一条结果    只从开头匹配是"海."的字符
海.$                     海燕海娇海东                     海东                 一条结果    只从结尾匹配是"海."的字符
李.?                     李杰和李莲英和李二棍子             李杰 李莲 李二        三条结果    ?表示重复零次或一次, 所以只匹配"李"后面任意一个字符
李.*                     李杰和李莲英和李二棍子             李杰和李莲英和李二棍子  一条结果       *表示重复零次或多次, 所以匹配"李"后面0个或多个字符   
李.+                     李杰和李莲英和李二棍子             李杰和李莲英和李二棍子  一条结果    +表示重复一次或多次, 所以匹配"李"后面一个或多个字符
李.{1,2}                 李杰和李莲英和李二棍子             李杰和 李莲英 李二棍    三条结果      {1, 2}表示匹配1到2次任意字符,  所以匹配"李"后面一个或两个字符      
李[杰莲英二棍子]*          李杰和李莲英和李二棍子             李杰  李莲英  李二棍子  三条结果      [杰莲英二棍子]*表示匹配字符组中任意一个字符  eg:(李杰  李杰莲 李杰莲英...)       
李[^和]*                 李杰和李莲英和李二棍子             李杰  李莲英  李二棍子  三条结果    [^和]* 表示匹配除了字符组中的和以外的任意字符
[\d]                    456bdha3                        4 5 6 3              四条结果    [\d]表示匹配任意一个数字
[\d]+                   456bdha3                        456  3               两条结果    [\d]*表示匹配任意数字

经过量词的修饰就可以改变提取的结果
'''

贪婪匹配和非贪婪匹配

1.贪婪匹配

'''
贪婪匹配:
1.
待匹配的文本:<script>alert(123)</script>
正则表达式 <.*>  
匹配结果: <script>alert(123)</script>
2.
待匹配的文本:<script>alert(123)</script>abs
正则表达式 <.*>
匹配结果: <script>alert(123)</script>

就是<匹配< 然后.*就是除了换行符什么都可以匹配遇到倒数第一个>停下匹配 然后>匹配最后一个>
'''

2.非贪婪匹配

'''
非贪婪匹配:
1.
待匹配的文本:<script>alert(123)</script>
正则表达式 <.*?>  
匹配结果: <script>   </script>
2.
待匹配的文本:<script>alert(123)</script>abs
正则表达式 <.*?>
匹配结果: <script>    </script>

就是<匹配<然后.*匹配除了换行符之外的所有字符遇到第一个>就会停下匹配 >匹配遇到的第一个>  然后继续下去知道没有为止
'''

3.主意事项

'''
所有的量词默认都是贪婪匹配
但是如果后面紧跟上?就会变成非贪婪匹配

小技巧:
    以后我们使用贪婪匹配和非贪婪匹配的时候一般我们都使用.*或者.*?
    并且结束的标识就是上述符号两边添加的表达式决定      
'''

取消转义

在正则表达式中取消斜杠与字母产生的特殊含义  就是在斜杠前面加上斜杠

\n>>>> \\n
\\n>>>>\\\n   
而在python中只需要在前面加上r
r'\n'
r'\\n'

正则表达式实战

编写校验用户手机号的正则
    0?(13|14|15|17|18|19)[0-9]{9}
编写校验用户身份证的正则
    \d{17}[\d|x]|\d{15}
编写校验用户邮箱的正则
    \w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}
编写校验用户qq号的正则
    [1-9]([0-9]{5,11})

'''
这些肯定在任何地方都需要这些需求, 所以已经有大佬写好了
用的时候我们只需问度娘 
或则点击这个链接即可:http://tool.chinaz.com/regex/
我们只需要知道这个怎么用 怎么修改即可
'''

re模块

在之前我们说讲的正则表达式之后

我们该如何在python表示呢?

在python解释器中想要表示正则表达式 re模块是其中之一

1. findall()

import re
#
res = re.findall('[0-9]', 'find123all123')
print(res)  # ['1', '2', '3', '1', '2', '3']
res1 = re.findall('a', 'findallabsabs')
print(res1)  # ['a', 'a', 'a']

# findall可以通过正则表达式筛选文本中所有符合条件的数据

2. finditer()

res2 = re.finditer('[0-9]', 'find123iter123')
print(res2)  # <callable_iterator object at 0x000001EF611894E0> 会生成一个迭代器
print(res2.__next__())  # <_sre.SRE_Match object; span=(4, 5), match='1'>
print(res2.__next__())  # <_sre.SRE_Match object; span=(5, 6), match='2'>
print(res2.__next__())  # <_sre.SRE_Match object; span=(6, 7), match='3'>
print(res2.__next__())  # <_sre.SRE_Match object; span=(11, 12), match='1'>
print(res2.__next__())  # <_sre.SRE_Match object; span=(12, 13), match='2'>
print(res2.__next__())  # <_sre.SRE_Match object; span=(13, 14), match='3'>
# finditer与findall作用是一致的 只不过finditer生成的是一个迭代器能够节省内存空间

3.search()

res3 = re.search('[0-9]', 'find123iter123')
print(res3)  # <_sre.SRE_Match object; span=(4, 5), match='1'>
print(res3.group())  # 1
res4 = re.search('a', 'findallabsabs')
print(res4)  # <_sre.SRE_Match object; span=(4, 5), match='a'>
print(res4.group())  # a

# search就是通过正则表达式匹配到一个符合条件的数据就会结束匹配 还可以通过group取值

4.match()

res5 = re.match('[0-9]', 'find123iter123')
print(res5)  # None 没有结果
res6 = re.match('a', 'findallabsabs')
print(res6)  # # None 没有结果

res7 = re.match('[0-9]', '23find')
print(res7)  # <_sre.SRE_Match object; span=(0, 1), match='2'>
print(res7.group())  # 2
res8 = re.match('a', 'aafindallabsabs')
print(res8)  # <_sre.SRE_Match object; span=(0, 1), match='a'>
print(res8.group())  # 2

'''
因为match通过正则表达式之匹配开头 开头有就匹配没有就返回None 然后结束
'''

5.complie()

r = re.compile('[0-9]')

r1 = re.findall(r, 'find123iter123' )
print(r1)  # ['1', '2', '3', '1', '2', '3']
'''
compile就是可以提前把正则表达式写好
然后后面要用到的时候只要调用他的变量名即可可以减少代码冗余
'''

re模块的其他用法

1.分组

import re

res = re.findall('abc', 'abcabcabcabcacbacb')
print(res)  # ['abc', 'abc', 'abc', 'abc']

res = re.findall('a(b)c', 'abcabcabcabcacbacb')
print(res)  # ['b', 'b', 'b', 'b']

# findall可以针对分组的正则表达式匹配的结果 优先展示

res = re.findall('a(?:b)c', 'abcabcabcabcacbacb')
print(res)  # ['abc', 'abc', 'abc', 'abc']

# 也可以通过?: 取消优先展示

res = re.search('a(b)c', 'abcabcabcabcacbacb')
print(res.group())  # abc
print(res.group(0))  # abc
print(res.group(1))  # b
print(res.group(2))  # 报错
'''
其实加上括号不影响正则表达式的运行
只不过就是通过正则表达式匹配出来的结果会存起来[abc, b]
然后索引0就是abc 索引1就是b
'''
res = re.search('a(b)(c)', 'abcabcabcabcacbacb')
print(res.group())
print(res.group(0))  # abc
print(res.group(1))  # b
print(res.group(2))  # c

'''
如果把c也加上括号的话就是把c匹配出来的结果添加到列表中[abc, b, c]
然后通过索引取值即可
'''

# 只有findall有分组的的效果 优先展示其他方法没有

2.起别名

import re

res = re.findall('abc', 'abcabcabcabcacbacb')
print(res)  # ['abc', 'abc', 'abc', 'abc']

res = re.findall('a(b)c', 'abcabcabcabcacbacb')
print(res)  # ['b', 'b', 'b', 'b']

res = re.findall('a(b)(c)', 'abcabcabcabcacbacb')
print(res)  # [('b', 'c'), ('b', 'c'), ('b', 'c'), ('b', 'c')] 优先展示

res = re.search('a(?P<name>b)(?P<name1>c)', 'abcabcabcabcacbacb')
print(res.group(0))  # abc
print(res.group(1))  # b
print(res.group(2))  # c
print(res.group('name'))  # b
print(res.group('name1'))  # c
# 就是可以通过加括号在要匹配的字符前面加上 ?P就可以起别名 这样就可以通过起的名字取值 p要大写

网络爬虫的简介

1.什么是互联网

  将全世界的计算机链接到一起组成的网络

2.互联网发明的目的是什么

  将接入到互联网中的计算机中的数据可以彼此共享

3.上网的本质是什么

  基于互联网访问别人的计算机上面的资源(有些计算机存在的意义就是让别人访问的 这种类型的计算机我们称之为服务器)

4.网络爬虫的本质

  模拟计算机浏览器朝目标网址发送请求获取数据并筛选

    只要是浏览器能够访问到的数据网络爬虫理论上都可以爬取数据

第三方模块的下载

如果要使用网络爬虫必须要使用到第三方模块 : requests

而使用第三方模块我们必须要提前下载

python下载第三方模块需要借助pip工具

1.终端

我们可以在终端中下载输入命令:

  pip版本 install  模块名

如果环境变量中的pip为pip3.6那么就可以怎么写

  pip3.6 install 模块名

'''
pip工具默认是要去外网仓库下载的 会下载的很慢

所以我们可以通过换pip源下载 会下载的快些
而国内的pip源地址有这些:

清华大学 :https://pypi.tuna.tsinghua.edu.cn/simple/
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科学技术大学 :http://pypi.mirrors.ustc.edu.cn/simple/
华中科技大学:http://pypi.hustunique.com/
豆瓣源:http://pypi.douban.com/simple/
腾讯源:http://mirrors.cloud.tencent.com/pypi/simple
华为镜像源:https://repo.huaweicloud.com/repository/pypi/simple/

只需要写入命令:
pip3.6 install 模块名 -i 源地址

源地址就是上面的链接 随便填写一个即可

模块名也是有版本的只要在终端中输入下行命令:
pip3.6 install 模块名==版本号
  pip3.6 install django==1.11.11

'''

2.pycharm

pycharm也给我们提供了下载第三方模块快捷方式

首先最新版本的pycharm下载方式已经改变了位置:

最新版本下载位置如下:

 

 

 

 1.在pycharm左下角点击 Python Packages 

2.然后在搜索框中输入模块名即可

3.点击下载即可  点击latest可以选择模块的版本号

 

在pycharm中也可以换源

 

 

 

 1.点击pycharm界面左下角Python Packages

2.点击设置

3.可以改变你这个源的名字

4.把国内的源地址随便一个复制到这即可

5.可以增加或删除源地址 +:增加  -: 删除

3.下载任意遇到的几种错误

1.pip工具版本过低 需要更新 直接复制提示信息里面的更新命令即可

  python3.6 -m pip install --upgrade pip

2.网络波动

  关键字: Read timed out

  这种出现的时候其实就是你的网络有可能卡掉了 只需要重新下载或则换一个网络即可

3.有些模块下载的时候 需要提前配置好指定环境

  结合具体情况 问度娘

requests模块的使用

import requests


res = requests.get('http://www.redbull.com.cn/about/branch')
# get就是模拟浏览器向目标地址发送请求获取相应数据(就是相当于在浏览器中输入网址然后回车)

print(res.content)  # 获取的是二进制数的数据
print(res.text)  # 获取解码后的数据  requests自带解码

# 为了避免每次运行程序的时候都要发送请求 我们可以把获取到的数据存入到文件中
with open('hn.html', 'wb')as f:
    f.write(res.content)
# 这样就保存到文件中了  主意网站信息文件的后缀名最好使用html

opnepyxl模块

openpyxl模块主要用于操作excel表格的  也是pandas模块的底层操作表格的模块

 

在python中可以操作excel表格有很多

  opnepyxl是属于最近几年比较流行的模块

    opnepyxl针对03版本之前的excel文件兼容性不好

  xlwt、xlrd也可以操作excel表格

    兼容所有版本excel文件 但是使用方式没有openpyxl简单

1.excel版本问题

  03版本之前 excel的后缀名是: .xls

  03版本之后 excel的后缀名是: .xlsx

    如果是苹果电脑excel后缀名是: .csv

因为opnepyxl模块时第三方模块所以使用之前必须先下载(下载过了就不需要)

openpyxl模块的使用

from openpyxl import Workbook

wb = Workbook() # 创建一个excel文件
# 因为excel表格不止一个页面有很多个页面 所以可以创建很多页面
wb1 = wb.create_sheet('成绩表') # 创建excel文件中的一个页面 页面名为'成绩表'
wb2 = wb.create_sheet('校花表') # 页面名为'校花表'

wb1.title('校草表') # 支持二次修改 页面名就会被修改

wb.save('学校信息.xlsx') # 保存excel文件 文件名为学校信息.xlsx

openpyxl还可以写入数据

1.第一种写入数据

from openpyxl import Workbook

wb1['A1'] = '分数'  

# 想定位坐标一样在一个准确的空格中编写数据

2.第二种写入数据

from openpyxl import Workbook

wb1.cell(row=3, column=2, value='学生信息')  
'''
使用cell关键
row行       编写第几行
column列    编写第几列
value值     编写数据值
'''

3.第三种写入数据

from openpyxl import Workbook

wb1.append(['username', 'password', 'age', 'gender', 'hobby'])
wb1.append(['tony', 123, 18, 'run'])
# 可以批量写入 如果一行中已经有数据的话那么就会跳到下一行写入

还可以别写函数计算

wb1['F11'] = '=sum(B5:B10)'
# 中括号是具体位置  后面的字符串就是编写一些函数

openpyxl还有很多功能可以去他的官网查看

openpyxl模块的读取

1.lord_workbook

wb = load_workbook('红牛.xlsx')
print(wb.sheetnames)  # ['红牛信息', 'Sheet']
# 查看excel表格中所有工作簿的名称 结果是一个表格

2.取值

print(wb1.max_row)  #  41 获取最大的行数
print(wb1.max_column)  # 4 获取最大列数

# 第一种取值方式
print(wb1['A1'])  # <Cell '红牛信息'.A1> 可以准确获取表格是把哪个数据
# 第二种取值方式
print(wb1.cell(row=2, column=2).value)  # 杭州市上城区庆春路29号远洋大厦11楼A座 可以通过行数和列数获取数据

'''
openpyxl模块其实是不擅长读取数据的 
所以一些模块优化了读取方式
那就是pandas模块
'''

random模块

random模块又称之为随机模块

random模块时一个很好玩的模块

1.random()

import random

print(random.random())  

# 每次运行都会随机产生一个0-1的小数(不包括0和1)

2.randint()

import random

print(random.randint(0, 6))  

# 每次运行都会随机产生一个0到6之间的一个整数(包括0和6) 0和6可以是任意数

3.choice()

print(random.choice(['特等奖', '一等奖', '二等奖', '三等奖']))

# 每次运行都会在列表中随机抽取一个数

4.sample()

import random

print(random.sample(['特等奖', '一等奖', '二等奖', '三等奖', '安慰奖', '参与奖'], 2))  # ['参与奖', '安慰奖']
# 每次运行都会在列表中随机抽取两个数

print(random.sample(['特等奖', '一等奖', '二等奖', '三等奖', '安慰奖', '参与奖'], 3))  # ['三等奖', '一等奖', '参与奖']
# 每次运行都会在列表中随机抽取三个数  

# 可自定义一个抽取数

5.shuffle()

import random


l1 = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'J', 'Q', 'K', 'A']
random.shuffle(l1)
print(l1)  # [7, 8, 'J', 10, 6, 'K', 4, 9, 2, 'Q', 3, 'A', 5]

# shuffle 每次运行都会把传入的容器里的数据打乱

hashlib加密模块

1.什么是加密

  就是把明文数据(看得懂的)经过处理后变成密文数据(看不懂的)

2.为什么要加密

  不想让敏感数据轻易的泄露

3.如何判断数据是否已经加密

  一般情况下看到一串没有规则的数字字母符号组合一般都是加密过后的结果

4.如何加密

  加密在计算机中是要通过加密算法的

  就是对明文数据采用的机密策略

    不同的加密算法的复杂程度不一样 得出的结果也会不一样

    通常情况下机密之后的结果越长 说明采用的加密算法越复杂

5.常见的加密算法

  md5 sha系列 hmac base64

1.加密代码体现

import hashlib

md5 = hashlib.md5()  # 选择md5算法作为数据的加密策略
md5.update(b'123')  # 往里面添加明文数据  数据必须是bytes类型
res = md5.hexdigest()  # 获取加密之后的数据
print(res)  # 202cb962ac59075b964b07152d234b70

md5.update(b'jason')
res1 = md5.hexdigest()  
print(res1)  # 65a2eab1aaca6a9aa2a0e9d58ee20f36

2.加密补充

1.一般情况下机密之后的密文是不能反解密的

  加密之后只有使用者知道自己加密的数据 

  所谓的反解密都是在偷换概念

    就是我们可以提前假设别人的密码是什么 然后在通过算法得出密文

    之后在够着对应关系 然后对比密文 之后就可以得出明文

2.只要明文数据是一样的那么采用相同的算法得出的密文也是一样的

import hashlib

md5.update(b'123')
md5.update(b'hello')
md5.update(b'jason')
res = md5.hexdigest()
print(res)  # 31b9a81dc788368469ee4b78877eb1eb

md5.update(b'123hellojason')
res1 = md5.hexdigest()
print(res1)  #31b9a81dc788368469ee4b78877eb1eb

# 不管你是分几次传入还是一次传入 只要明文数据是一样的那么密文肯定是一样的

3.加盐处理

就是可以加入干扰项 可以不会那么任意泄露数据

import hashlib

md5.update('公司设置的盐(干扰项)'.encode('utf8'))  # 明文数据必须是二进制
md5.update(b'123hellojason')
res1 = md5.hexdigest()
print(res1)  # b68946fd2bb01cc03c6c5fc4fc062f14

# 就是把干扰项跟真是数据一起加密 不容易泄密

4.动态加盐

import datetime
import hashlib

md5 = hashlib.md5()

res = datetime.datetime.today()  # 2022-07-21 19:19:33.731568
res = str(res)
print(res)

md5.update(res.encode('utf8'))
md5.update(b'jason')
res1 = md5.hexdigest()
print(res1)  # b9e3ef9e09245f4a572da03fbdb77906

# 我们可以动态获取当前时间然后在跟真实数据一起加密这样会相较于普通的加盐会更安全一些

# 还可以获取用户名时截取用户名的一段


#这样每次加盐都不一样会更安全一些

5.加密的实际引用场景

  1.用户密码加密

    用户注册时对用户的密码加密然后保存

    然后登入的时候也是对用户登入的密码进行加密

    然后对两个密文进行对比

  2.文件安全性校验

    正规的软件写完后会对程序进行加密

    网址提供软件文件记忆改文件内容对应的密文

    用户下载后不会立马执行软件 会先进行对内容加密

    然后对比对比两次密文是否一致 如果一致那么表示文件内容没有被改动

    如果不一致那么说明有可能被植入病毒

  3.大文件加密优化

    一般情况下如果家买文件是很大的话 那么直接加密速度会很慢 (100G)

    我们可以不对100G直接加密  可以截取一段进行加密

    每隔500M读取30bytes

subprocess模块

模拟计算机cmd窗口

import subprocess


cmd = input('请输入您的指令>>>:').strip()
sub = subprocess.Popen(cmd,
                       shell=True,
                       stdout=subprocess.PIPE,
                       stderr=subprocess.PIPE
                       )
# stdout执行命令之后正确的返回结果
print(sub.stdout.read().decode('gbk'))
# stderr执行命令报错之后的返回结果
print(sub.stderr.read().decode('gbk'))

日志模块

1.什么日志

  日志就是类似于记录历史记录

2.为什么要有日志

  记录事物发生的事实

3.如何使用日志

  3.1 日志的等级

import logging

logging.debug('debug等级')  # 10
logging.info('info等级')  # 20
logging.warning('warning等级')  # 30 默认日志是从warning级别开始记录的
logging.error('error等级')  # 40
logging.critical('critical等级')  # 50

# 还可以使用数字代表那个等级

  3.2基本使用

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对象>>>:可以忽略 不用使用
# 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': ['default','console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
        #     'level': 'WARNING',
        #     'propagate': True,  # 向上(更高level的logger)传递
        # },  # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
    },
}

logging.config.dictConfig(LOGGING_DIC)  # 自动加载字典中的配置
logger1 = logging.getLogger('红浪漫顾客消费记录')  # 写入日志信息
logger1.debug('慢男 猛男 骚男')  # 写入日志内容

 

posted @ 2022-07-24 20:55  stephen_hao  阅读(30)  评论(0编辑  收藏  举报