python day 9: xlm模块,configparser模块,shutil模块,subprocess模块,logging模块,迭代器与生成器,反射

时间:2022-08-06 11:57:02

python day 9

2019/10/12

学习资料来自老男孩教育

1. xml模块

xml模块是在json没有出来之前,用于不同语言之间通信,交换,处理xml格式数据的一种方式。

1.1 初识xml

import requests

from xml.etree import ElementTree as ET

# 使用第三方模块requests发送HTTP请求,或者XML格式内容
response = requests.get('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=375132083')
result = response.text # 字符串类型 # 使用xml包中的ElementTree解析XML格式内容
# XML接收一个字符串作为参数,将其格式化特殊的对象
node = ET.XML(result) #获取内容
if node.text =='Y':
print('在线')

import requests response2 = requests.get('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=K234&UserID=starpinlan')
result2 = response2.text #字符串str from xml.etree import ElementTree as ET root = ET.XML(result2) #<class 'xml.etree.ElementTree.Element'>
# print(type(node2)) for node in root.iter('TrainDetailInfo'): #iter方法是找到root这个对象中的后代标签名是TrainDetailInfo的所有元素
print(node.tag,node.attrib) #输出它的标签名,以及它的属性
print(node.find('TrainStation').text) #find方法是找到指定名称的第一个子标签

1.2 遍历xml文档的指定节点

  • 创建一个xml文档,写入如下内容:

s1 = '''
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year id="year">2024</year>
<gdppc>141100</gdppc>
<neighbor direction="E" name="Austria" />
<neighbor direction="W" name="Switzerland" />
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year id="year">2027</year>
<gdppc>59900</gdppc>
<neighbor direction="N" name="Malaysia" />
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year id="year">2027</year>
<gdppc>13600</gdppc>
<neighbor direction="W" name="Costa Rica" />
<neighbor direction="E" name="Colombia" />
</country>
</data>
''' with open('xmltest.xml','w+',encoding='utf-8') as f:
f.write(s1)
f.flush()
  • 读取xml文档,不修改原文件

from xml.etree import ElementTree as ET
#使用XML格式化字符串
root = ET.XML(open('xmltest.xml',encoding='utf-8').read()) #此种方式只能读取,不可修改文件
print(root.tag)
for node in root.iter('country'):
print(node.tag,node.attrib,node.find('year').text)
child_node = node.find('year') #找到标签名为year的所有节点
new_year = int(child_node.text)+1 #将year标签的值加1
child_node.text = str(new_year)
child_node.set('name','year') #设置属性name,其值为year
# del child_node.attrib['name'] #删除name属性键值对 #保存文件需要另创建一个新文件
tree = ET.ElementTree(root) #创建一个内容为root的ElementTree对象
tree.write('newxml.xml',encoding='utf-8') #一定要通过write写入文件。
  • 使用parse方法解析文件,可以修改原文件。

#使用ElementTree的parse方法解析文件 from xml.etree import ElementTree as ET tree = ET.parse('xmltest.xml') #parse方法可以打开文件,并解析其内容
# print(tree,type(tree)) # <class 'xml.etree.ElementTree.ElementTree'>
root = tree.getroot() # getroot方法获得最顶层的根节点
# print(root.tag) # data for node in root.iter('year'):
print(node.tag,node.text)
new_year = int(node.text) + 1
node.text = str(new_year)
node.set('id','year') # 设置id属性,其值为year,
print(node.attrib) # attrib是字典形式 tree.write('xmltest.xml') #parse可以直接修改原文件
  • 查看一个节点都有哪些方法
from xml.etree  import ElementTree as ET

tree = ET.parse('xmltest.xml')
root = tree.getroot()
print(dir(root)) #查看节点都有哪些方法 '''
['__class__', '__copy__', '__deepcopy__', '__delattr__', '__delitem__', '__dir__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getstate__', '__gt__',
'__hash__', '__init__', '__init_subclass__', '__le__', '__len__', '__lt__', '__ne__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__setstate__', '__sizeof__',
'__str__', '__subclasshook__', 'append', 'attrib', 'clear', 'extend', 'find', 'findall', 'findtext',
'get', 'getchildren', 'getiterator', 'insert', 'items', 'iter', 'iterfind', 'itertext', 'keys', 'makeelement',
'remove', 'set', 'tag', 'tail', 'text']
#常用tag,attrib,find,text,set,iter,get,append,clear,extend,findall,getchildren,insert,makeelement
'''

1.3 通过python手工创建xml文档

from xml.etree import ElementTree as ET

root = ET.Element('namelist')  #通过Element类创建一个名为namelist的xml元素(对象)
print(root,type(root)) # <Element 'namelist' at 0x00000184AD6C21D8> <class 'xml.etree.ElementTree.Element'>
name1 = ET.SubElement(root,'name',attrib={'enrolled':'yes'}) # 给root创建子节点,子节点的标签名是name,属性
name1.text = 'lanxing' #给内容赋值
age1 = ET.SubElement(name1,'age',attrib={'checked':'no'}) # 给name1创建子节点
age1.text = '18'
sex1 = ET.SubElement(name1,'sex',attrib={'sex':'male'})
sex1.text = 'male' name2 = ET.SubElement(root,'name',attrib={'enrolled':'yes'}) # 给root创建子节点,子节点的标签名是name,属性
name2.text = '蓝星' #给内容赋值
age2 = ET.SubElement(name2,'age',attrib={'checked':'no'}) # 给name1创建子节点
age2.text = '28' # 必须是字符串才可以序列化
sex2 = ET.SubElement(name2,'sex',attrib={'sex':'male'})
sex2.text = 'female' tree = ET.ElementTree(root) # 通过ElementTree类生成文档对象
tree.write('xmltest2.xml',encoding='utf-8',xml_declaration=True) #将文档对象写入文件,declaration表示声明文件,相当于注释。

1.4 创建节点的两种方式

from xml.etree import ElementTree as ET

tree = ET.parse('xmltest.xml')

root = tree.getroot()
# 创建新节点的第一种方式:makeelement
son = root.makeelement('son',{'sex':'male'})
print(son,type(son)) # <Element 'son' at 0x000002E1E1B10138> <class 'xml.etree.ElementTree.Element'>
# 创建新节点的第二种方式:通过Element类进行创建,实际第一种方式也是调用Element类
son2 = ET.Element('son2',{'sex':'male'})
son2.text = '男'
# 将新节点添加到root上
root.append(son)
root.append(son2) tree.write('xmltest.xml',encoding='utf-8',short_empty_elements=False) # short参数是控制是否可简写的。

1.5 总结


XML:
1,解析:
str:ElementTree.XML(str)
文件:ElementTree.parse(file)
2,Element对象操作:
tag,text,find,iter,get,set,findall,append,insert,remove。
3,重新写入文件:
ElementTree(Element(tag,attrib)).write(filepath,encoding=None)
必须是ElementTree对象才有写入方法。
4,创建XML:
root= Element(tag,attrib)
ele = root.makeelement(tag,attrib)
root.append(ele)
ElementTree.SubElement(root,tag,attrib)
5,缩进
from xml.dom import minidom def prettify(root):
'''将节点转换成字符串,并添加缩进'''
rough_string = ET.tostring(root,'utf-8')
reparsed = minidom.parseString(rough_string) return reparsed.topprettyxml(indent='\t')
6,命名空间
7,非常重要
一切皆对象,type(obj)查看对象的类。dir(obj)查看对象具有的方法。

2. configparser模块

configparser模块用来处理配置文件,配置文件是以.ini结尾的文件,长得像下面这样。

[AutoUpdate] #[xxx]叫做节点

configfileurl = https://update.pan.baidu.com/autoupdate # 键值对,左边的叫key,右边的叫value

autoupdatecheckdelay = 30

configfilekey1 = EDAD921681272C3E37F34020450A6963

configfilekey2 = 132150629469920000

lstm_autoupdate = 1570589347

isautoupdate = 0

[PackageInstallInfo]

default = 2

c6aa1078e4d92ff0573452220ca2d8ae = 4

import configparser

con = configparser.ConfigParser()  # 创建一个ConfigParser对象
con.read('config.ini',encoding='utf-8') # 打开文件并读取文件内容,放进内存 # 1,获取所有节点
# con对象的sections方法,内存中寻找所有的[xxx],一个[xxx]就是一个配置文件的节点
ret = con.sections() # 获取所有的节点名称,并返回一个列表
print(ret) # ['AutoUpdate', 'PackageInstallInfo'] # 2,获取指定节点下所有的键值对,将key与值作为元组,元组作为列表的元素返回。
ret2 = con.items('AutoUpdate')
print(ret2) # [('configfileurl', 'https://update.pan.baidu.com/autoupdate'), ('isautoupdate', '0'), ('autoupdatecheckdelay', '30'), ('configfilekey1', 'EDAD921681272C3E37F34020450A6963'), ('configfilekey2', '132150629469920000'), ('lstm_autoupdate', '1570589347')] # 3,获取指定节点所有的键
ret3 = con.options('PackageInstallInfo')
print(ret3) # ['default', 'c6aa1078e4d92ff0573452220ca2d8ae'] # 4, 获取指定节点下指定key的值,get(sections,key)
value1 = con.get('PackageInstallInfo','default') #默认返回字符串
print(value1,type(value1))
# 可以使用getint方法,自动将字符串转换为整数返回
value2 = con.getint('PackageInstallInfo','default')
print(value2,type(value2))
# 可以使用getfloat方法,自动将字符串转换为浮点数返回
value3 = con.getfloat('PackageInstallInfo','default')
print(value3,type(value3))
# 如果值是布尔值,可以使用getboolean方法,自动将字符串转换为布尔值返回
# value4 = con.getboolean('PackageInstallInfo','default') # 会报错,因为其值不是布尔值 # 5,检查,添加,删除节点 has_sec = con.has_section('AutoUpdate') #判断是否有节点,如果有返回True
print(has_sec) con.add_section('name') con.remove_section('name') # 添加,删除操作必须重新写入文件,否则不能持久化保存。 # 6,检查,删除,设置指定节点内的键值对 #检查
has_opt =con.has_option('AutoUpdate','IsAutoUpdate') #删除
con.remove_option('AutoUpdate','IsAutoUpdate') #设置
con.set('AutoUpdate','IsAutoUpdate','0') con.write(open('config.ini','w')) #write写入得接收一个文件对象

3. shutil模块

shutil模块是高级的文件,文件夹,压缩包处理模块。

import shutil
# 将文件内容复制到另一个文件中
# shutil.copyfileobj(fsrc,fdst[,length]) 将一个文件流对象复制给另一个文件流对象,长度是可选的。
f1 =open('1.txt','r',encoding='utf-8')
f2 =open('2.txt','w',encoding='utf-8')
shutil.copyfileobj(f1,f2)
f1.close()
f2.close() # shutil.copyfile(src,dst),复制文件
shutil.copyfile('1.txt','3.txt') # shutil.copymode(src,dst) 仅复制文件的权限,用户,组和内容都不变
shutil.copymode('1.txt','2.txt') #dst要存在
# shutil.copystat(src,dst) 仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
shutil.copystat('1.txt', '2.txt')
# shutil.copy(src,dst) #复制文件和权限
shutil.copy('1.txt','2.txt')
# shutil.copy2(src,dst) # 复制文件和状态信息
shutil.copy2('1.txt','2.txt')
# shutil.ignore_patterns(*patterns)忽略某些格式的文件
# shutil.copytree(src, dst, symlinks=False, ignore=None) 递归地去复制文件夹
shutil.copytree('.','../day10',symlinks=True,ignore=shutil.ignore_patterns('*.py')) # shutil.rmtree(path[, ignore_errors[, onerror]])
shutil.rmtree('../day10')# 递归的去删除文件
# shutil.move(src, dst) 递归的去移动文件,它类似mv命令,其实就是重命名。
shutil.make_archive(base_name, format[,root_dir[,owner[,group[,logger]]]])
# 创建压缩包并返回文件路径,
# 其中base_name是指压缩包的文件包,也可以压缩包的路径。
# format:压缩包种类,zip,tar,bztar,gztar.
# root_dir: 要压缩的文件夹路径(默认当前目录)
# owner:用户,默认当前用户
# group:组,默认当前组
# logger:用于记录日志,通常是logging.Logger对象
shutil.make_archive('../test1','tar','.')

shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,

import zipfile

# 压缩
z = zipfile.ZipFile('laxi.zip', 'w') #创建一个zip的压缩包对象
z.write('a.log') # 往压缩包里面加入文件
z.write('data.data')
z.close() # 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall() # 解压所有文件
print(z.namelist()) # 获得压缩包内的所有文件名
z.extract('1.txt') # 单独解压指定文件
z.close() import tarfile # 压缩
tar = tarfile.open('your.tar','w') # 创建tar格式的压缩包
tar.add('/Users/wupeiqi/PycharmProjects/bbs2.log', arcname='bbs2.log') #往里面加入压缩文件,可以另外设置名字为bbs2.log
tar.add('/Users/wupeiqi/PycharmProjects/cmdb.log', arcname='cmdb.log')
tar.close() # 解压
tar = tarfile.open('your.tar','r')
tar.extractall() # 可设置解压地址
print(tar.getmembers()) #返回压缩包内的所有文件名
tar.extractfile('1.txt') #单独解压指定文件
tar.close()

4. subprocess模块

专门用于python执行系统命令

import subprocess

ret = subprocess.call('ipconfig')  # call执行系统命令,返回状态码
print(ret) # 成功的返回码是0 ret2 = subprocess.check_call('ipconfig') # 执行命令,返回状态码
print(ret2)
ret3 = subprocess.check_output('ipconfig') # 执行命令,返回字节类型的命令结果
print(ret3) '''
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()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等
''' subprocess.Popen('mkdir test',shell=True,cwd='.') # shell是True的情况下,就是将前面的字符串当作命令来输入
subprocess.Popen(['ipconfig','dir']) # 执行多个命令 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)

5. logging模块

线程安全,方便,多人来写时不会写脏数据

  • 只写单文件日志
import logging

logging.basicConfig(filename='log.log',
format='%(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.INFO,) #level表示大于10的才会记录
'''
CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0
'''
logging.critical('c')
logging.fatal('f')
logging.error("sssssss")
logging.warning('w')
logging.info('i')
logging.debug('d')
logging.log(logging.INFO,'333') #本质上都是调用的log方法。 '''
  • 写多文件日志
'''
#logging模块写多文件日志取决于两个方法:
一个专门用于写日志
一个用于比较
def w():
pass
def w2():
pass
def b():
if agr>30:
w()
w2()
b()
定义文件:
创建文件
file_1_1 = logging.FileHandler('11_1.log','a')
创建格式
fmt = logging.Formatter(fmt="%s(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s")
文件应用格式
file_1_1.setFormatter(fmt) file_1_2 = logging.FileHandler('11_2.log','a')
创建格式
fmt = logging.Formatter(fmt="%s(asctime)s - %(name)s - %(levelname)s - %(module)s: %(message)s")
文件应用格式
file_1_1.setFormatter(fmt) 用于比较的函数:
logger1 = logging.Logger('s1',level=logging.ERROR) # 就是b()
logger1.addHandler(file_1_1) # 将文件加入进来
logger1.addHandler(file_1_2) 写日志:
logger1.critical('1111')
'''

6. 生成器(generator)与迭代器(iterator)

能够使用for循环都叫可迭代对象(iterable),可以被next()函数调用并不断返回下一个值的对象叫迭代器(iterator)。

生成器与迭代器都是可迭代对象,生成器都是迭代器对象,可迭代对象不一定是迭代器。可以通过iter()函数将可迭代对象转换为迭代器。

  • 生成器

    python中,一边循环一边计算的机制叫做生成器,generator。

    创建生成器,有两种方法。第一种通过列表生成式。

    a = (x for x in range(10) if x>=2)像这种通过列表生成式的就是一个生成器,可以通过for循环或者next()内置函数来获得生成器的值,生成器如果迭代完毕,则会报错。

    li = [x for x in rang(10) ] 这个叫做列表推导式。与下面的函数是一个功能。
li = []
for i in range(10):
li.append(i)

通过关键字yield来声明是生成器。

def f():
for x in range(10):
yield x
# 这时 f()就是一个生成器 print(next(f())) # 可以next(generator)函数来创建生成器的下一个值
print(f().__next__()) # 也可以通过__next__()方法
for i in f():
print i

7. 反射

'''
# 反射
通过字符串的形式,导入模块
通过字符串的形式,去模块中寻找指定的函数,并执行 反射:根据字符串的形式去某个对象中去操作它的成员
getattr:
import random
寻找函数
target_func = getattr(random,'randint',None)
target_func()
寻找变量
target_var = getattr(random,'sample',None)
hasattr:
hasattr(random,'randint')
setattr:
setattr(random,'randxy',lambda x,y:x+y)
delattr:
delattr(random,'randxy')
扩展:
导入模块:
import random as rd
rd = __import__('random.randint',fromlist=True) '''
import random as rd
# 本质是调用__import__来导入模块
rm = __import__('random') # r1 = rm.randint(1,20)
# print(r1) f1 = getattr(rm,'randint') # random.randint本质上是调用了getattr方法,这种就叫做反射
print(f1(1,20))