一 hashlib加密
1 什么是hash
Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。
简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
2 MD5
MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD2、MD3和MD4。
MD5的功能:
- 输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);
- 不同的输入得到的不同的结果(唯一性)
MD5特点:
- 压缩性:任意长度的数据,算出的MD5值的长度都是固定的
- 容易计算:从原数据计算出MD5值很容易
- 抗修改性:对原数据进行任何改动,修改一个字节生成的MD5值区别也会很大
- 强抗碰撞:已知原数据和MD5,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
3 SHA-1
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。
MD5与SHA-1的比较:
由于MD5与SHA-1均是从MD4发展而来,它们的结构和强度等特性有很多相似之处,SHA-1与MD5的最大区别在于其摘要比MD5摘要长32 比特。对于强行攻击,产生任何一个报文使之摘要等于给定报文摘要的难度:MD5是2128数量级的操作,SHA-1是2160数量级的操作。产生具有相同摘要的两个报文的难度:MD5是264是数量级的操作,SHA-1 是280数量级的操作。因而,SHA-1对强行攻击的强度更大。但由于SHA-1的循环步骤比MD5多80:64且要处理的缓存大160比特:128比特,SHA-1的运行速度比MD5慢。
4 Python提供的相关模块
用于加密相关的操作,3.x里用hashlib代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
import hashlib # md5 m = hashlib.md5() m.update(b"Hello") m.update(b"It's me") print(m.digest()) # 返回2进制格式的hash值 m.update(b"It's been a long time since last time we ...") print(m.hexdigest()) # 返回16进制格式的hash值 # sha1 s1 = hashlib.sha1() s1.update("小猿圈".encode("utf-8")) s1.hexdigest() # sha256 s256 = hashlib.sha256() s256.update("小猿圈".encode("utf-8")) s256.hexdigest() # sha512 s512 = hashlib.sha256() s512.update("小猿圈".encode("utf-8")) s512.hexdigest()
二 logging模块
logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级、日志保存路径、日志文件回滚等;相比print,具备如下优点:
- 可以通过设置不同的日志等级,在release版本中只输出重要信息,而不必显示大量的调试信息
- print将所有信息都输出到标准输出中,严重影响开发者从标准输出中查看其它数据;logging则可以由开发者决定将信息输出到什么地方,以及怎么输出
''' 将log 输出至文件 logging.basicConfig(filename='testlog', level=logging.INFO) logging.debug('This message should go to the log file') logging.info('So should this') ''' ''' 自定义日志格式 logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y-%m-%d %I:%M:%S', filename='testlog', level=logging.DEBUG) logging.debug('test the time') ''' ''' 每个组件的主要功能 logger 每个程序在输出信息之前都要获取一个logger, logger通常对应了程序的模块名,比如mysql LOG = logging.getLogger("mysql") 而核心模块可以这样 LOG = logging.getLogger("chat.kernel") 还可以绑定handler和filters Logger.setLevel(lel): 指定最低的日志级别,低于lel的级别被忽略,debub是内置最低级别 Logger.addFilter(filt):添加指定的filter Logger.removeFilter(filt): 删除指定filter Logger.addHandler(hdlr):添加指定的handler handler handler对象负责发送相关的信息到指定目的地,Python的日志系统有多种handler可以使用,有些handler 可以把相关信息输出到控制台,有些handler可以把信息输出到文件,还有戏可以发送到网络上 Handler.setLevel(lel): 指定处理的信息级别,低于lel级别的信息被忽略 Handler.setFormatter(): 给handler设定一个格式 ''' ''' fmt中允许使用的变量可以参考下表。 %(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 用户输出的消息 ''' class IgnoreBackupLogFilter(logging.Filter): '''忽略带db backup的日志''' def filter(self, record): return 'db backup' not in record.getMessage() from logging import handlers # 生成log对象并设定全局log级别 logger = logging.getLogger('mysql') logger.setLevel(logging.DEBUG) # 把filter对象添加到logger中 logger.addFilter(IgnoreBackupLogFilter()) # 生成屏幕handler对象和文件handler对象 ch = logging.StreamHandler() # fh = logging.FileHandler('mysql') # 设置日志文件的滚动 fh = handlers.RotatingFileHandler('mysql', maxBytes=10, backupCount=3) # 设定handler日志级别 ch.setLevel(logging.DEBUG) fh.setLevel(logging.INFO) # 把handler对象绑定到logger logger.addHandler(ch) logger.addHandler(fh) # 生成formatter对象 file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %I:%M:%S') console_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %I:%M:%S') # 把formatter对象绑定handler对象 ch.setFormatter(console_formatter) fh.setFormatter(file_formatter) logger.debug('db backup') logger.debug('tete') logger.debug('db backup sdf') logger.warning('sdfdsf')
三 subprocess模块
运行python的时候,我们都是在创建并运行一个进程。像Linux进程那样,一个进程可以fork一个子进程,并让这个子进程exec另外一个程序。在Python中,我们通过标准库中的subprocess包来fork一个子进程,并运行一个外部的程序。
subprocess包中定义有数个创建子进程的函数,这些函数分别以不同的方式创建子进程,所以我们可以根据需要来从中选取一个使用。另外subprocess还提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。
import subprocess result = subprocess.run('ipconfig', stdout=subprocess.PIPE, check=True) # 返回一个结果对象 check 如果是TRUE并且命令返回结果非0就会报错 print(result.args) print(str(bytes(str(result.stdout, encoding='gbk'),encoding='utf8'),encoding='utf8')) ''' 如果使用管道: subprocess.run('df -h | grep disk1', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=TRUE) call()方法的使用 执行命令,如果结果为0就正常返回,否则跑出异常 subprocess.check_call(["ls", "-l"]) 接收字符串格式命令,返回元祖形式,第一个元素是执行状态,第二个是命令结果 subprocess.getstatusoutput(’ls /bin/ls' ) (0,'/bin/ls') 接收字符串格式命令,并返回结果 subprocess.getoutput('ls /bin/ls') '/bin/ls' 执行命令并返回结果,注意是返回结果不是打印 subprocess.check_out(['ls', '-l']) ''' ''' Popen()方法 args:shell命令,可以是字符串或者序列类型(如:list, 元祖) stdin,stdout,stderr:分别表示程序的标准输入,输出,错误句柄 preexec_fn: 只在unix平台下有效, 由于指定一个可执行对象(callable object), 它将在之前被调用 shell:shell = True cwd: 用于设置子进程当前的目录 env:用于指定子进程的环境变量 Popen方法与run方法的区别在于,run会与主程序串行执行, Popen会并行执行 poll(): 检查字进程的返回值 wait(): 等待发起的进程结束 terminate(): 终止所启动的进程 kill() : communicate() 与启动的进程交互, 发送数据到stdin,并从stdout接收输出 '''
四 colletction模块
ollections模块在内置数据类型(dict、list、set、tuple)的基础上,还提供了几个额外的数据类型:ChainMap、Counter、deque、defaultdict、namedtuple和OrderedDict等。
- 1.namedtuple: 生成可以使用名字来访问元素内容的tuple子类
- 2.deque: 双端队列,可以快速的从另外一侧追加和推出对象
- 3.Counter: 计数器,主要用来计数
- 4.OrderedDict: 有序字典
- 5.defaultdict: 带有默认值的字典
from collections import namedtuple # namedtuple point = namedtuple('Point', ['x','y']) p = point(1, 2) print(p.x) # 这样就可以给元祖命名访问了 print(p.y) circle = namedtuple('circle',['x', 'y', 'z']) c = circle(1,24,2) from collections import deque # deque是为了高效实现插入和删除操作的双向列表,适合用于队列和栈 # deque除了实现list的append()和pop()外,还支持appendleft()和popleft(),这样就可以非常高效地往头部添加或删除元素。 q = deque(['a', 'b', 'c']) q.append('x') # 最后插入 q.appendleft('y') # 向前插入 print(q) from collections import defaultdict # 使用dict时,如果引用的Key不存在,就会抛出KeyError。如果希望key不存在时,返回一个默认值,就可以用defaultdict dd = defaultdict(lambda: "None") dd['key1'] = 'abc' print(dd['key1']) # key1 存在返回abc print(dd['key2']) # key2不存在返回默认值 None from collections import OrderedDict # 使用OrderedDict可以保持key的顺序 d = dict([('a', 1), ('b', 2), ('c',3)]) print(d) # d是无序的 od = OrderedDict([('a', 1), ('b', 2), ('c',3)]) print(od) # 有序
五 文件copy打包模块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) 递归的去拷贝文件夹 importport 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 可选参数如下: 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 两个模块来进行的,详细: zipfile压缩&解压缩 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() tarfile压缩&解压缩 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()
用来压缩目录的脚本
import zipfile,os,sys def zip_dir(dirname, zipfilename): filelist = [] if os.path.isfile(dirname): filelist.append(dirname) else: for root, dirs, files in os.walk(dirname): for name in files: filelist.append(os.path.join(root, name)) f = zipfile.ZipFile(zipfilename, "w", zipfile.ZIP_DEFLATED) #ZIP_STORE, zipfile.ZIP_DEFLATED for tar in filelist: arcname = tar[len(dirname):] f.write(tar, arcname) f.close() if len(sys.argv) > 2 and sys.argv[1] != "" and sys.argv[2] != "": zip_dir(sys.argv[1], sys.argv[2]) else: print("#error params")
使用方法
python compress.py [dir] [zipfile]
六 正则表达式re模块
1 正则常用符号
'.' 默认匹配除 之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行 '^' 匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a"," abc eee",flags=re.MULTILINE) '$' 匹配字符结尾, 若指定flags MULTILINE ,re.search('foo.$','foo1 foo2 ',re.MULTILINE).group() 会匹配到foo1 '*' 匹配*号前的字符0次或多次, re.search('a*','aaaabac') 结果'aaaa' '+' 匹配前一个字符1次或多次,re.findall("ab+","ab+cd+abb+bba") 结果['ab', 'abb'] '?' 匹配前一个字符1次或0次 ,re.search('b?','alex').group() 匹配b 0次 '{m}' 匹配前一个字符m次 ,re.search('b{3}','alexbbbs').group() 匹配到'bbb' '{n,m}' 匹配前一个字符n到m次,re.findall("ab{1,3}","abb abc abbcbbb") 结果'abb', 'ab', 'abb'] '|' 匹配|左或|右的字符,re.search("abc|ABC","ABCBabcCD").group() 结果'ABC' '(...)' 分组匹配, re.search("(abc){2}a(123|45)", "abcabca456c").group() 结果为'abcabca45' 'A' 只从字符开头匹配,re.search("Aabc","alexabc") 是匹配不到的,相当于re.match('abc',"alexabc") 或^ '' 匹配字符结尾,同$ 'd' 匹配数字0-9 'D' 匹配非数字 'w' 匹配[A-Za-z0-9] 'W' 匹配非[A-Za-z0-9] 's' 匹配空白字符、 、 、 , re.search("s+","ab c1 3").group() 结果 ' ' '(?P<name>...)' 分组匹配 re.search("(?P<province>[0-9]{4})(?P<city>[0-9]{2})(?P<birthday>[0-9]{4})","371481199306143242").groupdict("city") 结果{'province': '3714', 'city': '81', 'birthday': '1993'}
2 Python正则表达式方法
re的匹配语法有以下几种
- re.match 从头开始匹配,必须第一个字符就开始匹配规则 使用不多
- re.search 匹配包含, 全局匹配,找到第一个匹配条件后 不再匹配
- re.findall 把所有匹配到的字符放到以列表中的元素返回
- re.split 以匹配到的字符当做列表分隔符
- re.sub 匹配字符并替换
3 FLAG标志位
- re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)
- M(MULTILINE): 多行模式,改变'^'和'$'的行为
- S(DOTALL): 改变'.'的行为,make the '.' special character match any character at all, including a newline; without this flag, '.' will match anything except a newline.
- X(re.VERBOSE) 可以给你的表达式写注释,使其更可读,下面这2个意思一样