内置模块
- python内部提供的功能
- 导入模块后,直接使用即可
一、 random
- 随机数模块
- randint:得到一个随机数
import random # 导入一个模块
v = random.randint(起始,终止) # 得到一个随机数
#示例:生成随机验证码
import random
def get_random_code(length=6):
data = []
for i in range(length):
v = random.randint(65,90)
data.append(chr(v))
return ''.join(data)
code = get_random_code()
print(code)
- uniform:生成一个随机小数
- choice:抽取一个对象
- 应用:验证码、抽奖
- sample:抽取多个对象
- 应用:一个奖项抽取多个人
- shuffle:打乱顺序
- 应用:洗牌、算法
二、 hashlib
- 摘要算法模块
- 密文验证
- 校验文件的一致性
- md5
# 将指定的 “字符串” 进行 加密
import hashlib # 导入一个模块
def get_md5(data): # md5 加密函数
obj = hashlib.md5()
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
val = get_md5('123')
print(val)
# 加盐
import hashlib
def get_md5(data):
obj = hashlib.md5("sidrsdxff123ad".encode('utf-8')) # 加盐
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
val = get_md5('123')
print(val)
# 应用:用户注册+用户登录
import hashlib
USER_LIST = []
def get_md5(data): # md5 加密函数
obj = hashlib.md5("12:;idrsicxwersdfsaersdfs123ad".encode('utf-8')) # 加盐
obj.update(data.encode('utf-8'))
result = obj.hexdigest()
return result
def register(): # 用户注册函数
print('**************用户注册**************')
while True:
user = input('请输入用户名:')
if user == 'N':
return
pwd = input('请输入密码:')
temp = {'username':user,'password':get_md5(pwd)}
USER_LIST.append(temp)
def login(): # 用户登录函数
print('**************用户登陆**************')
user = input('请输入用户名:')
pwd = input('请输入密码:')
for item in USER_LIST:
if item['username'] == user and item['password'] == get_md5(pwd):
return True
register()
result = login()
if result:
print('登陆成功')
else:
print('登陆失败')
sha
import hashlib md5 = hashlib.sha1('盐'.encode()) md5.update(b'str') print(md5.hexdigest())
三、 getpass
- 只能在终端运行
- getpass.getpass:输入密码时不显示
import getpass # 导入一个模块
pwd = getpass.getpass('请输入密码:')
if pwd == '123':
print('输入正确')
四、 time
- 时间模块
time.time:时间戳(从1970年到现在经历的秒数)
# https://login.wx.qq.com/cgi-bin/mmwebwx-bin/login?loginicon=true&uuid=4ZwIFHM6iw==&tip=1&r=-781028520&_=1555559189206
time.sleep:等待的秒数
time.timezone
示例
# 计算函数执行时间 import time def wrapper(func): def inner(): start_time = time.time() v = func() end_time = time.time() print(end_time-start_time) return v return inner @wrapper def func1(): time.sleep(2) print(123) func1()
五、 datetime
- 时间模块
datetime.now():当前本地时间
datetime.utcnow():当前UTC时间
import time from datetime import datetime,timezone,timedelta # 获取datetime格式时间 # 当前本地时间 v1 = datetime.now() # 当前东7区时间 tz = timezone(timedelta(hours=7)) v2 = datetime.now(tz) # 当前UTC时间 v3 = datetime.utcnow() print(v3)
相互转换
import time from datetime import datetime,timedelta # 1.datetime格式和字符串的相互转换 # 把datetime格式转换成字符串:strftime v1 = datetime.now() val = v1.strftime("%Y-%m-%d %H:%M:%S") # 字符串转成datetime格式:strptime v1 = datetime.strptime('2011-11-11','%Y-%m-%d') # 2.datetime时间的加减 v1 = datetime.strptime('2011-11-11','%Y-%m-%d') v2 = v1 - timedelta(days=140) # 再转换成字符串 date = v2.strftime('%Y-%m-%d') # 3.时间戳和datetime的相互转换 # 时间戳转换成datetime格式:fromtimestamp ctime = time.time() v1 = datetime.fromtimestamp(ctime) # datetime格式转换成时间戳:timestamp v1 = datetime.now() val = v1.timestamp()
六、 sys
- python解释器相关数据
sys.getrefcount:获取一个值的应用计数
sys.getrecursionlimit:python默认支持的递归数量
sys.stdout.write:输入输出
补充:\n:换行 \t:制表符 \r:回到当前行的起始位置
import time for i in range(1,101): msg = "%s%%\r" %i print(msg,end='') time.sleep(0.05)
示例:读取文件的进度条
import os # 1. 读取文件大小(字节) file_size = os.stat('20190409_192149.mp4').st_size # 2.一点一点的读取文件 read_size = 0 with open('20190409_192149.mp4',mode='rb') as f1,open('a.mp4',mode='wb') as f2: while read_size < file_size: chunk = f1.read(1024) # 每次最多去读取1024字节 f2.write(chunk) read_size += len(chunk) val = int(read_size / file_size * 100) print('%s%%\r' %val ,end='')
sys.argv:获取用户执行脚本时,传入的参数
- 示例:让用户执行脚本传入要删除的文件路径,在内部帮助用将目录删
""" 让用户执行脚本传入要删除的文件路径,在内部帮助用将目录删除。 C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py D:/test C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py """ import sys # 获取用户执行脚本时,传入的参数。 # C:\Python36\python36.exe D:/code/s21day14/7.模块传参.py D:/test # sys.argv = [D:/code/s21day14/7.模块传参.py, D:/test] path = sys.argv[1] # 删除目录 import shutil shutil.rmtree(path)
sys.exit(0):程序终止,0代表正常终止
sys.path:默认python去导入模块时,会按照sys.path中的路径
- 添加目录:sys.path.append(‘目录’)
import sys sys.path.append('D:\\')
sys.modules:存储了当前程序中用到的所有模块,反射本文件中的内容
七、 os
- 和操作系统相关的数据
os.path.exists(path):如果path存在,返回True;如果path不存在,返回False
os.stat(‘文件路径’).st_size:获取文件大小
os.path.abspath():获取一个文件的绝对路径
import os v1 = os.path.abspath(path) print(v1)
os.path.dirname():获取路径的上级目录
import os v = r"D:\code\s21day14\20190409_192149.mp4" print(os.path.dirname(v))
补充:转义
v1 = r"D:\code\s21day14\n1.mp4" (推荐) v2 = "D:\\code\\s21day14\\n1.mp4"
os.path.join:路径的拼接
import os path = "D:\code\s21day14" # user/index/inx/fasd/ v = 'n.txt' result = os.path.join(path,v) print(result)
os.listdir:查看一个目录下所有的文件【第一层】
import os result = os.listdir(r'D:\code\s21day14') for path in result: print(path)
os.walk:查看一个目录下所有的文件【所有层】
import os result = os.walk(r'D:\code\s21day14') for a,b,c in result: # a,正在查看的目录 b,此目录下的文件夹 c,此目录下的文件 for item in c: path = os.path.join(a,item) print(path)
os.makedir:创建目录,只能生产一层目录(基本不用这个)
os.makedirs:创建目录及其子目录(推荐使用)
# 将内容写入指定文件中 import os file_path = r'db\xx\xo\xxxxx.txt' file_folder = os.path.dirname(file_path) if not os.path.exists(file_folder): os.makedirs(file_folder) with open(file_path,mode='w',encoding='utf-8') as f: f.write('asdf')
os.rename:重命名
# 将db重命名为sb import os os.rename('db','sb')
os.path.isdir:判断是否是文件夹
os.path.isfile:判断是否是文件
八、 shutil
- 用途:删除、重命名、压缩、解压等
shutil.rmtree(path):删除目录
# 删除目录 import shutil shutil.rmtree(path)
shutil.move:重命名
# 重命名 import shutil shutil.move('test','ttt')
shutil.make_archive:压缩文件
# 压缩文件 import shutil shutil.make_archive('zzh','zip','D:\code\s21day16\lizhong')
shutil.unpack_archive:解压文件
# 解压文件 import shutil shutil.unpack_archive('zzh.zip',extract_dir=r'D:\code\xxxxxx\xxxx',format='zip')
示例
import os import shutil from datetime import datetime ctime = datetime.now().strftime('%Y-%m-%d-%H-%M-%S') # 1.压缩lizhongwei文件夹 zip # 2.放到到 code 目录(默认不存在) # 3.将文件解压到D:\x1目录中。 if not os.path.exists('code'): os.makedirs('code') shutil.make_archive(os.path.join('code',ctime),'zip','D:\code\s21day16\lizhongwei') file_path = os.path.join('code',ctime) + '.zip' shutil.unpack_archive(file_path,r'D:\x1','zip')
九、 json
- json是一个特殊的字符串,长得像列表/字典/字符串/数字等嵌套
- 序列化:把python中的值转化为json格式的字符串
- 反序列化:将json格式的字符串转换成python的数据类型
- json格式要求:
- 只包含 int / float / str / list / dict
- 最外层必须是 list / dict
- 在json中,内部str必须是双引号
- 存在字典字典的key只能是str
- 不能连续load多次
json.dumps():序列化
- json只支持 dict / list / typle / str / int / float / True / False / None 序列化
- 字典或列表中如果有中文,序列化时,如果想保留中文显示
import json v = {'k1':'alex','k2':'李杰'} val = json.dumps(v,ensure_ascii = False)
json.loads():反序列化
import json # 序列化,将python的值转换为json格式的字符串。 v = [12,3,4,{'k1':'v1'},True,'asdf'] v1 = json.dumps(v) print(v1) # 反序列化,将json格式的字符串转换成python的数据类型 v2 = '["alex",123]' print(type(v2)) v3 = json.loads(v2) print(v3,type(v3))
json.dump:打开文件,序列化后,写入文件
import json v = {'k1':'alex','k2':'李杰'} f = open('x.txt',mode='w',encoding='utf-8') val = json.dump(v,f) print(val) f.close()
json.load:打开文件,读取文件内容
import json v = {'k1':'alex','k2':'李杰'} f = open('x.txt',mode='r',encoding='utf-8') data = json.load(f) f.close() print(data,type(data))
十、 pickle
- pickle与json的区别
- json
- 优点:所有语言通用
- 缺点:只能序列化基本的数据类型 list/dict 等
- pickle
- 优点:python中所有的东西都能被他序列化(socket对象),支持连续load多次
- 缺点:序列化的内容只有python认识
- json
pickle.dumps:序列化
- 序列化后的东西不可读
pickle.loads:反序列化
import pickle # 序列化 v = {1,2,3,4} val = pickle.dumps(v) print(val) # 反序列化 data = pickle.loads(val) print(data,type(data))
pickle.dump:写入文件(注意:mode=’wb’)
pickle.load:读取文件(注意:mode=’rb’)
import pickle # 写入文件 v = {1,2,3,4} f = open('x.txt',mode='wb') val = pickle.dump(v,f) f.close() # 读取文件 f = open('x.txt',mode='rb') data = pickle.load(f) f.close() print(data)
十一、 copy
- 拷贝模块
copy.copy:浅拷贝
copy.deepcopy:深拷贝
import copy v1 = [1,2,3] v2 = copy.copy(v1) #浅拷贝 v3 = copy.deepcopy(v1) #深拷贝
十二、 importlib
importlib.import_module:通过字符串的形式导入模块
#示例一: import importlib # 用字符串的形式导入模块。 redis = importlib.import_module('utils.redis') # 用字符串的形式去对象(模块)找到他的成员。 getattr(redis,'func')() #示例二: import importlib middleware_classes = [ 'utils.redis.Redis', # 'utils.mysql.MySQL', 'utils.mongo.Mongo' ] for path in middleware_classes: module_path,class_name = path.rsplit('.',maxsplit=1) module_object = importlib.import_module(module_path)# from utils import redis cls = getattr(module_object,class_name) obj = cls() obj.connect()
十三、 logging
日志模块:记录日志的
- 给用户看的:流水类,如银行流水
- 给程序员看的:
- 统计用的
- 用来做故障排除的,debug
- 用来记录错误,完成代码的优化
日志处理本质:Logger / FileHandler / Formatter
两种配置方式:
basicConfig
- 优点:使用方便
- 缺点:不能实现编码问题,不能同时向文件和屏幕上输出
logger对象
- 优点:能实现编码问题,能同时向文件和屏幕上输出
- 缺点:复杂
- 示例:
import logging # 创建一个logger对象 logger = logging.getLogger() # 创建一个文件操作符 fh = logging.FileHandler('log.log') # 创建一个屏幕操作符 sh = logging.StreamHandler() # 给logger对象绑定 文件操作符 logger.addHandler(fh) # 给logger对象绑定 屏幕操作符 logger.addHandler(sh) # 创建一个格式 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 给文件操作符 设定格式 fh.setFormatter(formatter) # 给屏幕操作符 设定格式 sh.setFormatter(formatter) # 用logger对象来操作 logger.warning('message')
日志异常级别
CRITICAL = 50 # 崩溃 FATAL = CRITICAL ERROR = 40 # 错误 WARNING = 30 WARN = WARNING INFO = 20 DEBUG = 10 NOTSET = 0
推荐处理日志方式
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 time import logging from logging import handlers # file_handler = logging.FileHandler(filename='x1.log', mode='a', encoding='utf-8',) file_handler = handlers.TimedRotatingFileHandler(filename='x3.log', when='s', interval=5, 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 ) for i in range(1,100000): time.sleep(1) logging.error(str(i))
注意事项:
# 在应用日志时,如果想要保留异常的堆栈信息。 import logging import requests logging.basicConfig( filename='wf.log', format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S %p', level=logging.ERROR ) try: requests.get('http://www.xxx.com') except Exception as e: msg = str(e) # 调用e.__str__方法 logging.error(msg,exc_info=True)
十四、 collections
OrderedDict:有序字典
from collections import OrderedDict odic = OrderedDict([('a', 1), ('b', 2), ('c', 3)]) print(odic) for k in odic: print(k,odic[k])
defaultdict:默认字典
deque:双端队列
namedtuple:可命名元组
# 创建一个类,这个类没有方法,所有属性的值都不能修改 from collections import namedtuple # 可命名元组 Course = namedtuple('Course',['name','price','teacher']) python = Course('python',19800,'alex') print(python) print(python.name) print(python.price)
十五、 re
15.1 正则表达式
- 定义
- 定义:正则表达式是一种规则匹配字符串的规则
- re模块本身只是用来操作正则表达式的,和正则本身没关系
- 为什么要有正则表达式?
- 匹配字符串
- 一个人的电话号码
- 一个人的身份证号
- 一台机器的ip地址
- 表单验证
- 验证用户输入的信息是否准确
- 银行卡号
- 爬虫
- 从网页源码中获取一些链接、重要数据
- 匹配字符串
- 正则规则
- 第一条规则 : 本身是哪一个字符,就匹配字符串中的哪一个字符
- 第二条规则 : 字符组[字符1字符2],一个字符组就代表匹配一个字符,只要这个字符出现在字符组里,那么就说明这个字符能匹配上
- 字符组中还可以使用范围
- 所有的范围都必须遵循ascii码从下到大来指定
- 常用:[0-9] [a-z] [A-Z]
- 元字符
- \d:表示所有的数字
- \是转义符 转义符转义了d,让d能够匹配所有0-9之间的数
- \w:表示大小写字母、数字、下划线
- \s:表示空白、空格、换行符、制表符
- \t:匹配制表符
- \n:匹配换行符
- \D:表示所有的非数字
- \W:表示除数字、字母、下划线之外的所有字符
- \S:表示非空白
- . :表示除了换行符之外的任意内容
- [] 字符组:只要在中括号内的所有字符都是符合规则的字符
- [^ ]非字符组:只要在中括号内的所有字符都是不符合规则的字符
- ^:表示一个字符的开始
- $:表示一个字符的结束
- |:表示或
- 注意:如果两个规则有重叠部分,总是长的在前面,短的在后面
- ():表示分组,给一部分正则规定为一组,|这个符号的作用域就可以缩小了
- 特殊:
- [\d]、[0-9]、\d:没有区别 都是要匹配一位数字
- [\d\D]、[\W\w]、[\S\s] 匹配所有一切字符
- 量词
- {n}:表示只能出现n次
- {n,}:表示至少出现n次
- {n,m}:表示至少出现n次,至多出现m次
- ?:表示匹配0次或1次,表示可有可无,但是有只能有一个,比如小数点
+
:表示匹配1次或多次*
:表示匹配0次或多次,表示可有可无,但是有可以有多个比如小数点后n位- 匹配0次出现的情况:
- 匹配任意的保留两位小数的数字
- 匹配一个整数或者小数
- 贪婪匹配
- 默认贪婪匹配,总是会在符合量词条件的范围内尽量多匹配
- 非贪婪匹配 :惰性匹配
- 总是匹配符合条件范围内尽量小的字符串
- 格式:元字符 量词 ? x
- 表示按照元字符规则在量词范围内匹配,一旦遇到x就停止
- 示例:.*?x 匹配任意的内容任意多次遇到x就立即停止
- 转义符:
- 正则表达式中的转义符在python的字符串中也刚好有转移的作用
- 但是正则表达式中的转义符和字符串中的转义符并没关系,且还容易有冲突
- 为了避免这种冲突,我们所有的正则都以在工具中的测试结果为结果
- 然后只需要在正则和待匹配的字符串外面都加r即可
邮箱规则
@之前必须有内容且只能是字母(大小写)、数字、下划线(_)、减号(-)、点(.)
@和最后一个点(.)之间必须有内容且只能是字母(大小写)、数字、点(.)、减号(-),且两个点不能挨着
最后一个点(.)之后必须有内容且内容只能是字母(大小写)、数字且长度为大于等于2个字节,小于等于6个字节
邮箱验证的正则表达式:
^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$
15.2 正则模块
re.findall:会匹配字符串中所有符合规则的项,并返回一个列表,如果没匹配到,返回空列表
import re ret = re.findall('\d+','alex83') print(ret) # findall 会匹配字符串中所有符合规则的项 # 并返回一个列表 # 如果未匹配到返回空列表
re.search:如果匹配到,返回一个对象,用group取值,如果没匹配到,返回None,不能用group
import re ret = re.search('\d+','alex83') print(ret) # 如果能匹配上返回一个对象,如果不能匹配上返回None if ret: print(ret.group()) # 如果是对象,那么这个对象内部实现了group,所以可以取值 # 如果是None,那么这个对象不可能实现了group方法,所以报错 # 会从头到尾从带匹配匹配字符串中取出第一个符合条件的项 # 如果匹配到了,返回一个对象,用group取值 # 如果没匹配到,返回None,不能用group
re.match:match = search + ^正则
import re ret = re.match('\d','alex83') == re.match('^\d','alex83') print(ret) # 会从头匹配字符串,从第一个字符开始是否符合规则 # 如果符合,就返回对象,用group取值 # 如果不符合,就返回None
re.finditer:在查询的结果超过1个的情况下,能够有效的节省内存,降低空间复杂度,从而也降低了时间复杂度
import re ret = re.finditer('\d','safhl02urhefy023908'*20000000) # ret是迭代器 for i in ret: # 迭代出来的每一项都是一个对象 print(i.group()) # 通过group取值即可
re.compile:在同一个正则表达式重复使用多次的时候使用能够减少时间的开销
import re ret = re.compile('\d+') r1 = ret.search('alex83') r2 = ret.findall('wusir74') r3 = ret.finditer('taibai40') for i in r3: print(i.group())
re.split:利用正则规则进行切割
import re ret = re.split('\d(\d)','alex83wusir74taibai') # 默认自动保留分组中的内容 print(ret)
re.sub / re.subn:利用正则规则进行替换
import re ret = re.sub('\d','D','alex83wusir74taibai',1) print(ret) # 'alexD3wusir74taibai' ret = re.subn('\d','D','alex83wusir74taibai') print(ret) # ('alexDDwusirDDtaibai', 4)
- 分组和re模块
关于group取值
import re ret = re.search('<(\w+)>(.*?)</\w+>',s1) print(ret) print(ret.group(0)) # group参数默认为0 表示取整个正则匹配的结果 print(ret.group(1)) # 取第一个分组中的内容 print(ret.group(2)) # 取第二个分组中的内容
分组命名:(?P 正则表达式)
import re ret = re.search('<(?P<tag>\w+)>(?P<cont>.*?)</\w+>',s1) print(ret) print(ret.group('tag')) # 取tag分组中的内容 print(ret.group('cont')) # 取cont分组中的内容
引用分组:(?P=组名) 这个组中的内容必须完全和之前已经存在的组匹配到的内容一模一样
import re # 方法一: s = '<h1>wahaha</h1>' ret = re.search('<(?P<tag>\w+)>.*?</(?P=tag)>',s) print(ret.group('tag')) # 'h1' # 方法二: s = '<h1>wahaha</h1>' ret = re.search(r'<(\w+)>.*?</\1>',s) print(ret.group(1)) # 'h1'
分组和findall:默认findall 优先显示分组内的内容,取消分组优先显示 :(?:正则)
import re ret = re.findall('\d(\d)','aa1alex83') # findall遇到正则表达式中的分组,会优先显示分组中的内容 print(ret) # 取消分组优先显示: ret = re.findall('\d+(?:\.\d+)?','1.234+2') print(ret)
有的时候我们想匹配的内容包含在不相匹配的内容当中,这个时候只需要把不想匹配的先匹配出来,再通过手段去掉
import re ret=re.findall(r"\d+\.\d+|(\d+)","1-2*(60+(-40.35/5)-(-4*3))") print(ret) # ['1', '2', '60', '', '5', '4', '3'] ret.remove('') print(ret) # ['1', '2', '60', '5', '4', '3']
爬虫示例
# 方法一: import re import json import requests def parser_page(par,content): res = par.finditer(content) for i in res: yield {'id': i.group('id'), 'title': i.group('title'), 'score': i.group('score'), 'com_num': i.group('comment_num')} def get_page(url): ret = requests.get(url) return ret.text pattern = '<div class="item">.*?<em class="">(?P<id>\d+)</em>.*?<span class="title">(?P<title>.*?)</span>.*?' \ '<span class="rating_num".*?>(?P<score>.*?)</span>.*?<span>(?P<comment_num>.*?)人评价</span>' par = re.compile(pattern,flags=re.S) num = 0 with open('movie_info',mode = 'w',encoding='utf-8') as f: for i in range(10): content = get_page('https://movie.douban.com/top250?start=%s&filter=' % num) g = parser_page(par,content) for dic in g: f.write('%s\n'%json.dumps(dic,ensure_ascii=False)) num += 25
# 方法二:进阶 import re import json import requests def parser_page(par,content): res = par.finditer(content) for i in res: yield {'id': i.group('id'), 'title': i.group('title'), 'score': i.group('score'), 'com_num': i.group('comment_num')} def get_page(url): ret = requests.get(url) return ret.text def write_file(file_name): with open(file_name,mode = 'w',encoding='utf-8') as f: while True: dic = yield f.write('%s\n' % json.dumps(dic, ensure_ascii=False)) pattern = '<div class="item">.*?<em class="">(?P<id>\d+)</em>.*?<span class="title">(?P<title>.*?)</span>.*?' \ '<span class="rating_num".*?>(?P<score>.*?)</span>.*?<span>(?P<comment_num>.*?)人评价</span>' par = re.compile(pattern,flags=re.S) num = 0 f = write_file('move2') next(f) for i in range(10): content = get_page('https://movie.douban.com/top250?start=%s&filter=' % num) g = parser_page(par,content) for dic in g: f.send(dic) num += 25 f.close()