目录
JSON模块&pickle模块
requests模块
time模块
datetime模块
logging模块
os模块
sys模块
hashlib模块
re模块、正则表达式
configparser模块
XML模块
shutil模块
subprocess 模块
JSON模块&pickle模块
1、安装模块的两种方法:
第一种:pip install 模块名
第二种:源码安装:先到官网下载模块的源码(选择download the tarball)----》先解压(解压文件夹中有一个setup.py文件)----》cd 目录----》pip setup.py install
2、JSON(JavaScript Object Notation)格式最初是JavaScript开发的,但随后成为一种常见格式,被包括Python在内的众多语言使用。模块json能够将简单的Python数据结构存储到文件中,并在程序再次运行时加载该文件中的数据;不仅可以在Python程序之间分享数据,还可以与使用其他编程语言的人分享,而且所有的.json类型的文件内容都是字符串形式的。
json.load() 读取文件内容,并将字符串转为基本数据类型;
json.dump()把基本类型数据存储到文件中;适用于所有的语言,适合跨平台使用,只支持Python中的基本数据类型;函数接受两个实参:要存储的数据以及可用于存储数据的文件对象;
pickle模块:功能同上,但是只能针对Python使用,会以字节的形式将数据存储到文件,但是支持Python中所有的数据类型,包括复杂的类等等。
#json.dump()存储,json.load()读取
import json
filename = r'json_file\favor_number.json'
with open(filename, 'r') as f_obj:
favor_number = json.load(f_obj)
print('I know your favorite number is %d.'%int(favor_number))
love_number = input('enter your favorite number:')
with open(filename,'w') as f_obj:
json.dump(love_number,f_obj)
#json.loads()将字符串形式的字典或列表,转为字典或列表
import json
s = "[1,2,3]"
li = json.loads(s)
print(li,type(li))#[1, 2, 3] <class 'list'>
#json.dumps()将字典或列表转为字符串
s = {"k":"v"}
dic = json.dumps(s)
print(dic,type(dic))#{"k": "v"} <class 'str'>
#如果字符串内部是字典,字典内部一定要用双引号,外部用单引号
n = '{"k":"v"}'
print(json.loads(n))
requests模块
#访问URL获取北京天气
import requests
import json
response = requests.get("http://wthrcdn.etouch.cn/weather_mini?city=北京")
response.encoding = "utf-8"
r = json.loads(response.text)
print(r)
time模块
import time
time.time()#返回系统当前时间戳,从1970年Unix(Linux的前身)正式商用开始算起(秒);
time.ctime()#返回系统当前时间,字符串格式#Tue Nov 27 09:07:55 2018
print(time.gmtime())#将时间戳转换为struct_time格式,按0时区算,跟本地时间差8小时
#time.struct_time(tm_year=2018, tm_mon=11, tm_mday=27, tm_hour=1,
# tm_min=12, tm_sec=46, tm_wday=1, tm_yday=331, tm_isdst=0)
print(time.localtime())#将时间戳转换为struct_time格式,返回本地时间
#与time.localtime()功能相反,将struct_time格式转为时间戳格式
print(time.mktime(time.localtime()))
time.sleep(0.1)#程序睡眠0.1秒
#将本地时间转换成特定格式
tm =time.strftime("%Y-%m-%d %H-%M-%S",time.localtime())
print(tm)
tm = time.strptime("2018-11-27 09:33","%Y-%m-%d %H:%M")
print(tm)#将特定时间格式转换为struct_time格式,如果没有写秒,默认从0开始
datetime模块
import datetime
#获取系统当前日期
print(datetime.date.today())#2018-11-27
#将时间戳转换为日期格式
print(datetime.date.fromtimestamp(time.time()))#2018-11-27
#返回系统当前准确时间
current_time = datetime.datetime.now()
print(current_time)#2018-11-27 09:48:21.483993
#将时间转换为struct_time格式
print(current_time.timetuple())
#时间运算
print(datetime.datetime.now() + datetime.timedelta(days=10))
#替换当前时间,可单独替换年月日
print(current_time.replace(2014,12,12))
#日期格式的时间可以比较大小
old_time = current_time.replace(2014)
print(type(old_time))#<class 'datetime.datetime'>
print(current_time>old_time)#True
logging模块
1、用于便捷记录日志且线程安全的模块
2、日志等级:
CRITICAL = 50 (危险的)
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
3、输出到屏幕
import logging
logging.warning("user [alex] attempted wrong password more than 3 times")
logging.critical("server is down")
4、写入文件
#把日志写到文件里,level值表示只写入这个等级或以上等级
import logging
logging.basicConfig(filename='text_file\example.log',level=logging.INFO)
logging.debug('This message should go to the log file')#等级不够,不写入
logging.info('So should this')
logging.warning('And this, too')
#日志格式加上时间
logging.basicConfig(filename='text_file\example.log',level=logging.INFO,
format='%(asctime)s%(message)s',
datefmt='%Y-%m-%d %I-%M-%S %p')
logging.warning(" It's time to go home.")
5、日志同时输出屏幕和将日志类型分别写入多个文件
注:只有【当前写等级】大于【日志等级】时,日志文件才被记录。
import logging
#创建日志类型
logger = logging.getLogger("测试日志")
#创建全局日志等级,全局等级为最低限制,局部只能高不能低,以全局等级为准
logger.setLevel(logging.DEBUG)
#创建输出屏幕对象和等级
sh = logging.StreamHandler()
sh.setLevel(logging.INFO)
#创建写入文件对象和等级
fh = logging.FileHandler("text_file\warning.log",'a',encoding='utf-8')
fh.setLevel(logging.WARNING)
#创建输出格式
formater1 = logging.Formatter('%(asctime)s-%(name)s-%(levelname)s-%(message)s')
formater2 = logging.Formatter('%(asctime)s-%(filename)s-%(levelname)s-%(message)s')
#给输出对象添加输出格式
sh.setFormatter(formater1)
fh.setFormatter(formater2)
#将输出对象添加到logger
logger.addHandler(sh)
logger.addHandler(fh)
#执行输出命令
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
6、日志记录格式:
os模块
1、获取当前文件的绝对路径
import os
print(os.path.abspath(__file__))
#C:\Users\Administrator\Desktop\Pycharm_Projects\basic_knowledge\模块.py
2、获取当前路径的上一级路径
import os
print(os.path.dirname(os.path.abspath(__file__)))
#C:\Users\Administrator\Desktop\Pycharm_Projects\basic_knowledge
3、调用另一个文件夹下的模块
import sys
import os
s = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(s)
#package为Python Package类型的文件夹
#不能使用import.login调用
from package import login
login.log()
4、当一个py文件中末尾加入下面的代码时,只有执行当前文件的时候,当前文件的特殊变量__name__ == "__main__",也即是说直接运行当前文件,就会直接执行函数;如果是导入到另一个文件中,只调用文件不会执行,只有执行文件时才会执行;如果py文件中没有if语句,直接在文件末尾调用了函数,也就是可以直接运行该文件,如果此时该文件被另一个文件调用了,函数会直接运行,不需要使用文件名.函数名的格式来执行函数。
if __name__ == "__main__":
main()
5、调用一个函数中的全局变量
import test
print(test.NAME)
6、模块中的特殊变量
#__doc__返回文件开头的注释
#__cached__字节码存放的位置
#__file__当前py文件的路径
#__package__当前模块所在的包
7、创建文件夹、子文件夹以及文件夹中的文件;
import os
#生成多层递归目录
os.makedirs('user_db/6225021542120/record')
os.makedirs('user_db/6225021542120/basic_info')
#另一种方法
card_num = "6225021542120"
#"user_db"为第一级文件夹名,依次二级,三级目录
os.makedirs(os.path.join("user_db",card_num,"record"))
#再次在card_num目录下新建文件夹
os.makedirs(os.path.join("user_db",card_num,"basic_info"))
8、模块中用于提供系统级别的操作
os.getcwd() #获取当前工作目录,即当前python脚本工作的目录路径
os.chdir("dirname") #改变当前脚本工作目录;相当于shell下cd
os.curdir #返回当前目录: ('.')
os.pardir #获取当前目录的父目录字符串名:('..')
os.makedirs('dir1/dir2') #可生成多层递归目录
os.removedirs('dirname1') #若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.mkdir('dirname') #生成单级目录;相当于shell中mkdir dirname
os.rmdir('dirname') #删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.listdir('dirname') #列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
os.remove() #删除一个文件
os.rename("oldname","new") #重命名文件/目录
os.stat('path/filename') #获取文件/目录信息
os.sep #操作系统特定的路径分隔符,win下为"\\",Linux下为"/"
os.linesep #当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"
os.pathsep #用于分割文件路径的字符串
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所指向的文件或者目录的最后修改时间
sys模块
1、sys模块中的基本操作
sys.argv #命令行参数List,第一个元素是程序本身路径
sys.exit(n) #退出程序,正常退出时exit(0)
sys.version #获取Python解释程序的版本信息
sys.maxint #最大的Int值
sys.path #返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform #返回操作系统平台名称
sys.stdin #输入相关
sys.stdout #输出相关
sys.stderror #错误相关
2、view_bar(num,total)制作一个进度条
import sys
import time
def view_bar(num,total):
rate = num / total #求出每次给的num占总数的比例
rate_num = int(rate * 100) #转换成百分比形式,取整
r = "\r%s%d%%" % (">" * rate_num, rate_num) #\r表示重新回到当前行的初始位置
sys.stdout.write(r) #重新输出r
if __name__ == "__main__":
for i in range(0,101):
time.sleep(0.001)
view_bar(i,100)
#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>100%
hashlib模块
1、对密码123进行双层加密
import hashlib
obj = hashlib.md5(bytes("asfdfdfdf",encoding="utf-8"))
obj.update(bytes('123',encoding='utf-8'))
ret = obj.hexdigest()
print(ret)
re模块、正则表达式
1、python中re模块提供了正则表达式相关操作
字符:
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
次数:
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
正则分组:从已经匹配到的数据中再提取数据
import re
#精准匹配
print(re.findall('alex','alexfkalexslalwxlp'))#['alex', 'alex']
#'.'能匹配到换行符以外的所有字符
print(re.findall('al.x','alexfkalexshalwxkp'))#['alex', 'alex', 'alwx']
#'^'从字符串初始位置匹配
print(re.findall('^alex','alexfkalexslalwxlp'))#['alex']
#'$'从字符串末尾位置匹配,只有在末尾才能匹配到
print(re.findall('^alex','alexfkalexslalwalex'))#['alex']
#'*'表示x前面的字符匹配0到多次
print(re.findall('al.*x','alexfkalexshalwxkp'))#['alexfkalexshalwx']
print(re.findall('ale*x','alexfkalexshalwxkp'))#['alex', 'alex']
print(re.findall('al*x','fkalxshalwx'))#['alx']
#'+'表示x前面的字符匹配1到多次
print(re.findall('al.+x','fkalxshuulw'))#[]
#'?'表示x前面的字符匹配0或1次
print(re.findall('al.?x','fkalxshuulw'))#['alx']
#{}表示匹配的范围
print(re.findall('al.{0,5}x','fkalrrrrxshuulw'))#['alrrrrx']
#[]表示字母的范围,以上元字符在中括号内不再有原有的意义
print(re.findall('al[a-z]x','alqx'))#['alqx']
#"^"在中括号内表示否的意思,只要不是z,都可以匹配到
print(re.findall('al[^z]x','alqx'))#['alqx']
#[/d]表示数字
print(re.findall('al[\d]x','al3x'))#['al3x']
#\b匹配一个单词边界,也就是指单词和空格间的位置,空白和非字母数字都可以匹配到
print(re.findall(r'I\b','I%am a cat.'))#['I']
#split()以什么为界分割字符串
print(re.split('\d+','ane1two2three3four4'))
#['ane', 'two', 'three', 'four', '']
2、match(pattern, string, flags=0) 从起始位置开始匹配,匹配成功返回一个对象,未匹配成功返回None
# pattern: 正则模型
# string : 要匹配的字符串
# falgs : 匹配模式
#匹配模式:
#re.I--使匹配对大小写不敏感
#re.L--做本地化识别匹配
#re.M--多行匹配,影响^和$
#re.S--是.匹配包括换行符在内的所有字符
# 无分组
origin = "hello alex bcd abcd lge acd 19"
r = re.match("h\w+", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果
# 有分组
# 为何要有分组?提取匹配成功的指定内容(先匹配成功全部正则,再匹配成功的局部内容提取出来)
r = re.match("h(\w+).*(?P<name>\d)$", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
3、findall(pattern, string, flags=0) 获取非重复的匹配列表;如果有一个组则以列表形式返回,且每一个匹配均是字符串;如果模型中有多个组,则以列表形式返回,且每一个匹配均是元祖;空的匹配也会包含在结果中。
# 无分组
r = re.findall("a\w+",origin)
print(r)
# 有分组
origin = "hello alex bcd abcd lge acd 19"
r = re.findall("a((\w*)c)(d)", origin)
print(r)
#[('bc', 'b', 'd'), ('c', '', 'd')]
#如果需要调用很多次,使用下面的方法更快速
s = "hello alex bcd alex lge alex acd 19"
obj = re.compile(r'a\w+')
print(obj.findall(s))
#['alex', 'alex', 'alex', 'acd']
4、search(pattern, string, flags=0) 浏览整个字符串去匹配第一个,未匹配成功返回None
# 无分组
origin = "hello alex bcd abcd lge acd 19"
r = re.search("a\w+", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组结果
# 有分组
r = re.search("a(\w+).*(?P<name>\d)$", origin)
print(r.group()) # 获取匹配到的所有结果
print(r.groups()) # 获取模型中匹配到的分组结果
print(r.groupdict()) # 获取模型中匹配到的分组中所有执行了key的组
#正则表达式两个\匹配到一个\
import re
r = re.search(r"\\", 'ori\gin')
print(r.group())
5、sub( ) 替换匹配成功的指定位置字符串
sub(pattern, repl, string, count=0, flags=0)
# pattern: 正则模型
# repl : 要替换的字符串或可执行对象
# string : 要匹配的字符串
# count : 指定匹配个数
# flags : 匹配模式
# 与分组无关
origin = "hello alex bcd alex lge alex acd 19"
r = re.sub("a\w+", "999", origin, 2)
print(r)
6、subn( ) 替换匹配成功的指定位置字符串,并返回替换次数
# 与分组无关
import re
origin = "hello alex bcd alex lge alex acd 19"
r = re.subn(r"a\w+", "999", origin)
print(r)
#('hello 999 bcd 999 lge 999 999 19', 4)
7、split( ) 根据正则匹配分割字符串
split(pattern, string, maxsplit=0, flags=0)
# pattern: 正则模型
# string : 要匹配的字符串
# maxsplit:指定分割个数
# flags : 匹配模式
# 无分组
origin = "hello alex bcd alex lge alex acd 19"
r = re.split("alex", origin, 1)
print(r)
#['hello ', ' bcd alex lge alex acd 19']
# 有分组
origin = "hello alex bcd alex lge alex acd 19"
r1 = re.split("(alex)", origin, 1)
print(r1)
#['hello ', 'alex', ' bcd alex lge alex acd 19']
r2 = re.split("(al(ex))", origin, 1)
print(r2)
#['hello ', 'alex', 'ex', ' bcd alex lge alex acd 19']
print(re.split('\d+','ane1two2three3four4'))
#['ane', 'two', 'three', 'four', '']
8、常用正则表达式
IP:
^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$
手机号:
^1[3|4|5|8][0-9]\d{8}$
邮箱:
[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+
必须是字母和数字组合:
(?!^[a-zA-Z]+$)(?!^\d+$)[0-9a-zA-Z]{3,}
字母、数字、下划线:
(?!^[a-zA-Z]+$)(?!^\d+$)(?!^_+$)[0-9a-zA-Z_]{3,}
9、练习题:正则表达式实现计算器的+ - * /运算
需求分析:
表达式 = 8*5-2+(10-(8*5+6)/10+5)*(3-2)+8*(9-4)
1、从前到后找,找到第一个以(开始)结尾,中间不含有括号的表达式
2、正则表达式:\([^()]\)
定义两个函数:
1、def 处理加减乘除(表达式):
return 结果
2、def 处理括号(表达式):
while True:
#先找到第一个,分割成三部分,得到括号内的表达式,不要括号
re.split('\( [^()] \)',表达式,1)
#8*5-2+(10- 8*5+6 /10+5)*(3-2)+8*(9-4)
ret = 加减乘除(8*5+6)
#再把表达式连起来
8*5-2+(10- ret /10+5)*(3-2)+8*(9-4)
#再返回给函数,知道没有括号,直接给运算函数,得到最终结果
import re
import sys
def no_bracket_rules(expression):
'''计算没有括号的乘除运算'''
md_check = re.search(r'\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*',expression)
if md_check:#乘除存在
#得到第一个*或/运算表达式
data = md_check.group()
if len(data.split("*")) > 1:# 当可以用乘号分割,证明有乘法运算
part1, part2 = data.split("*") # 用乘号分割
result = float(part1)*float(part2)
else:
part1, part2 = data.split("/")# 用除号分割
if part2 == 0:
sys.exit("计算过程中有被除数为0的存在,计算表达式失败!")
else:
result = float(part1) / float(part2)
# 获取第一个匹配到的乘除计算结果value,将value放回原表达式
# 以第一个*或/组成的表达式为界分割表达式
s1, s2 = re.split('\d+\.*\d*[\*\/]+[\+\-]?\d+\.*\d*', expression, 1)
# 将计算结果和剩下的表达式组合成新的字符串
new_exp = "%s%s%s" % (s1, result, s2)
return no_bracket_rules(new_exp)#递归表达式
else:#乘除不存在,在判断加减是否存在
expression = expression.replace('+-', '-') # 替换表达式里的所有'+-'
expression = expression.replace('--', '+') # 替换表达式里的所有'--'
expression = expression.replace('-+', '-') # 替换表达式里的所有'-+'
expression = expression.replace('++', '+') # 替换表达式里的所有'++'
as_check = re.search('\d+\.*\d*[\+\-]{1}\d+\.*\d*', expression)#匹配加减号
if not as_check: # 如果不存在加减号,则证明表达式已计算完成,返回最终结果
return expression
else:
#得到第一个+或-运算表达式
data = re.search('[\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*', expression).group()
if len(data.split("+")) > 1: #以加号分割成功,有加法计算
part1, part2 = data.split('+')
value = float(part1) + float(part2) # 计算加法
elif data.startswith('-'): # 如果是以'-'开头则需要单独计算,因为是负数
#分割为三部分,分别为'',正数,正数
part1, part2, part3 = data.split('-')
value = -float(part2) - float(part3) # 计算以负数开头的减法
else: #正数的减法运算
part1, part2 = data.split('-')
value = float(part1) - float(part2) # 计算减法
# 以第一个+或-分割表达式
s1, s2 = re.split('[\-]?\d+\.*\d*[\+\-]{1}\d+\.*\d*', expression, 1)
# 将计算后的结果替换回表达式,生成下一个表达式
new_exp = "%s%s%s" % (s1, value, s2)
return no_bracket_rules(new_exp) # 递归运算表达式
def bracket_rules(expression):
'''找到括号内的表达式,返回给计算函数'''
while True:
#验证表达式内是否含有以括号开始和结尾,且中间不含括号的
if re.findall(r"\(([^()]+)\)",expression):
# 找到第一个以(开始,以)结尾,且中间不含()的表达式
s_split = re.split(r"\(([^()]+)\)",expression,1)
ret = no_bracket_rules(s_split[1])#分割为三部分,中间为得到的表达式
# 将先前得到的表达式的计算结果和剩下的表达式组合成新的字符串
new_exp = "%s%s%s" % (s_split[0], ret, s_split[2])
return bracket_rules(new_exp)#返回函数,继续查找表达式
else:
#如果表达式内没有括号,就直接调用加减乘除函数进行计算
result = no_bracket_rules(expression)
return result
s = "8*5-2+(10-(8*5+6)/10+5)+6*(3-2)+8*9-4"
ret = bracket_rules(s)
print(ret)#122.4
configparser模块
- configparser用于处理配置文件,其本质上是利用open来操作文件。每个节点相当于一个key,下面的键值对相当于value;
- 首先创建config对象,然后读取文件config.read(文件),写入文件config.write(文件)
[section1] # 节点
k1 = v1 # 值
k2:v2 # 值
[section2] # 节点
k1 = v1 # 值
1、获取所有节点
import configparser
config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
ret = config.sections()
print(ret)
2、获取指定节点下所有的键值对
import configparser
config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
ret = config.items('section1')
print(ret)
3、获取指定节点下所有的建
import configparser
config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
ret = config.options('section1')
print(ret)
4、获取指定节点下指定key的值
import configparser
config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
#get函数可以将得到的字符串转换为相应类型数据,前提是可以转
v = config.get('section1', 'k1')
# v = config.getint('section1', 'k1')#转换为整数
# v = config.getfloat('section1', 'k1')#转换为浮点型
# v = config.getboolean('section1', 'k1')#转换为布尔值
print(v)
5、检查、删除、添加节点
import configparser
config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
# 检查
has_sec = config.has_section('section1')
print(has_sec)
# 添加节点
config.add_section("SEC_1")
config.write(open('xxxooo', 'w'))
# 删除节点
config.remove_section("SEC_1")
config.write(open('xxxooo', 'w'))
6、检查、删除、设置指定组内的键值对
import configparser
config = configparser.ConfigParser()
config.read('xxxooo', encoding='utf-8')
# 检查
has_opt = config.has_option('section1', 'k1')
print(has_opt)
# 删除
config.remove_option('section1', 'k1')
config.write(open('xxxooo', 'w'))
# 设置
config.set('section1', 'k10', "123")
config.write(open('xxxooo', 'w'))
XML模块
1、浏览器返回的数据类型:
a.HTML
b.Json
c.XML(XML是实现不同语言或程序之间进行数据交换的协议)
- 页面上做展示(字符串类型,一个XML格式数据)
- 配置文件(文件类型,内部数据XML格式)
2、操作XML:XML格式类型是节点嵌套节点,对于每一个节点均有以下功能,以便对当前节点进行操作:
from xml.etree import ElementTree as ET
# 直接解析XML文件
tree = ET.parse('xml_file\country.xml')
# 获取xml文件的根节点
root = tree.getroot()
#每一个节点都是一个Element对象
print(root)#<Element 'data' at 0x0000001E46461138>
print(root.tag)#获取当前节点的名字
print(root.attrib)#获取当前节点的属性{'title': 'total', 'age': '12'}
#遍历所有子节点,text获取节点中间的内容
for child in root:
print(child.tag,'-',child.attrib)
for grandchild in child:
print(grandchild.tag, grandchild.text)
# makeelement(tag,attrib)添加节点
# append(subelement)添加一个节点
# extend(elements)为当前节点扩展n个节点
# insert(index,subelement)为当前节点创建子节点,然后插入指定位置
# find(path)获取第一个寻找到的子节点
# findtext()获取第一个寻找到的子节点的内容
# findall(path)获取所有的子节点
# iterfind(path)获取所有子节点,并创建一个迭代器
# clear()清空所有节点
# get(key)获取当前节点的属性值
# print(root.attrib.get('title'))#total
# keys()获取当前节点的所有属性的key
# print(root.attrib.keys())#dict_keys(['title', 'age'])
# items()获取当前节点的所有属性值,每个属性都是一个键值对
# print(root.attrib.items())# dict_items([('title', 'total'), ('age', '12')])
# iter()在当前节点的子节点中根据节点名称寻找所有指定节点,并返回一个迭代器
# itertext()在当前节点的子孙中根据节点名称寻找所有指定的节点的内容,并返回一个迭代器
3、由于修改节点时,均是在内存中进行,其不会影响文件中的内容,所以,如果想要保存文件,则需要重新将内存中的内容写到文件。
############ 解析方式一 ############
from xml.etree import ElementTree as ET
# 利用ElementTree.parse将文件直接解析成XML对象
tree = ET.parse('xml_file\country.xml')#ElementTree类型
# 获取xml文件的根节点
root1 = tree.getroot()#element类型
#循环所有year节点,修改节点内容
for node in root1.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
#设置属性set(key,value)
node.set("name","charlie")
node.set("age","20")
#删除属性 del
del node.attrib["name"]
#写入文件
tree.write(r'xml_file\country2.xml',encoding='utf-8')
############ 解析方式二 ############
# 利用ElementTree.XML将字符串解析成XML对象
str_xml = open('xml_file\country.xml', 'r').read()
# 将字符串解析成xml特殊对象,root代指xml文件的根节点
root2 = ET.XML(str_xml)#element类型
#循环所有year节点,修改节点内容
for node in root2.iter('year'):
new_year = int(node.text) + 1
node.text = str(new_year)
#设置属性set(key,value)
node.set("name","charlie")
node.set("age","20")
#删除属性 del
del node.attrib["name"]
#写入文件,只有ElementTree类型的对象有写入功能
tree = ET.ElementTree(root2)
tree.write(r'xml_file\country3.xml',encoding='utf-8')
4、创建一个XML文件:<neighbor direction="W" name="Costa Rica" />如果节点没有内容,会进行自闭和
############ 创建方式一 ############
# #创建根节点
root_family = ET.Element('family')
#创建大儿子
son1 = ET.Element('son',{'name':'大儿子'})
#创建小儿子
son2 = ET.Element('son',{'name':'小儿子'})
#在大儿子中创建两个孙子
grandson1 = ET.Element('grandson',{'name':'大孙子'})
grandson2 = ET.Element('grandson',{'name':'二孙子'})
son1.append(grandson1)
son1.append(grandson2)
#把儿子添加到根目录
root_family.append(son1)
root_family.append(son2)
#写入文件
family_tree = ET.ElementTree(root_family)
family_tree.write(r'xml_file\family.xml',encoding='utf-8',
xml_declaration=True,short_empty_elements=False)
############ 创建方式二 ############
# 创建大儿子
son1 = root.makeelement('son', {'name': '儿1'})
grandson1 = son1.makeelement('grandson',{'name':'大孙子'})
########### 创建方式三 ############
#创建节点大儿子
son1 = ET.SubElement(root, "son", attrib={'name': '儿1'})
grandson1 = ET.SubElement(son1,'grandson',attrib={'name':'大孙子'})
5、由于原生保存的XML时默认无缩进,如果想要设置缩进的话,需要修改保存方式,所以先定义一个保存方式:
from xml.dom import minidom
def prettify(elem):
"""将节点转换成字符串,并添加缩进。
"""
rough_string = ET.tostring(elem, 'utf-8')
reparsed = minidom.parseString(rough_string)
return reparsed.toprettyxml(indent="\t")
root_family = ET.Element('family')
son1 = ET.Element('son',{'name':'大儿子'})
son2 = ET.Element('son',{'name':'小儿子'})
grandson1 = ET.Element('grandson',{'name':'大孙子'})
grandson2 = ET.Element('grandson',{'name':'二孙子'})
son1.append(grandson1)
son1.append(grandson2)
root_family.append(son1)
root_family.append(son2)
#调用方法写入文件
raw_str = prettify(root_family)
f = open(r"xml_file\family.xml",'w',encoding='utf-8')
f.write(raw_str)
f.close()
shutil模块
1、文件、文件夹基本操作
import shutil
#将文件内容拷贝到另一个文件中
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
#拷贝文件
shutil.copyfile('f1.log', 'f2.log')
#仅拷贝权限,内容、组、用户均不变
shutil.copymode('f1.log', 'f2.log')
#仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat('f1.log', 'f2.log')
#拷贝文件和权限
shutil.copy('f1.log', 'f2.log')
#拷贝文件和状态信息
shutil.copy2('f1.log', 'f2.log')
#递归的去拷贝文件夹
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))
#递归的去删除文件
shutil.rmtree('folder1')
#递归的去移动文件,它类似mv命令,其实就是重命名。
shutil.move('folder1', 'folder3')
2、压缩文件操作
shutil.make_archive(base_name, format,...)创建压缩包并返回文件路径,例如:zip、tar
- base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如:www =>保存至当前路径
如:/Users/wupeiqi/www =>保存至/Users/wupeiqi/
- format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
- root_dir: 要压缩的文件夹路径(默认当前目录)
- owner: 用户,默认当前用户
- group: 组,默认当前组
- logger: 用于记录日志,通常是logging.Logger对象
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置当前程序目录
import shutil
ret = shutil.make_archive("wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
#将 /Users/wupeiqi/Downloads/test 下的文件打包放置 /Users/wupeiqi/目录
import shutil
ret = shutil.make_archive("/Users/wupeiqi/wwwwwwwwww", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
3、shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
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.namelist()#查看所有文件
z.extract(member)#解压单个文件
z.extractall()#解压所有文件
z.close()
import tarfile
# 压缩
tar = tarfile.open('xml_file\your.tar','w')
#可以通过arcname来修改文件在压缩包中的名字
tar.add(r'xml_file\family.xml', arcname='son.xml')
tar.add(r'xml_file\country.xml', arcname='city.xml')
tar.close()
# 解压
tar = tarfile.open('your.tar','r')
tar.getmembers()#获取压缩包所有成员,得到一个特殊对象
#解压单个成员,需要传递一个对象
obj = tar.getmember('text.py')
tar.extract(obj)
tar.extractall() # 可设置解压地址
tar.close()
subprocess 模块
1、call 、check_call、check_output
import subprocess
#call执行命令,返回状态码
ret = subprocess.call(["ls", "-l"], shell=False)
ret = subprocess.call("ls -l", shell=True)
#check_call执行命令,如果执行状态码是 0 ,则返回0,否则抛异常
subprocess.check_call(["ls", "-l"])
subprocess.check_call("exit 1", shell=True)
#check_output执行命令,如果状态码是 0 ,则返回执行结果,否则抛异常
subprocess.check_output(["echo", "Hello World!"])
subprocess.check_output("exit 1", shell=True)
2、subprocess.Popen(...)用于执行复杂的系统命令
参数:
- args:shell命令,可以是字符串或者序列类型(如:list,元组)
- bufsize:指定缓冲。0 无缓冲,1 行缓冲,其他 缓冲区大小,负值 系统缓冲
- stdin, stdout, stderr:分别表示程序的标准输入、输出、错误句柄
- preexec_fn:只在Unix平台下有效,用于指定一个可执行对象(callable object),它将在子进程运行之前被调用
- close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会继承父进程的输入、输出、错误管道。
- 所以不能将close_fds设置为True同时重定向子进程的标准输入、输出与错误(stdin, stdout, stderr)。
- shell:同上
- cwd:用于设置子进程的当前目录
- env:用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父进程中继承。
- universal_newlines:不同系统的换行符不同,True -> 同意使用 \n
- startupinfo与createionflags只在windows下有效
- 将被传递给底层的CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
#执行普通命令
import subprocess
ret1 = subprocess.Popen(["mkdir","t1"])
ret2 = subprocess.Popen("mkdir t2", shell=True)
终端输入的命令分为两种:
- 输入即可得到输出,如:ifconfig
- 输入进行某环境,依赖再输入,如:python
import subprocess
obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
obj.stdin.close()
cmd_out = obj.stdout.read()
obj.stdout.close()
cmd_error = obj.stderr.read()
obj.stderr.close()
print(cmd_out)
print(cmd_error)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
obj.stdin.write("print(1)\n")
obj.stdin.write("print(2)")
out_error_list = obj.communicate()
print(out_error_list)
import subprocess
obj = subprocess.Popen(["python"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
out_error_list = obj.communicate('print("hello")')
print(out_error_list)