Python常用模块

time

 

UTC(Coordinated Universal Time,世界协调时)亦即格林威治天文时间,世界标准时间。在中国为UTC+8。DST(Daylight Saving Time)即夏令时。

 

时间戳(timestamp)的方式:通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。

 

元组(struct_time)方式:struct_time元组共有9个元素,返回struct_time的函数主要有gmtime(),localtime(),strptime()。下面列出这种方式元组中的几个元素:

 

索引(Index)    属性(Attribute)    值(Values)

0     tm_year(年)                 比如2011

1     tm_mon(月)             1 - 12

2     tm_mday(日)                 1 - 31

3     tm_hour(时)                 0 - 23

4     tm_min(分)             0 - 59

5     tm_sec(秒)             0 - 61

6     tm_wday(weekday)            0 - 6(0表示周日)

7     tm_yday(一年中的第几天)    1 - 366

8     tm_isdst(是否是夏令时)            默认为-1

 

time.localtime([secs]):将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。

 

time.gmtime([secs]):和localtime()方法类似,

a = time.localtime()

print('%s-%s-%s'%(a.tm_year,a.tm_mon,a.tm_mday))

 

gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。

晚8小时

 

time.time():返回当前时间的时间戳。

 

time.mktime(t):将一个struct_time转化为时间戳。

time.mktime(a)

 

time.sleep(secs):线程推迟指定的时间运行。单位为秒。

time.asctime([t]):把一个表示时间的元组或者struct_time表示为这种形式:'Sun Oct 1 12:04:38 2017'。如果没有参数,将会将time.localtime()作为参数传入。

time.ctime([secs]):把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。

time.strftime(format[, t]):把一个代表时间的元组或者struct_time(如由time.localtime()和time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。

 

举例:time.strftime("%Y-%m-%d %X", time.localtime()) #输出'2017-10-01 12:14:23'

time.strptime(string[, format]):把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。

 

举例:time.strptime('2017-10-3 17:54',"%Y-%m-%d %H:%M") #输出 time.struct_time(tm_year=2017, tm_mon=10, tm_mday=3, tm_hour=17, tm_min=54, tm_sec=0, tm_wday=1, tm_yday=276, tm_isdst=-1)

 

%a        Locale’s abbreviated weekday name.        

%A        Locale’s full weekday name.        

%b        Locale’s abbreviated month name.        

%B        Locale’s full month name.        

%c        Locale’s appropriate date and time representation.        

%d        Day of the month as a decimal number [01,31].        

%H        Hour (24-hour clock) as a decimal number [00,23].        

%I        Hour (12-hour clock) as a decimal number [01,12].        

%j        Day of the year as a decimal number [001,366].        

%m        Month as a decimal number [01,12].        

%M        Minute as a decimal number [00,59].        

%p        Locale’s equivalent of either AM or PM.        (1)

%S        Second as a decimal number [00,61].        (2)

%U        Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0.        (3)

%w        Weekday as a decimal number [0(Sunday),6].        

%W        Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0.        (3)

%x        Locale’s appropriate date representation.        

%X        Locale’s appropriate time representation.        

%y        Year without century as a decimal number [00,99].        

%Y        Year with century as a decimal number.        

%z        Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59].        

%Z        Time zone name (no characters if no time zone exists).

 

 

datatime

 

datetime模块定义了下面这几个类:

 

datetime.date:表示日期的类。常用的属性有year, month, day;

datetime.time:表示时间的类。常用的属性有hour, minute, second, microsecond;

.timetuple() 转换时间对象 小时,分钟,秒会丢失

datetime.datetime:表示日期时间。

datetime.timedelta:表示时间间隔,即两个时间点之间的长度。

datetime.tzinfo:与时区有关的相关信息。(这里不详细充分讨论该类,感兴趣的童鞋可以参考python手册)

我们需要记住的方法仅以下几个:

 

d=datetime.datetime.now() 返回当前的datetime日期类型

d.timestamp(),d.today(), d.year,d.timetuple()等方法可以调用

2.datetime.date.fromtimestamp(322222) 把一个时间戳转为datetime日期类型

 

3.时间运算

 

>>> datetime.datetime.now()

 

datetime.datetime(2017, 10, 1, 12, 53, 11, 821218)

 

>>> datetime.datetime.now() + datetime.timedelta(4) #当前时间 +4天

 

datetime.datetime(2017, 10, 5, 12, 53, 35, 276589)

 

>>> datetime.datetime.now() + datetime.timedelta(hours=4) #当前时间+4小时

 

datetime.datetime(2017, 10, 1, 16, 53, 42, 876275)

4.时间替换

 

>>> d.replace(year=2999,month=11,day=30)

 

datetime.date(2999, 11, 30)

 

 

 

 

 

Os

 

得到当前工作目录,即当前Python脚本工作的目录路径: os.getcwd()

返回指定目录下的所有文件和目录名:os.listdir()

函数用来删除一个文件:os.remove()

删除多个目录:os.removedirs(r“c:\python”)

检验给出的路径是否是一个文件:os.path.isfile()

检验给出的路径是否是一个目录:os.path.isdir()

判断是否是绝对路径:os.path.isabs()

检验给出的路径是否真地存:os.path.exists()

返回一个路径的目录名和文件名:os.path.split()     e.g os.path.split('/home/swaroop/byte/code/poem.txt') 结果:('/home/swaroop/byte/code', 'poem.txt')

分离扩展名:os.path.splitext()       e.g  os.path.splitext('/usr/local/test.py')    结果:('/usr/local/test', '.py')

获取路径名:os.path.dirname()

获得绝对路径: os.path.abspath() 

获取文件名:os.path.basename()

运行shell命令: os.system()

读取操作系统环境变量HOME的值:os.getenv("HOME")

返回操作系统所有的环境变量: os.environ 终端内生效

设置系统环境变量,仅程序运行时有效:os.environ.setdefault('HOME','/home/alex')

给出当前平台使用的行终止符:os.linesep    Windows使用'\r\n',Linux and MAC使用'\n'

指示你正在使用的平台:os.name       对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix'

重命名:os.rename(old, new)

创建多级目录:os.makedirs(r“c:\python\test”)

创建单个目录:os.mkdir(“test”)

获取文件属性:os.stat(file)

修改文件权限与时间戳:os.chmod(file)

获取文件大小:os.path.getsize(filename)

结合目录名与文件名:os.path.join(dir,filename)

改变工作目录到dirname: os.chdir(dirname)  终端内生效

获取当前终端的大小: os.get_terminal_size()

杀死进程: os.kill(10884,signal.SIGKILL)

 

sys

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

sys.exit(n)        退出程序,正常退出时exit(0)

sys.version        获取Python解释程序的版本信息

sys.maxint         最大的Int值

sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值

sys.platform       返回操作系统平台名称

sys.stdout.write('please:')  #标准输出 , 引出进度条的例子, 注,在py3上不行,可以用print代替

val = sys.stdin.readline()[:-1] #标准输入  封装input

sys.getrecursionlimit() #获取最大递归层数

sys.setrecursionlimit(1200) #设置最大递归层数

sys.getdefaultencoding()  #获取解释器默认编码

sys.getfilesystemencoding  #获取内存数据存到文件里的默认编码

 

 

 

Random

 

import random

print(random.randint(1,100))  (包含1和100)

print(random.randrange(1,100))

print(random.random()) 随机返回一个浮点数

print(random.choice('dsadsafsafasfas')) 随机返回字符串中一个字符

print(random.sample('dsadsadas3131',3)) 随便返回特定个字符串

 

生成随机验证码

import string

 ''.join(random.sample(string.ascii_lowercase #所有小写字符范围 + string.digits, 6) #所有数字范围)

 

a = list(range(100))  #  按顺生成1-100列表

random.shuffle(a)    # 打乱

print(a)

 

 

序列化

序列化是指把内存里的数据类型转变成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘或网络传输时只能接受bytes

json,用于字符串 和 python数据类型间进行转换

pickle,用于python特有的类型 和 python的数据类型间进行转换

dumps是将dict转化成str格式,loads是将str转化成dict格式。

dump和load也是类似的功能,只是与文件操作结合起来了。

Json模块提供了四个功能:dumps、dump、loads、load

 

pickle模块提供了四个功能:dumps、dump、loads、load

import pickle

data = {'k1':123,'k2':'Hello'}

 

# pickle.dumps 将数据通过特殊的形式转换位只有python语言认识的字符串

p_str = pickle.dumps(data)

print(p_str)

 

#pickle.dump 将数据通过特殊的形式转换位只有python语言认识的字符串,并写入文件

with open('D:/result.pk','wb',encoding='utf8') as fp:

    pickle.dump(data,fp)

 

import json

# json.dumps 将数据通过特殊的形式转换位所有程序语言都认识的字符串

j_str = json.dumps(data)

print(j_str)

 

#pickle.dump 将数据通过特殊的形式转换位只有python语言认识的字符串,并写入文件

with open('D:/result.json','wb',encoding='utf8') as fp:

    json.dump(data,fp)

 

json vs pickle:

JSON:

优点:跨语言、体积小

缺点:只能支持int\str\list\tuple\dict

Pickle:

优点:专为python设计,支持python所有的数据类型

缺点:只能在python中使用,存储数据占空间大

 

shelve

shelve模块是一个简单的k,v将内存数据通过文件持久化的模块,可以持久化任何pickle可支持的python数据格式

序列化:

import shelve

f = shelve.open('shelve_test')  # 打开一个文件

names = ["alex", "rain", "test"]

info = {'name':'alex','age':22}

f["names"] = names  # 持久化列表

f['info_dic'] = info

f.close()

 

反序列化:

import shelve

d = shelve.open('shelve_test')  # 打开一个文件

print(d['names'])

print(d['info_dic'])

只能修改key值,不能修改key列表里的值

del d['test'] #还可以删除

 

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')

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()

 

Xml

xml的格式如下,就是通过<>节点来区别数据结构的:

 

<?xml version="1.0"?>

<data>

    <country name="Liechtenstein">

        <rank updated="yes">2</rank>

        <year>2008</year>

        <gdppc>141100</gdppc>

        <neighbor name="Austria" direction="E"/>

        <neighbor name="Switzerland" direction="W"/>

    </country>

    <country name="Singapore">

        <rank updated="yes">5</rank>

        <year>2011</year>

        <gdppc>59900</gdppc>

        <neighbor name="Malaysia" direction="N"/>

    </country>

    <country name="Panama">

        <rank updated="yes">69</rank>

        <year>2011</year>

        <gdppc>13600</gdppc>

        <neighbor name="Costa Rica" direction="W"/>

        <neighbor name="Colombia" direction="E"/>

    </country>

</data>

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

 

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)

    for i in child:

        print(i.tag,i.text)

.tag是节点名

.attrib 是属性 字典形式

.text 是具体值,没有值为None

 

 

 

#只遍历year 节点

for node in root.iter('year'):

    print(node.tag,node.text)

修改和删除xml文档内容

 

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")

 

tree.write("xmltest.xml")

node.set("updated","yes") 设置属性值

 

#删除node

for country in root.findall('country'):

   rank = int(country.find('rank').text)

   if rank > 50:

     root.remove(country)

 

tree.write('output.xml')

自己创建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"})    #  name子节点

sex = ET.SubElement(name,"sex")  #  name子 节点

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

来看一个好多软件的常见配置文件格式如下

 

```cnf

[DEFAULT]

ServerAliveInterval = 45  

Compression = yes

CompressionLevel = 9

ForwardX11 = yes

 

[bitbucket.org]

User = hg

 

[topsecret.server.com]

Port = 50022

ForwardX11 = no

```

解析配置文件

 

```py

>>> import configparser # 导入模块

>>> config = configparser.ConfigParser()  #实例化(生成对象)

>>> config.sections()  #调用sections方法

[]

>>> config.read('example.ini')  # 读配置文件(注意文件路径)

['example.ini']

>>> config.sections() #调用sections方法(默认不会读取default)

['bitbucket.org', 'topsecret.server.com']

print(list(conf['bitbucket.org'].keys()))

['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11']

dafault值在每个节点都有

>>> 'bitbucket.org' in config #判断元素是否在sections列表内

True

>>> 'bytebong.com' in config

False

>>> config['bitbucket.org']['User'] # 通过字典的形式取值

'hg'

>>> config['DEFAULT']['Compression']

'yes'

>>> topsecret = config['topsecret.server.com']

>>> topsecret['ForwardX11']

'no'

>>> topsecret['Port']

'50022'

>>> for key in config['bitbucket.org']: print(key) # for循环 bitbucket.org 字典的key

...

user

compressionlevel

serveraliveinterval

compression

forwardx11

>>> config['bitbucket.org']['ForwardX11']

'yes'

```

其它增删改查语法

 

```python

[group1] # 支持的两种分隔符“=”, “:”

k1 = v1

k2:v2

 

[group2]

k1 = v1

 

import ConfigParser

 

config = ConfigParser.ConfigParser()

config.read('i.cfg')

 

# ########## 读 ##########

#secs = config.sections()

#print(secs)

#options = config.options('group2') # 获取指定section的keys

#print(options)

 

 

#item_list = config.items('group2') # 获取指定 section 的 keys & values ,key value 以元组的形式

#print(item_list)

 

#val = config.get('group1','key') # 获取指定的key 的value

#val = config.getint('group1','key')

 

# ########## 改写 ##########

#sec = config.remove_section('group1') # 删除section 并返回状态(true, false)

conf.remove_option("group3",'name')

#config.write(open('i.cfg', "w")) # 对应的删除操作要写入文件才会生效

 

#sec = config.has_section('wupeiqi')

#sec = config.add_section('wupeiqi')

#config.write(open('i.cfg', "w")) #

 

 

#config.set('group2','k1',11111)

#config.write(open('i.cfg', "w"))

 

#config.remove_option('group2','age')

#config.write(open('i.cfg', "w"))

 

 

Hashlib

Hash,一般翻译做“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫做预映射,pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。

 

简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。

 

HASH主要用于信息安全领域中加密算法,他把一些不同长度的信息转化成杂乱的128位的编码里,叫做HASH值.也可以说,hash就是找到一种数据内容和数据存放地址之间的映射关系

 

无法通过算法反解析出来

 

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD2、MD3和MD4。

 

输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);

不同的输入得到的不同的结果(唯一性);

 

重启软件变化

 

MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码杂凑函数,可以产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD2、MD3和MD4。

 

MD5功能

 

输入任意长度的信息,经过处理,输出为128位的信息(数字指纹);

不同的输入得到的不同的结果(唯一性);

 

MD5算法的特点

 

压缩性:任意长度的数据,算出的MD5值的长度都是固定的 

容易计算:从原数据计算出MD5值很容易

抗修改性:对原数据进行任何改动,修改一个字节生成的MD5值区别也会很大

强抗碰撞:已知原数据和MD5,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

MD5算法是否可逆?

 

MD5不可逆的原因是其是一种散列函数,使用的是hash算法,在计算过程中原文的部分信息是丢失了的。

 

MD5用途

 

防止被篡改:

 

比如发送一个电子文档,发送前,我先得到MD5的输出结果a。然后在对方收到电子文档后,对方也得到一个MD5的输出结果b。如果a与b一样就代表中途未被篡改。

 

比如我提供文件下载,为了防止不法分子在安装程序中添加木马,我可以在网站上公布由安装文件得到的MD5输出结果。

 

SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.

 

防止直接看到明文:

 

现在很多网站在数据库存储用户的密码的时候都是存储用户密码的MD5值。这样就算不法分子得到数据库的用户密码的MD5值,也无法知道用户的密码。(比如在UNIX系统中用户的密码就是以MD5(或其它类似的算法)经加密后存储在文件系统中。当用户登录的时候,系统把用户输入的密码计算成MD5值,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这不但可以避免用户的密码被具有系统管理员权限的用户知道,而且还在一定程度上增加了密码被破解的难度。)

防止抵赖(数字签名):

 

这需要一个第三方认证机构。例如A写了一个文件,认证机构对此文件用MD5算法产生摘要信息并做好记录。若以后A说这文件不是他写的,权威机构只需对此文件重新产生摘要信息,然后跟记录在册的摘要信息进行比对,相同的话,就证明是A写的了。这就是所谓的“数字签名”。

SHA-1

安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。

 

SHA是美国国家安全局设计的,由美国国家标准和技术研究院发布的一系列密码散列函数。

 

由于MD5和SHA-1于2005年被山东大学的教授王小云破解了,科学家们又推出了SHA224, SHA256, SHA384, SHA512,当然位数越长,破解难度越大,但同时生成加密的消息摘要所耗时间也更长。目前最流行的是加密算法是SHA-256 .

 

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慢。

 

重启软件不变化

 

撞库

将大量信息预先生成md5 和已知md5码进行匹配

 

subproccess

Os.system("xxx")

替换

os.system

os.spawn*

os.popen

import os

f = os.popen('arp -a')

print(f)

print(f.read())

 

三种执行命令的方法

 

subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs) #官方推荐

 

subprocess.call(*popenargs, timeout=None, **kwargs) #跟上面实现的内容差不多,另一种写法

 

subprocess.Popen() #上面各种方法的底层封装

 

发出一个新进程,word里不能打开qq,程序是独立进程,浏览器内容可以复制到其他地方,是通过操作系统copy命令,操作系统可以访问所有程序

 

a = subprocess.run(["arp","-a"],stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)

print(a)

print(a.stdout)  结果输出

print(a.stderr)   错误输出

 

Windows 终端是GBK,需要将结果转换GBK

a = subprocess.run(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=True)

# print(a)

print(a.stdout.decode('GBK'))

print(a.stderr.decode('GBK'))

 

stdout=subprocess.PIPE,stderr=subprocess.PIPE  结果和错误都输入到管道

Check=True 命令错误直接报错,程序终止

a = subprocess.run('ls -al | grep *.txt',stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)

shell=True  涉及linux 管道命令不需要在通过列表拼命令

 

#执行命令,返回命令执行状态 , 0 or 非0

>>> retcode = subprocess.call(["ls", "-l"])

 

#执行命令,如果命令结果为0,就正常返回,否则抛异常

>>> subprocess.check_call(["ls", "-l"])

0

 

#接收字符串格式命令,返回元组形式,第1个元素是执行状态,第2个是命令结果

>>> subprocess.getstatusoutput('ls /bin/ls')

(0, '/bin/ls')

 

#接收字符串格式命令,并返回结果

>>> subprocess.getoutput('ls /bin/ls')

'/bin/ls'

 

#执行命令,并返回结果,注意是返回结果,不是打印,下例结果返回给res

>>> res=subprocess.check_output(['ls','-l'])

>>> res

b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'

a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)

a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)

run方法卡着执行

Popen 发出一个新进程,主进程继续执行,不影响,通过poll()获取结果

 

Popen()方法

常用参数:

 

args:shell命令,可以是字符串或者序列类型(如:list,元组)

stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄

preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用

shell:同上

cwd:用于设置子进程的当前目录

env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。

 

def test():

    print("tesst")

a = subprocess.Popen('sleep 10',stderr=subprocess.PIPE,stdout=subprocess.PIPE,preexec_fn=test)

a.stdout

a.stdout.read()

poll()

 

Check if child process has terminated. Returns returncode

 

wait()  等待程序结束

 

Wait for child process to terminate. Returns returncode attribute.

 

terminate()终止所启动的进程Terminate the process with SIGTERM

 

kill() 杀死所启动的进程 Kill the process with SIGKILL

 

communicate()与启动的进程交互,发送数据到stdin,并从stdout接收输出,然后等待任务结束

 

>>> a = subprocess.Popen('python3 guess_age.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)

 

>>> a.communicate(b'22')

 

(b'your guess:try bigger\n', b'')

send_signal(signal.xxx)发送系统信号  20多个信号        

 

pid 拿到所启动进程的进程号

Linux ps -ef | grep xxx

 

a = subprocess.Popen('sleep 100',shell=True,stderr=subprocess.PIPE,stdout=subprocess.PIPE)

print(a.pid)

a.terminate()    #  发终止信息,不一定终止

a.kill()    #  强制终止

 

 

logging

logging的日志可以分为 debug()调试, info()信息, warning()告警, error()错误 and critical()严重5个级别

logging.warning("user [alex] attempted wrong password more than 3 times")

logging.critical("server is down")

默认日志等级为 warning(),info()无法显示,日志级别优先级低到高debug-info-warning-error-critical

其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。

logging.basicConfig(filename='example.log',level=logging.INFO)

 

自定义日志格式

感觉上面的日志格式忘记加上时间啦,日志不知道时间怎么行呢,下面就来加上!

import logging

logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')

logging.warning('is when this event was logged.')

 

#输出

12/12/2010 11:46:36 AM is when this event was logged.

 

%(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        用户输出的消息

 

日志同时输出到屏幕和文件

如果想同时把log打印在屏幕和文件日志里,就需要了解一点复杂的知识 了

 

 

Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适:

 

生成 logger对象

把filter对象加入

Logger.addFiter(对象)

生成 handler对象

绑定logger对象

生成formatter对象

绑定handler对象

设置日记级别

 

handler也可以设置日志级别

日志级别已全局优先级最高

全局设置为info后,console handler设置为info,如果输出日志级别是debug,屏幕不会显示

全局先过滤,在过滤handler

 

logger提供了应用程序可以直接使用的接口;

handler将(logger创建的)日志记录发送到合适的目的输出;

filter提供了细度设备来决定输出哪条日志记录;

formatter决定日志记录的最终输出格式。

他们之间的关系是这样的每个组件的主要功能

logger

每个程序在输出信息之前都要获得一个Logger。Logger通常对应了程序的模块名,比如聊天工具的图形界面模块可以这样获得它的Logger:

 

LOG=logging.getLogger(”chat.gui”)

而核心模块可以这样:

 

LOG=logging.getLogger(”chat.kernel”)

还可以绑定handler和filters

 

Logger.setLevel(lel):指定最低的日志级别,低于lel的级别将被忽略。debug是最低的内置级别,critical为最高

Logger.addFilter(filt)、Logger.removeFilter(filt):添加或删除指定的filter

Logger.addHandler(hdlr)Logger.removeHandler(hdlr):增加或删除指定的handler

Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以设置的日志级别

 

handler

handler对象负责发送相关的信息到指定目的地。Python的日志系统有多种Handler可以使用。有些Handler可以把信息输出到控制台,有些Handler可以把信息输出到文件,还有些 Handler可以把信息发送到网络上。如果觉得不够用,还可以编写自己的Handler。可以通过addHandler()方法添加多个多handler

 

Handler.setLevel(lel):指定被处理的信息级别,低于lel级别的信息将被忽略

Handler.setFormatter():给这个handler选择一个格式

Handler.addFilter(filt)、Handler.removeFilter(filt):新增或删除一个filter对象

每个Logger可以附加多个Handler。接下来我们就来介绍一些常用的Handler:

 

logging.StreamHandler 使用这个Handler可以向类似与sys.stdout或者sys.stderr的任何文件对象(file object)输出信息。

logging.FileHandler 和StreamHandler 类似,用于向一个文件输出日志信息。不过FileHandler会帮你打开这个文件

logging.handlers.RotatingFileHandler

 

这个Handler类似于上面的FileHandler,但是它可以管理文件大小。当文件达到一定大小之后,它会自动将当前日志文件改名,然后创建 一个新的同名日志文件继续输出。比如日志文件是chat.log。当chat.log达到指定的大小之后,RotatingFileHandler自动把 文件改名为chat.log.1。不过,如果chat.log.1已经存在,会先把chat.log.1重命名为chat.log.2。。。最后重新创建 chat.log,继续输出日志信息。它的函数是:

 

 RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])

其中filename和mode两个参数和FileHandler一样。

 

maxBytes用于指定日志文件的最大文件大小。如果maxBytes为0,意味着日志文件可以无限大,这时上面描述的重命名过程就不会发生。

backupCount用于指定保留的备份文件的个数。比如,如果指定为2,当上面描述的重命名过程发生时,原有的chat.log.2并不会被更名,而是被删除。

logging.handlers.TimedRotatingFileHandler

 

这个Handler和RotatingFileHandler类似,不过,它没有通过判断文件大小来决定何时重新创建日志文件,而是间隔一定时间就 自动创建新的日志文件。重命名的过程与RotatingFileHandler类似,不过新的文件不是附加数字,而是当前时间。它的函数是:

 

TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])

其中filename参数和backupCount参数和RotatingFileHandler具有相同的意义。

 

interval是时间间隔。

 

when参数是一个字符串。表示时间间隔的单位,不区分大小写。它有以下取值:

 

S 秒

M 分

H 小时

D 天

W 每星期(interval==0时代表星期一)

midnight 每天凌晨

formatter 组件

日志的formatter是个独立的组件,可以跟handler组合

 

fh = logging.FileHandler("access.log")

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

 

fh.setFormatter(formatter) #把formmater绑定到fh上

filter 组件

如果你想对日志内容进行过滤,就可自定义一个filter

 

class IgnoreBackupLogFilter(logging.Filter):

    """忽略带db backup 的日志"""

    def filter(self, record): #固定写法

        return   "db backup" not in record.getMessage()

注意filter函数会返加True or False,logger根据此值决定是否输出此日志

 

然后把这个filter添加到logger中

 

logger.addFilter(IgnoreBackupLogFilter())

下面的日志就会把符合filter条件的过滤掉

 

logger.debug("test ....")

logger.info("test info ....")

logger.warning("start to run db backup job ....")

logger.error("test error ....")

一个同时输出到屏幕、文件、带filter的完成例子

 

import logging

 

 

 

class IgnoreBackupLogFilter(logging.Filter):

    """忽略带db backup 的日志"""

    def filter(self, record): #固定写法

        return   "db backup" not in record.getMessage()

 

 

 

 

#console handler

ch = logging.StreamHandler()

ch.setLevel(logging.INFO)

#file handler

fh = logging.FileHandler('mysql.log')

#fh.setLevel(logging.WARNING)

 

 

#formatter

formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

#bind formatter to ch

ch.setFormatter(formatter)

fh.setFormatter(formatter)

 

logger = logging.getLogger("Mysql")

logger.setLevel(logging.DEBUG) #logger 优先级高于其它输出途径的

 

 

#add handler   to logger instance

logger.addHandler(ch)

logger.addHandler(fh)

 

 

 

#add filter

logger.addFilter(IgnoreBackupLogFilter())

 

logger.debug("test ....")

logger.info("test info ....")

logger.warning("start to run db backup job ....")

logger.error("test error ....")

文件自动截断例子

 

import logging

 

from logging import handlers

 

logger = logging.getLogger(__name__)

 

log_file = "timelog.log"

#fh = handlers.RotatingFileHandler(filename=log_file,maxBytes=10,backupCount=3)

fh = handlers.TimedRotatingFileHandler(filename=log_file,when="S",interval=5,backupCount=3)

 

 

formatter = logging.Formatter('%(asctime)s %(module)s:%(lineno)d %(message)s')

 

fh.setFormatter(formatter)

 

logger.addHandler(fh)

 

 

logger.warning("test1")

logger.warning("test12")

logger.warning("test13")

logger.warning("test14")

 

 

import logging

class IgnoreBackupLogFiter(logging.Filter):

    def filter(self, record):

        return "db backup" not in record.getMessage()

test = logging.getLogger("test")   #  生成日志对象

test.setLevel(logging.INFO)  # 设置日志级别

test.addFilter(IgnoreBackupLogFiter())  #  添加过滤条件

log_console = logging.StreamHandler()  #  屏幕输入对象

log_console.setLevel(logging.DEBUG)

log_file = logging.FileHandler("test2.log",encoding='utf-8')  #  写入文件对象

log_file.setLevel(logging.INFO)   #  设置Handler日志级别

test.addHandler(log_console)

test.addHandler(log_file)    #  绑定输出到日志对象

file_foramt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  #  文件日志格式

console_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')  #  屏幕日志格式

log_console.setFormatter(console_format)

log_file.setFormatter(file_foramt)   #  绑定格式到Handler

test.info("tetdasd")

 

分割

test_spite = handlers.RotatingFileHandler('log2.txt',maxBytes=10,backupCount=3)  #  按大小分割 保留几份

test_spite2 = handlers.TimedRotatingFileHandler('log3.txt',when="S",interval=10,backupCount=3) # when 为单位 interval为数值

 

re正则

手机号是有规则的,都是数字且是11位,再严格点,就都是1开头,如果能把这样的规则写成代码,直接拿规则代码匹配文件内容不就行了?

 

这么nb的玩法是什么?它的名字叫正则表达式!

 

re模块

正则表达式就是字符串的匹配规则,在多数编程语言里都有相应的支持,python里对应的模块是re

 

常用的表达式规则

'.'     默认匹配除\n之外的任意一个字符,若指定flag DOTALL,则匹配任意字符,包括换行

'^'     匹配字符开头,若指定flags MULTILINE,这种也可以匹配上(r"^a","\nabc\neee",flags=re.MULTILINE)

'$'     匹配字符结尾, 若指定flags MULTILINE ,re.search('foo.$','foo1\nfoo2\n',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") 或^

'\Z'    匹配字符结尾,同$

'\d'    匹配数字0-9

'\D'    匹配非数字

'\w'    匹配[A-Za-z0-9]

'\W'    匹配非[A-Za-z0-9]

's'     匹配空白字符、\t、\n、\r , re.search("\s+","ab\tc1\n3").group() 结果 '\t'

 

'(?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'}

re的匹配语法有以下几种

re.match 从头开始匹配

re.search 匹配包含

re.findall 把所有匹配到的字符放到以列表中的元素返回

re.split 以匹配到的字符当做列表分隔符

re.sub 匹配字符并替换

re.fullmatch 全部匹配

re.compile(pattern, flags=0)

 

Compile a regular expression pattern into a regular expression object, which can be used for matching using its match(), search() and other methods, described below.

 

The sequence

 

prog = re.compile(pattern)

result = prog.match(string)

is equivalent to

 

result = re.match(pattern, string)

but using re.compile() and saving the resulting regular expression object for reuse is more efficient when the expression will be used several times in a single program.

 

re.match(pattern, string, flags=0)

 

从起始位置开始根据模型去字符串中匹配指定内容,匹配单个

 

pattern 正则表达式

string 要匹配的字符串

flags 标志位,用于控制正则表达式的匹配方式

import re

obj = re.match('\d+', '123uuasf')

if obj:

    print obj.group()

Flags标志符

 

re.I(re.IGNORECASE): 忽略大小写(括号内是完整写法,下同)

M(MULTILINE): 多行模式,改变'^'和'$'的行为  有\n 认为一行

S(DOTALL): 改变'.'的行为,make the '.' special character match any character at all, including a newline; without this flag, '.' will match anything except a newline.  换行符也会匹配 .可以匹配\n

X(re.VERBOSE) 可以给你的表达式写注释,使其更可读,下面这2个意思一样

a = re.compile(r"""\d + # the integral part

                \. # the decimal point

                \d * # some fractional digits""",

                re.X)

 

b = re.compile(r"\d+\.\d*")

re.search(pattern, string, flags=0)

 

根据模型去字符串中匹配指定内容,匹配单个

 

import re

obj = re.search('\d+', 'u123uu888asf')

if obj:

    print obj.group()

re.findall(pattern, string, flags=0)

 

match and search均用于匹配单值,即:只能匹配字符串中的一个,如果想要匹配到字符串中所有符合条件的元素,则需要使用 findall。

 

import re

obj = re.findall('\d+', 'fa123uu888asf')

print obj

re.sub(pattern, repl, string, count=0, flags=0)

 

用于替换匹配的字符串

 

>>>re.sub('[a-z]+','sb','武配齐是abc123',)

 

>>> re.sub('\d+','|', 'alex22wupeiqi33oldboy55',count=2)

'alex|wupeiqi|oldboy55'

相比于str.replace功能更加强大

 

re.split(pattern, string, maxsplit=0, flags=0)

 

>>>s='9-2*5/3+7/3*99/4*2998+10*568/14'

>>>re.split('[\*\-\/\+]',s)

['9', '2', '5', '3', '7', '3', '99', '4', '2998', '10', '568', '14']

 

>>> re.split('[\*\-\/\+]',s,3)

['9', '2', '5', '3+7/3*99/4*2998+10*568/14']

re.fullmatch(pattern, string, flags=0)

 

整个字符串匹配成功就返回re object, 否则返回None

 

re.fullmatch('\w+@\w+\.(com|cn|edu)',"alex@oldboyedu.cn")

 

f = open("retest.txt",'r')

data = f.read()

print(data)

print(re.search("[0-9]{11}", data))

print(re.findall("1[0-9]{10}", data))

print(re.match("1[0-9]{10}", data))

 

 print(re.search("[0-9]{11}", data).group())        group 拿匹配内容

re.search("^ab","abd") == re.match("ab","abd") == re.search("\Aalex","alex")

Re.search("(xxxx)(xxxx)").groups 元组形式

(?P<name>…)

s = "130704200005250613"

print(re.search("(?P<name1>\d{3})(?P<name2>\d{3})(?P<name3>\d{4})",s).groups())

('130', '704', '2000')

 

s = "130704200005250613"

res = re.search("(?P<name1>\d{3})(?P<name2>\d{3})(?P<name3>\d{4})",s)

print(res.groupdict())

{'name1': '130', 'name2': '704', 'name3': '2000'}

 

按条件分割,列表形式

s = "testa11testb512312testc3421321"

print(re.split("\d+",s))

['testa', 'testb', 'testc', '']

匹配\ 需要用\\\\匹配

Maxsplit

 

正则替换

s = "testa11testb512312testc3421321"

print(re.sub("\d+","_",s,count=2))

testa_testb_testc3421321

 

全匹配

re.fullmatch

 

 

预先定义规则,存在内存里

re.compile

s = "testa11testb512312testc3421321"

pattern = re.compile("\d+")

print(pattern.sub('_',s))

testa_testb_testc_

 

 

 

posted @ 2018-06-25 00:26  深处灬印迹  阅读(18)  评论(0)    收藏  举报