subprocess模块,re模块,logging模块,XML模块,typing模块,包的简介
11.subprocess模块
subprocess模块可以通过python代码给操作系统终端发送命令,并且可以返回结果。该模块主要通过popen这个方法创建子进程,并连接它们的输入、输出和错误管道,执行cmd并获取它们的返回状态。
import subprocess
while True:
# 让用户输入终端命令
cmd_str = input('请输入终端命令:').strip()
# 调用Popen就会将用户的终端命令发送给本地操作系统的终端
# 得到一个对象,对象中包含着正确或错误的结果。
obj = subprocess.Popen(
cmd_str,shell=False, # 默认是False,需要改成True
stdout=subprocess.PIPE,
stderr=subprocess.PIPE
)
success = obj.stdout.read().decode('gbk') # windows默认gbk格式
if success: # 如果终端命令正确,输入成功
print(success,'正确的结果')
error = obj.stderr.read().decode('gbk')
if error: # 如果终端命令错误,输入失败
print(error,'错误的结果')
subprocess的run命令和popen命令类似。run会产生一个CompletedProcess的实例,以及returncode=0(0表示正常结束子进程),还有输出结果stdout,
popen 命令会产生一个subprocess.Popen object,通过read方法和decode方法可以取出输出结果,都有一个参数shell来控制是否用shell解释器来执行命令
poll()方法是检查进程是否结束,正常应该返回0
12.re模块和正则表达式
-
什么是re模块和正则表达式
正则表达式:
正则表达式是一门独立的技术, 任何语言都可以使用正则表达式,正则表达式是由一堆特殊的字符组合而来的。
由字符组和元字符 来 组合使用
re模块:
在python中,若想使用正则表达式,必须通过re模块来实现。
字符组: - [0-9] 可以匹配到一个0-9的字符 - [9-0]: 报错, 必须从小到大 - [a-z]: 从小写的a-z - [A-Z]: 从大写A-Z - [z-A]: 错误, 只能从小到大,根据ascii表来匹配大小。 - [A-z]: 总大写的A到小写的z。 注意: 顺序必须要按照ASCII码数值的顺序编写。
元字符:https://images2015.cnblogs.com/blog/1036857/201705/1036857-20170529203214461-666088398.png
元字符组合使用
\w\W: 匹配字母数字下划线与非字母数字下划线,匹配所有。
\d\D: 无论是数字或者非数字都可以匹配。
^$: 配合使用叫做精准匹配,如何限制一个字符串的长度或者内容。
|: 或。ab|abc如果第一个条件成立,则abc不会执行,怎么解决,针对这种情况把长的写在前面就好了,一定要将长的放在前面。
re模块三种比较重要的方法:
# findall():
# 可以匹配 "所有字符" ,拿到返回的结果,返回的结果是一个列表。
import re
demo = 'Sean json tank' #(不要带逗号,否则会返回空列表
# res = re.findall(元字符,分割范围,需要分割的字符串)
res = re.findall('[A-z]{4}',demo)
print(res) # 返回的结果是个列表
# 输出结果:['Sean', 'json', 'tank']
# #search():----> obj ----> obj.group()
# #在匹配一个字符成功后,拿到结果后结束,不往后匹配。
import re
demo1 = 'Sean json tank'
res1 = re.search('[A-z]{4}',demo1)
print(res1) # 直接打印是一个re.Match object,需要group一下
print(type(res1))
print(res1.group()) # 找出第一个元素后就不会再往下找了
# 输出结果:Sean
# match():----> obj ----> obj.group()
import re
demo3 = 'Sean json tank'
res2 = re.match('[A-z]',demo3)
# print(res2) # 从匹配字符的开头匹配,若开头不是想要的内容,则返回None,若是则继续往下匹配,直到全部匹配出结果
# print(res2.group())
if res2: # 可以通过判断是否匹配成功
print(res2)
print('匹配成功')
else:
print('匹配失败')
- 为什么要使用正则
比如要获取“一堆字符串”中的“某些字符”,正则表达式可以帮我们过滤,并提取出想要的字符数据。
例如:'dkljdwqoweiurorwytfc nnclaxxnjspwacmjdssu;slaksdoa'
我们需要在上面的字符串里面提取dssu,则可以使用正则表达式取过滤提取我们需要的数据
应用场景:
- 爬虫: re, BeautifulSoup4, Xpath, selector
- 数据分析过滤数据: re, pandas, numpy...
- 用户名与密码、手机认证:检测输入内容的合法性
- 用户名: alex
- 如何使用正则表达式和re模块
# 检测手机号码的合法性
import re
# phon_number = input('请输入11位手机号:').strip()
while True:
phon_number = input('请输入11位手机号:').strip()
# 需求: 11位、开头13/14/15/17/19
# # 参数1: 正则表达式 ''
# # 参数2: 需要过滤的字符串
# # ^: 代表“开头”
# # $: 代表“结束”
# # |: 代表“或”
# # (13|14): 可以获取一个值,判断是否是13或14.
# # {1}: 需要获取1个值 限制数量
# # []: 分组限制取值范围
# # # [0-9]: 限制只能获取0——9的某一个字符。
# if re.match(参数1,参数2): match表示从头开始比较
# if re.match('^(13|15|14|17|19)[0-9]{9}$',phon_number):
if re.match('(13|15|14|17|19)[0-9]{9}', phon_number):
print('手机号合法')
#
else:
print('不合法')
13.logging模块
配置日志的模块
logging的配置信息
"""
logging配置
"""
import os
import logging.config
# 定义三种日志输出格式 开始
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# 定义日志输出格式 结束
# ****************注意1: log文件的目录
BASE_PATH = os.path.dirname(os.path.dirname(__file__))
logfile_dir = os.path.join(BASE_PATH, 'log')
# print(logfile_dir)
# ****************注意2: log文件名
logfile_name = 'user.log'
# 如果不存在定义的日志目录就创建一个
if not os.path.isdir(logfile_dir):
os.mkdir(logfile_dir)
# log文件的全路径
logfile_path = os.path.join(logfile_dir, logfile_name)
# ****************注意3: log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
# 打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': logfile_path, # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG',
'propagate': True, # 向上(更高level的logger)传递
},
},
}
# 注意4:
def get_logger(user_type):
# 1.加载log配置字典到logging模块的配置中
logging.config.dictConfig(LOGGING_DIC)
# 2.获取日志对象
# logger = logging.getLogger('user')
# logger = logging.getLogger('bank')
# logger = logging.getLogger('shop')
logger = logging.getLogger(user_type)
return logger
# logging.config.dictConfig(LOGGING_DIC)
# # 调用获取日志函数的到日志对象
# logger = logging.getLogger('user')
# 通过logger日志对象,调用内部的日志打印
logger = get_logger('user')
# '只要思想不滑坡,方法总比问题多!'就是需要记录的日志信息
logger.info('学习不要浮躁,一步一个脚印!')
# logger.info('只要思想不滑坡,方法总比问题多!')
15.XML模块
xml是实现不同语言或程序之间进行数据交换的协议,跟json差不多,但json使用起来更简单,不过,古时候,在json还没诞生的黑暗年代,大家只能选择用xml呀,至今很多传统公司如金融行业的很多系统的接口还主要是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:
# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子节点找,只找一个
# print(root.findall('country')) #在root的子节点找,找所有
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,child.attrib['name'])
for i in child:
print(i.tag,i.attrib,i.text)
#只遍历year 节点
for node in root.iter('year'):
print(node.tag,node.text)
#---------------------------------------
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')
node.set('version','1.0')
tree.write('test.xml')
#删除node
for country in root.findall('country'):
rank = int(country.find('rank').text)
if rank > 50:
root.remove(country)
tree.write('output.xml')
#在country内添加(append)节点year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
for year in country.findall('year'):
if int(year.text) > 2000:
year2=ET.Element('year2')
year2.text='新年'
year2.attrib={'update':'yes'}
country.append(year2) #往country节点下添加子节点
tree.write('a.xml.swap')
自己创建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"})
sex = ET.SubElement(name,"sex")
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) #打印生成的格式
16.typing模块
https://www.cnblogs.com/liuqingzheng/p/11012099.html#_label1
14.包
1.什么是包?
包是一个带有__ init__.py的文件夹,包也可以被导入,并且可以一并导入包下的所有模块。
2.为什么要使用包?
包可以帮我们管理模块,在包中有一个__init__.py, 由它来帮我们管理模块。
3.怎么使用包?
- import 包.模块名
- from 包 import 模块名
- from 包.模块名 import 模块中的名字
4.导入包时发生的事情:
1.当包被导入时,会以包中的__ init __.py来产生一个名称空间。
2.然后执行__ init _.py文件, 会将 __ init __.py中的所有名字添加到名称空间中。
3.接着会将包下所有的模块的名字加载到__ init__.py产生的名称空间中。
4.导入的模块指向的名称空间其实就是_ini__.py产生的名称空间中。