Python基础知识:模块
目录
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)