一、操作系统接口
os模块提供了很多与操作系统相关联的函数;
导入os模块时建议使用 "import os" 风格而非 "from os import *"。原因是可以保证随操作系统变化而有所变化的 os.open() 函数不会覆盖内置函数 open();
内置的 dir() 和 help() 函数对使用 os 等大型模块时非常有用,dir()函数列出os模块的所有方法,help()方法用于说明os模块方法的使用;
Python 中使用 shutil 模块可实现文件或目录的复制、删除、移动;
二、shutil 模块实现文件或目录的复制、删除、移动
Python 中使用 shutil 模块可实现文件或目录的复制、删除、移动;
2.1、文件和文件夹复制
a)、shutil.copyfileobj(fsrc , fdst , length)
复制类文件(file-like)对象 fsrc
的内容到类文件对象 fdst
。 可选整数参数 length
,指定缓冲区大小。若length
的值为负数,复制操作不会将源数据分块进行复制。 默认的,为了避免不可控制的内存消耗,数据会被分块存入chunk中;
注意: 如果 fsrc
对象的当前文件位置不为 0 ,则只有从当前文件位置到文件末位的内容会被复制
b)、shutil.copyfile(src, dst)
复制文件 src
的内容(不包含元素据)到文件 dst
中, dst
必须是一个完整的目标文件。
源文件src
和目标文件 dst
不能为同一个文件,否则会报错。
目标文件 dst
必须为可写状态,否则会触发 IOError。
如果 dst
已经存在,则会被覆盖。
注意:字符设备、块设备和管道不能使用此方法复制。
使用字符串指定src
和 dst
路径。
C)、shutil.copymode(src, dst)
复制 src
的文件权限位到 dst
。文件的内容、属主和用户组不会受影响。
使用字符串指定src
和 dst
路径。
d)、shutil.copystat(src , dst)
复制文件 src
的文件权限位、最后访问 access 时间、最后修改 modification 时间和**标识 flags **到 dst
。
文件的内容、属主和用户组不会受影响。
使用字符串指定src
和 dst
路径。
e)、shutil.copy(src, dst)
复制文件 src
到 dst
文件或文件夹中。
如果 dst
是文件夹, 则会在文件夹中创建或覆盖一个文件,且该文件与 src
的文件名相同。
文件权限位会被复制。
使用字符串指定src
和 dst
路径。
f)、shutil.copy2(src, dst)
shutil.copy2(src , dst)函数相比较shutil.copy()
增加了复制文件的元数据功能。
实际上,该方法是 shutil.copy()
和 shutil.copystat()
组合。
该方法相当于 Unix 命令的 ` cp -p `。
g)、shutil.ignore_patterns(*patterns)
该工厂函数创建了一个可以被调用的函数, 该函数可以用于 shutil.copytree()
的 ** ignore 参数**的值, 以跳过正确匹配的文件和文件夹
h)、shutil.copytree(src, dst, symlinks=False, ignore=None)
递归复制整个 src
文件夹。
目标文件夹 dst
不能已经存在;shutil.copytree()
方法会自动创建 dst
根文件夹。
文件夹权限和时间通过 shutil.copystat()
复制, 单独的文件通过 shutil.copy2()
复制。
如果“symlinks
”为真, 源文件夹中的符号链接将会被保留,但是原链接的元数据不会被复制。如果值为假或被省略,则链接文件指向文件的内容和元数据复制到新文件夹树中。
如果指定了 ignore
, 那么他必须是调用队列(callable),且作为 shutil.copytree()
的参数,参数包括文件夹本机及并通过 os.listdir()
返回文件夹包含的内容。
由于 shutil.copytree()
递归复制,因此 ignore
会在复制每个子文件夹的时候被调用。
callable必须返回一个由当前文件夹下的文件夹和文件所组成的队列(i.e. a subset of the items in the second argument); 这些文件夹和文件在复制过程中会被忽略。
可以使用 shutil.ignore_patterns()
创建callable。
如果发生意外, shutil.Error()
返回错误原因。
2.2、文件/文件夹的删除和移动
a)、shutil.rmtree(path , ignore_errors , onerror)
删除整个目录树;
path
必须指向一个文件夹,但不能是一个指向文件夹的符号链接;
如果 ` ignore_errors ` 值为真, 则删除失败时的信息将会被忽略。如果值为假或省略,那么这些错误将通过 onerror
指定的 handler 进行处理;
如果 onerror
被省略,则会 raise 一个异常。
如果指定了 onerror
,则必须包含三个参数: function, path 和 excinfo的 callable 。 第一个参数 ` function ` , 该函数用于 raise 异常;该函数可以是 os.path.islink(), os.listdir(), os.remove(), os.rmdir()
。 第二个参数 path
为传递给第一个参数的路径。 第三个参数 excinfo
为 sys.exc_info()
返回的异常信息;
通过 onerror
raise 的异常不会被捕捉;
b)、shutil.move(src, dst)
将一个文件或文件夹从 src
移动到 dst
。如果 dst
已存在且为文件夹,则 src
将会被移动到 dst
内。 如果如 dst
存在但不是一个文件夹, 取决于 os.rename()
的语义,dst
可能会被覆盖。 如果 dst
与 src
在相同的文件系统下, 则使用 os.rename()
。 否认将使用 shutil.copy2()
复制 src
到 dst
并删除;
c)、shutil.Error
该异常汇集文件操作时 raise 的异常。 例如 shutil.copytree()
, the exception argument is a list of 3-tuples (srcname, dstname, exception);
import os
# 输出当前工作目录
print("当前工作目录为:" , os.getcwd())
# 更改当前工作目录
os.chdir("/home/zx/ZX/MyProject/Python/Runoob/ZX_21_命名空间和作用域")
# 输出更新后工作目录
print("输出更新后工作目录:" , os.getcwd())
def mkfile(path):
# 判断文件是否存在,存在则删除,不存在创建
if os.path.exists(path):
os.removedirs(path)
print("文件删除成功")
else:
os.mkdir(path)
print("文件创建成功")
path = "/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/file.txt"
mkfile(path)
当前工作目录为: /home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库
输出更新后工作目录: /home/zx/ZX/MyProject/Python/Runoob/ZX_21_命名空间和作用域
文件删除成功
import os
# 创建一个文件dir(os),用于存储dir(os)输出内容
file_dir = os.open("./file_dir(os)" , os.O_RDWR | os.O_CREAT)
for i in dir(os):
os.write(file_dir , (i + '\n').encode("utf-8"))
os.close(file_dir)
import sys
import os
# 通过重定向,输出help(os)结果至文件
def WriteHelpFileByStdout(path ,mode , module):
# 通过重定向,设置系统输出结果至文件路径path
sys.stdout = open(path , mode)
# 系统输出help(module)结果
help(module)
# 关闭文件
sys.stdout.close()
path = './file_help(os)'
mode = 'w+'
module = os
WriteHelpFileByStdout(path ,mode , module)
三、文件通配符
Python的glob模块可以实现查找符合特定规则的文件路径名功能
查找文件一般用到如下三个匹配符:”” 、“?” 、“[]”
”” 匹配0个或多个字符;
”?” 匹配单个字符;
”[]” 匹配指定范围内的字符;如[0-9]匹配数字
3.1、glob.glob函数
以list的形式返回所有匹配的文件路径列表;
glob.glob函数只有pathname一个参数,定义了文件路径匹配规则,可以是绝对路径,也可以是相对路径;
3.2、glob.iglob函数
glob.iglob()函数获取一个可遍历对象,使用它可以逐个获取匹配的文件路径名。与glob.glob()的区别是:glob.glob()同时获取所有的匹配路径,而glob.iglob()一次只获取一个匹配路径;
"""
三、文件通配符
Python的glob模块可以实现查找符合特定规则的文件路径名功能
查找文件一般用到如下三个匹配符:”” 、“?” 、“[]”
”” 匹配0个或多个字符;
”?” 匹配单个字符;
”[]” 匹配指定范围内的字符;如[0-9]匹配数字
"""
import glob
import os
# glob.glob()函数一次性获取相对路径下指定格式的所有文件
Relative_path = r"./*.py"
print("glob.glob()函数一次性获取相对路径下指定格式的所有文件:")
for i in glob.glob(Relative_path):
print(i)
print("glob.glob(Relative_path)返回值类型:" , type(glob.glob(Relative_path)))
# glob.glob()函数一次性获取绝对路径下指定格式的所有文件
Absolute_path = os.getcwd() + "/*.py"
print("glob.glob()函数一次性获取绝对路径下指定格式的所有文件:")
for i in glob.glob(Absolute_path):
print(i)
# glob.iglob()函数一次获取相对路径下指定格式的一个文件
Relative_path = r"./*.py"
print("glob.iglob()函数一次获取相对路径下指定格式的一个文件:")
for i in glob.iglob(Relative_path):
print(i)
print("glob.iglob(Relative_path)返回值类型:" , type(glob.iglob(Relative_path)))
glob.glob()函数一次性获取相对路径下指定格式的所有文件:
./1.py
./ZX_01_操作系统.py
./__init__.py
./ZX_02_文件通配符glob函数.py
glob.glob(Relative_path)返回值类型:
glob.glob()函数一次性获取绝对路径下指定格式的所有文件:
/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/1.py
/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/ZX_01_操作系统.py
/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/__init__.py
/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/ZX_02_文件通配符glob函数.py
glob.iglob()函数一次获取相对路径下指定格式的一个文件:
./1.py
./ZX_01_操作系统.py
./__init__.py
./ZX_02_文件通配符glob函数.py
glob.iglob(Relative_path)返回值类型:
3.3、使用glob.glob()获得文件路径
a)、获得当前文件夹下的所有文件
path参数为相对路径“./*”或者“*”;
b)、获得当前目录的某个子目录的文件A
子文件也属于相对路径,所以使用“./*/filenameA”或者“*/filenameA”。这里的“*/”代表下一层文件夹;
c)、当前处于目录A,获取目录B下文件C的路径
建议使用绝对路径,也就是使用类似“/*/*”的参数;
# “./*”或者“*”获得当前文件夹下的所有文件
print("(“./*”)或者(“*”)获得当前文件夹下的所有文件:"
, glob.glob("./*"))
# (“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件
print("(“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件:"
, glob.glob("./file/*"))
print("(“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件:"
, glob.glob("./*/file1.py"))
print("(“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件:"
, glob.glob("*/file2.py"))
# 当前处于目录A(ZX_22_标准库),获取目录B(ZX_21_命名空间和作用域)下文件C(file_dir(os))的路径
print(os.getcwd())
print(glob.glob("../*/file_dir(os)"))
(“./*”)或者(“*”)获得当前文件夹下的所有文件: ['./1.py', './ZX_01_操作系统.py', './file', './__init__.py', './ZX_02_文件通配符glob函数.py']
(“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件: ['./file/file2.py', './file/file1.py']
(“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件: ['./file/file1.py']
(“./*/filename”)或者(“*/filename”)获得当前目录的某个子目录的文件: ['file/file2.py']
/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库
['../ZX_21_命名空间和作用域/file_dir(os)']
四、命令行参数
sys.argv[]是一个从程序外部获取参数的桥梁,因我们从外部获取的参数可以是多个,所以sys.argv返回一个列表(list),所以才能用[]提取其中的元素,其中sys.argv[0]第一个元素是程序本身,即程序的路径,随后依次是外部给予的参数;
test.py代码如下:
# 四、命令行参数
# sys.argv[0]返回本文件路径
print("sys.argv[0]返回本文件路径:" , sys.argv[0])
# sys.argv返回列表list
print("sys.argv返回列表list:" , sys.argv)
# 从第二个元素开始输出
print("sys.argv[1:]:" , sys.argv[1:])
交互器中运行如下脚本,增加参数"this is a python"
输出结果如下:
zx@zx:~$ python3 '/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/1.py' this is a python
sys.argv[0]返回本文件路径: /home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/1.py
sys.argv返回列表list: ['/home/zx/ZX/MyProject/Python/Runoob/ZX_22_标准库/1.py', 'this', 'is', 'a', 'python']
sys.argv[1:]: ['this', 'is', 'a', 'python']
综上可看出,Sys.argv[ ]其实就是一个列表,里边的数据项就是用户输入的参数,参数是从程序外部输入的,而非代码本身,要想看到它的效果可以将程序保存,从外部运行程序并给出参数
五、错误输出重定向和程序终止
几种常见重定向的方式,参考文档:https://www.jb51.net/article/90506.htm
大多脚本的定向终止都使用 "sys.exit()"
5.1、控制台重定向
最简单常用的输出重定向方式是利用控制台命令,这种重定向由控制台完成,与Python本身无关;
Windows命令提示符(cmd.exe)和Linux Shell(bash等)均通过">"或">>"将输出重定向。其中,">"表示覆盖内容,">>"表示追加内容。类似地,"2>"可重定向标准错误。重定向到"nul"(Windows)或"/dev/null"(Linux)会抑制输出,既不屏显也不存盘;
以Windows命令提示符为例,将Python脚本输出重定向到文件:
E:\>echo print 'hello' > test.py # print 'hello' 代码块重定向写入test.py中
E:\>test.py > out.txt # test.py文件重定向至out.txt,覆盖内容
E:\>type out.txt # type命令直接显示文本文件内容,类似Linux系统的cat命令
hello
E:\>test.py >> out.txt # test.py文件重定向至out.txt,追加内容
E:\>type out.txt
hello
hello
E:\>test.py > nul # 重定向到"nul"(Windows)会抑制输出,既不屏显也不存盘
Linux Shell中执行Python脚本时,命令行应以"python"开头。除">"或">>"重定向外,还可使用tee命令。该命令可将内容同时输出到终端屏幕和(多个)文件中,"-a"选项表示追加写入,否则覆盖写入;
zx@zx:~$ python3 -c "print ('hello python')"
hello python
zx@zx:~$ python3 -c "print ('hello python')" > out.txt
zx@zx:~$ cat out.txt
hello python
zx@zx:~$ python3 -c "print ('hello python')" >> out.txt
zx@zx:~$ cat out.txt
hello python
hello python
zx@zx:~$ python3 -c "print ('I am')" | tee out.txt
I am
zx@zx:~$ python3 -c "print ('白杨')" | tee -a out.txt
白杨
zx@zx:~$ cat out.txt
I am
白杨
zx@zx:~$ python3 -c "print ('hello python')" > /dev/null
5.2、print 函数重定向
python2.x:
print >> filename , expr
此方式基于print语句的扩展形式,即"print obj >> expr
"(输出的obj对象追加重定向至expr中);
其中obj
为一个file-like(尤其是提供write方法的)对象,为None时对应标准输出(sys.stdout);expr
将被输出到该文件对象中;
python3.x:
print( expr , file = filename )
# print 函数重定向
from io import StringIO
import sys
memo=StringIO()
serr=sys.stderr
file=open('out.txt','w+')
print('StringIO' , memo)
print('stderr' , serr)
print('file' , file)
print(memo.getvalue() , None)
StringIO <_io.StringIO object at 0x7f08dba15168>
stderr <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'>
file <_io.TextIOWrapper name='out.txt' mode='w+' encoding='UTF-8'>
None
5.3、sys.stdout重定向
将一个可写对象(如file-like对象)赋给sys.stdout,可使随后的print语句输出内容重定向至该对象。重定向结束后,将sys.stdout恢复最初的缺省值,即标准输出。
import sys
# 5.3、sys.stdout重定向
# 方法一:
# 保存标准输出流
savedStdout = sys.stdout
# 打开文件,用于保存标准输出流内容
with open('./out.txt', 'w+') as file:
# 标准输出重定向至文件,以下print输出的内容均被重定向至文件file内
sys.stdout = file
print('方法:This message is for file!')
print('方法:print输出的内容被重定向至文件file内')
# 恢复标准输出流
sys.stdout = savedStdout
print('方法:This message is for screen!')
print('方法:print输出的内容显示在屏幕上')
方法:This message is for screen!
方法:print输出的内容显示在屏幕上
import os, sys
from io import StringIO
# 自定义多种具有write()方法的file-like对象,满足不同重定向需求
class RedirectStdout:
def __init__(self):
self.content = ''
self.savedStdout = sys.stdout
self.memObj, self.fileObj, self.nulObj = None, None, None
# 外部的print语句将执行本write()方法,并由当前sys.stdout输出
def write(self, outStr):
self.content.append(outStr)
#self.content += outStr
# 标准输出重定向至控制台
def toCons(self):
# sys.__stdout__
sys.stdout = self.savedStdout
# 标准输出重定向至内存
def toMemo(self):
self.memObj = StringIO()
sys.stdout = self.memObj
# 标准输出重定向至文件
def toFile(self, file='./out.txt'):
self.fileObj = open(file, 'a+', 1) # 改为行缓冲
sys.stdout = self.fileObj
# 抑制输出
def toMute(self):
self.nulObj = open(os.devnull, 'w')
sys.stdout = self.nulObj
def restore(self):
self.content = ''
if self.memObj.closed != True:
self.memObj.close()
if self.fileObj.closed != True:
self.fileObj.close()
if self.nulObj.closed != True:
self.nulObj.close()
sys.stdout = self.savedStdout # sys.__stdout__
# 实例化
redirObj = RedirectStdout()
#本句会抑制"Let's begin!"输出
sys.stdout = redirObj
print("Let's begin!")
# 屏显'Hello World!'和'I am Gavin.'(两行)
print('Hello World!' , redirObj.toCons())
print('I am Gavin' , redirObj.toCons())
# 写入'How are you?'和"Can't complain."(两行)
print('How are you?' , redirObj.toFile())
print("Can't complain." , redirObj.toFile())
# 屏显
print("What'up?" , redirObj.toCons())
# 无屏显或写入
print('' , redirObj.toMute())
# 控制台屏显'Never redirect me!'
os.system('echo Never redirect me!')
# 无屏显或写入
print('What a pity!' , redirObj.toMemo())
# 屏显
print('Hello?' , redirObj.toCons())
# 该串写入文件
print("Oh, Gavin can't hear me" , redirObj.toFile())
redirObj.restore()
# 屏显
print('Pop up')
Hello World! None
I am Gavin None
What'up? None
Never redirect me!
Hello? None
Pop up
out.txt文件内容:
How are you? None
Can't complain. None
Oh, Gavin can't hear me None
5.4、上下文管理器(Context Manager)
借助于上下文管理器语法,可不必向重定向使用者暴露sys.stdout
首先考虑输出抑制,基于上下文管理器语法实现如下:
import sys , contextlib
from io import StringIO
class DummyFile:
def write(self, outStr): pass
@contextlib.contextmanager
def MuteStdout():
savedStdout = sys.stdout
sys.stdout = StringIO() #DummyFile()
try:
yield
except Exception: #捕获到错误时,屏显被抑制的输出(该处理并非必需)
content, sys.stdout = sys.stdout, savedStdout
print (content.getvalue()) #; raise
#finally:
sys.stdout = savedStdout
使用示例如下:
with MuteStdout():
print "I'll show up when is executed!" #不屏显不写入
raise #屏显上句
print "I'm hiding myself somewhere:)" #不屏显
再考虑更通用的输出重定向:
import os, sys
from contextlib import contextmanager
@contextmanager
def RedirectStdout(newStdout):
savedStdout, sys.stdout = sys.stdout, newStdout
try:
yield
finally:
sys.stdout = savedStdout
使用示例如下:
def Greeting(): print 'Hello, boss!'
with open('out.txt', "w+") as file:
print "I'm writing to you..." #屏显
with RedirectStdout(file):
print 'I hope this letter finds you well!' #写入文件
print 'Check your mailbox.' #屏显
with open(os.devnull, "w+") as file, RedirectStdout(file):
Greeting() #不屏显不写入
print 'I deserve a pay raise:)' #不屏显不写入
print 'Did you hear what I said?' #屏显
可见,with内嵌块里的函数和print语句输出均被重定向。注意,上述示例不是线程安全的,主要适用于单线程。
当函数被频繁调用时,建议使用装饰器包装该函数。这样,仅需修改该函数定义,而无需在每次调用该函数时使用with语句包裹。示例如下:
import sys, cStringIO, functools
def MuteStdout(retCache=False):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
savedStdout = sys.stdout
sys.stdout = cStringIO.StringIO()
try:
ret = func(*args, **kwargs)
if retCache == True:
ret = sys.stdout.getvalue().strip()
finally:
sys.stdout = savedStdout
return ret
return wrapper
return decorator
若装饰器MuteStdout的参数retCache为真,外部调用func()
函数时将返回该函数内部print输出的内容(可供屏显);若retCache为假,外部调用func()
函数时将返回该函数的返回值(抑制输出)。
MuteStdout装饰器使用示例如下:
@MuteStdout(True)
def Exclaim(): print 'I am proud of myself!'
@MuteStdout()
def Mumble(): print 'I lack confidence...'; return 'sad'
print Exclaim(), Exclaim.__name__ #屏显'I am proud of myself! Exclaim'
print Mumble(), Mumble.__name__ #屏显'sad Mumble'
在所有线程中,被装饰函数执行期间,sys.stdout
都会被MuteStdout装饰器劫持。而且,函数一经装饰便无法移除装饰。因此,使用该装饰器时应慎重考虑场景。
接着,考虑创建RedirectStdout装饰器:
def RedirectStdout(newStdout=sys.stdout):
def decorator(func):
def wrapper(*args,**kwargs):
savedStdout, sys.stdout = sys.stdout, newStdout
try:
return func(*args, **kwargs)
finally:
sys.stdout = savedStdout
return wrapper
return decorator
使用示例如下:
file = open('out.txt', "w+")
@RedirectStdout(file)
def FunNoArg(): print 'No argument.'
@RedirectStdout(file)
def FunOneArg(a): print 'One argument:', a
def FunTwoArg(a, b): print 'Two arguments: %s, %s' %(a,b)
FunNoArg() #写文件'No argument.'
FunOneArg(1984) #写文件'One argument: 1984'
RedirectStdout()(FunTwoArg)(10,29) #屏显'Two arguments: 10, 29'
print FunNoArg.__name__ #屏显'wrapper'(应显示'FunNoArg')
file.close()
注意FunTwoArg()
函数的定义和调用与其他函数的不同,这是两种等效的语法。此外,RedirectStdout装饰器的最内层函数wrapper()
未使用"functools.wraps(func)"
修饰,会丢失被装饰函数原有的特殊属性(如函数名、文档字符串等)。
5.5、logging模块重定向
对于代码量较大的工程,建议使用logging模块进行输出。该模块是线程安全的,可将日志信息输出到控制台、写入文件、使用TCP/UDP协议发送到网络等等。
默认情况下logging模块将日志输出到控制台(标准出错),且只显示大于或等于设置的日志级别的日志。日志级别由高到低为CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET
,默认级别为WARNING。
以下示例将日志信息分别输出到控制台和写入文件:
import logging
logging.basicConfig(level = logging.DEBUG,
format = '%(asctime)s [%(levelname)s] at %(filename)s,%(lineno)d: %(message)s',
datefmt = '%Y-%m-%d(%a)%H:%M:%S',
filename = 'out.txt',
filemode = 'w')
#将大于或等于INFO级别的日志信息输出到StreamHandler(默认为标准错误)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter('[%(levelname)-8s] %(message)s') #屏显实时查看,无需时间
console.setFormatter(formatter)
logging.getLogger().addHandler(console)
logging.debug('gubed'); logging.info('ofni'); logging.critical('lacitirc')
通过对多个handler设置不同的level参数,可将不同的日志内容输入到不同的地方。本例使用在logging模块内置的StreamHandler(和FileHandler),运行后屏幕上显示:
[INFO ] ofni
[CRITICAL] lacitirc
out.txt文件内容则为:
2016-05-13(Fri)17:10:53 [DEBUG] at test.py,25: gubed
2016-05-13(Fri)17:10:53 [INFO] at test.py,25: ofni
2016-05-13(Fri)17:10:53 [CRITICAL] at test.py,25: lacitirc
除直接在程序中设置Logger、Handler、Formatter等外,还可将这些信息写入配置文件。示例如下:
#logger.conf
###############Logger###############
[loggers]
keys=root,Logger2F,Logger2CF
[logger_root]
level=DEBUG
handlers=hWholeConsole
[logger_Logger2F]
handlers=hWholeFile
qualname=Logger2F
propagate=0
[logger_Logger2CF]
handlers=hPartialConsole,hPartialFile
qualname=Logger2CF
propagate=0
###############Handler###############
[handlers]
keys=hWholeConsole,hPartialConsole,hWholeFile,hPartialFile
[handler_hWholeConsole]
class=StreamHandler
level=DEBUG
formatter=simpFormatter
args=(sys.stdout,)
[handler_hPartialConsole]
class=StreamHandler
level=INFO
formatter=simpFormatter
args=(sys.stderr,)
[handler_hWholeFile]
class=FileHandler
level=DEBUG
formatter=timeFormatter
args=('out.txt', 'a')
[handler_hPartialFile]
class=FileHandler
level=WARNING
formatter=timeFormatter
args=('out.txt', 'w')
###############Formatter###############
[formatters]
keys=simpFormatter,timeFormatter
[formatter_simpFormatter]
format=[%(levelname)s] at %(filename)s,%(lineno)d: %(message)s
[formatter_timeFormatter]
format=%(asctime)s [%(levelname)s] at %(filename)s,%(lineno)d: %(message)s
datefmt=%Y-%m-%d(%a)%H:%M:%S
此处共创建三个Logger:root,将所有日志输出至控制台;Logger2F,将所有日志写入文件;Logger2CF,将级别大于或等于INFO的日志输出至控制台,将级别大于或等于WARNING的日志写入文件。
程序以如下方式解析配置文件和重定向输出:
import logging, logging.config
logging.config.fileConfig("logger.conf")
logger = logging.getLogger("Logger2CF")
logger.debug('gubed'); logger.info('ofni'); logger.warn('nraw')
logger.error('rorre'); logger.critical('lacitirc')
logger1 = logging.getLogger("Logger2F")
logger1.debug('GUBED'); logger1.critical('LACITIRC')
logger2 = logging.getLogger()
logger2.debug('gUbEd'); logger2.critical('lAcItIrC')
运行后屏幕上显示:
[INFO] at test.py,7: ofni
[WARNING] at test.py,7: nraw
[ERROR] at test.py,8: rorre
[CRITICAL] at test.py,8: lacitirc
[DEBUG] at test.py,14: gUbEd
[CRITICAL] at test.py,14: lAcItIrC
out.txt文件内容则为:
2016-05-13(Fri)20:31:21 [WARNING] at test.py,7: nraw
2016-05-13(Fri)20:31:21 [ERROR] at test.py,8: rorre
2016-05-13(Fri)20:31:21 [CRITICAL] at test.py,8: lacitirc
2016-05-13(Fri)20:31:21 [DEBUG] at test.py,11: GUBED
2016-05-13(Fri)20:31:21 [CRITICAL] at test.py,11: LACITIRC
5.6、make 2>&1 | tee log.txt命令解析
1. make是什么?
make是linux下一个非常强大的命令,简单点就是你要编译你的源代码就得靠他了。
2. 2>&1是什么意思?
0 stdin,1 stdout,2 stderr
2>&1应该分成两个部分来看,一个是2>以及另一个是&1,
其中2>就是将标准出错重定向到某个特定的地方;&1是指无论标准输出在哪里。
所以2>&1的意思就是说无论标准出错在哪里(哪怕是没有),都将标准出错重定向到标准输出中。
3. | 管道
管道的作用是提供一个通道,将上一个程序的标准输出重定向到下一个程序作为下一个程序的标准输入。
通常使用管道的好处是一方面形式上简单,另一方面其执行效率要远高于使用临时文件。
这里使用管道的目的是将make程序的输出重定向到下一个程序,其最终目的是用来将输出log存入文件中。
4. tee是用来干什么的?
tee从标准输入中读取,并将读入的内容写到标准输出以及文件中。
所以这里tee命令的作用是将数据读入并写到标准输出以及log.txt中。
之所以要将编译产生的log保存到log.txt中,
其原因是你的标准输出的缓存可能是有限制的,而你编译程序产生的log可能会很多,
这样很可能会造成log不完整;
其目的是当程序发生编译错误的时候,我们可以从log.txt中看到完整的编译log,
这样方便查找编译错误。
六、字符串正则匹配
re模块为高级字符串的处理提供了正则表达式的工具,详细内容见正则表达式一文
import re
# 匹配f开头的字符
print(re.findall(r'\bf[a-z]*', 'which foot or hand fell fastestfaaaat'))
print(re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat'))
['foot', 'fell', 'fastestfaaaat']
cat in the hat
七、数学
math模块为浮点运算提供了对底层C函数库的访问
import math
print("pi/4的余弦值:" , math.cos(math.pi/4))
print("math.log(1024 , 4)返回值:" , math.log(1024 , 4))
pi/4的余弦值: 0.7071067811865476
math.log(1024 , 4)返回值: 5.0
random()提供了生成随机数的工具
import random
# 列表中随机选择一个元素
print(random.choice(['apple', 'pear', 'banana']))
# range(100):生成一个100之内的元组;
# random.sample(list , 2):从list中随机选择2个元素,组成一个新的列表
print(random.sample(range(100), 10))
# 随机生成一个1以内的浮点数
print(random.random())
# 随机生成一个10以内的整数
print(random.randrange(10))
apple
[92, 45, 58, 22, 38, 9, 2, 16, 43, 53]
0.0018608135098209244
8
以上结果为随机值
八、访问互联网
python提供了几个模块用于访问互联网以及处理网络通信协议。其中最常用的两个模块是用于处理从 urls 接收的数据的 urllib.request 模块以及用于发送电子邮件的 smtplib 模块
8.1、urllib.request库的基本使用
urllib.request
模块提供了最基本的构造HTTP请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还带有处理授权验证(authenticaton)、重定向(redirection)、浏览器Cookies以及其他内容;
urllib库是python的内置请求库,常用于网页的请求访问。主要包括以下模块:
官方文档地址:https://docs.python.org/3/library/urllib.request.html
A)、urllib.request.urlopen()方法
urllib.request.urlopen()函数用于实现对目标url的访问,直接使用urllib.request.urlopen()函数访问页面,页面的数据类型为bytes类型,需要使用decode()解码,转化为str类型;
可测试get形式接口:
http://httpbin.org/get
可测试post形式接口:
http://httpbin.org/post
https://www.iqianyue.com/mypost
语法:
urllib.request.urlopen(url , data = None , timeout , cafile=None , capath=None , cadefault=False , context=None)
参数说明:
返回值:
urllib.request.urlopen()函数返回一个HTTPResposne
类型的对象。它主要包含read()
、readinto()
、getheader(name)
、getheaders()
、fileno()
等方法,以及msg
、version
、status
、reason
、debuglevel
、closed
等属性;
urllib.request.urlopen()方法返回对象提供以下方法:
read()、readline()、readlines()、close() :对HTTPResponse类型数据进行操作;
fileno():返回一个整型的文件描述符(file descriptor FD 整型),可用于底层操作系统的 I/O 操作;
info():返回HTTPMessage对象,表示远程服务器返回的头信息;
getcode():返回Http状态码。如果是http请求,200表示请求成功完成;404表示网址未找到;
geturl():返回请求的url;
urllib.request.urlopen()方法默认的“User-agent”是本机Python的版本(User-agent:Python-urllib/3.x),对于服务器而言,较容易识别出这是爬虫;
不含data参数:
import urllib.request
#coding=utf-8
#Python3.x
# 1、urllib.request.urlopen()方法:不含data参数
# 目标URL
url = "http://httpbin.org/get"
# get方式发送请求访问URL网址,返回HTML格式文件
html = urllib.request.urlopen(url)
print("urllib.request.urlopen(url)类型:" , type(urllib.request.urlopen(url)))
print("返回结果的状态码html.status:" , html.status)
print("返回结果的状态码html.getcode():" , html.getcode())
print("响应的头信息html.getheaders():" , html.getheaders())
print("响应的头信息html.getheader('Content-Type'):" , html.getheader('Content-Type'))
# 读取文件内容并解码
str = html.read().decode("utf-8")
file = open("./python.txt" , "w+")
file.write(str)
file.close()
本地生成python.txt文件
urllib.request.urlopen(url)类型:
返回结果的状态码html.status: 200
返回结果的状态码html.getcode(): 200
响应的头信息html.getheaders(): [('Date', 'Fri, 22 May 2020 16:47:47 GMT'), ('Content-Type', 'application/json'), ('Content-Length', '275'), ('Connection', 'close'), ('Server', 'gunicorn/19.9.0'), ('Access-Control-Allow-Origin', '*'), ('Access-Control-Allow-Credentials', 'true')]
响应的头信息html.getheader('Content-Type'): application/json
含有data参数:
#coding=utf-8
#Python3.x
# 2、urllib.request.urlopen()方法:含有data参数
"""
利用有道翻译接口进行在线翻译
"""
import urllib.request
import urllib.parse
import json
# 定义traslate()函数,实现翻译功能
def traslate(words):
#有道翻译目标URL
targetURL = "http://fanyi.youdao.com/translate"
#用户自定义数据,words表示的是用户要翻译的内容。此处data使用的是dict类型
data = {}
data['i'] = words
data['from'] = "AUTO"
data['to'] = 'AUTO'
data["smartresult"] = "dict"
data["client"] = "fanyideskweb"
data["salt"] = "15901593694637"
data["sign"] = "38f10d4893317ff333aeecc2bca58a8d"
data["ts"] = "1590159369463"
data["bv"] = "1de9313c44872e4c200c577f99d4c09e"
data["doctype"] = "json"
data["version"] = "2.1"
data["keyfrom"] = "fanyi.web"
data["action"] = "FY_BY_CLICKBUTTION"
# urllib.parse.urlencode()将字典结构的参数data序列化为url编码后的字符串,utf-8编码(常用来构造get请求和post请求的参数)
data = urllib.parse.urlencode(data).encode('utf-8')
# post方式发送用户请求,返回 HTML 格式文件
html = urllib.request.urlopen(targetURL, data)
# 读取并解码内容,结果为 JSON 对象
rst_json = html.read().decode("utf-8")
# 将 JSON 对象转换为 Python 字典
rst_dict = json.loads(rst_json)
# ['translateResult'][0][0]['tgt']为翻译结果
# ['translateResult'][0][0]['src']为输入文字
return rst_dict['translateResult'][0][0]['tgt']
if __name__ == "__main__":
print("输入字母q表示退出")
while True:
words = input("请输入要查询的单词或句子:\n")
if words == 'q':
break
result = traslate(words)
print(words + "的翻译结果是:%s" % result)
break
输入字母q表示退出
请输入要查询的单词或句子:
中国
中国的翻译结果是:China
import urllib.request
import urllib.parse
import string
def get_method_params():
url = "http://www.baidu.com/s?"
param = {
#多个参数,利用字典的形式完成
"wd":"中文",
"key":"zhang",
"value": "san"
}
# 将字典转换成参数形式的字符串
result = str(param)
# 这个方法可以将URL转化为计算机可以识别的状态,且多个参数之间补充&,补充=
strpa = urllib.parse.urlencode(param)
#拼接参数
finurl = url + strpa
# 将带有中文的url转化为可以识别的状态
# 这里后面的参数是一个固定写法,用来保证原有的URL的状态
encode_url = urllib.parse.quote(finurl, safe=string.printable)
#发送网络请求
res = urllib.request.urlopen(encode_url)
# 获得爬取数据,根据网页编码方式进行解码
data = res.read().decode("utf-8")
with open("./baidu.txt" , "w+") as file:
file.write(data)
print(data)
get_method_params()
timeout
参数
timeout
参数用于设置超时时间,单位为秒,即如果请求超出了设置的时间还没有得到响应,就会抛出异常;如果不指定该参数,就会使用全局默认时间;它支持HTTP、HTTPS、FTP请求;可以通过设置这个超时时间来控制一个网页,如果长时间未响应,就跳过它的抓取。
# 3、timeout参数
import urllib.request , urllib.error , socket
url = "http://httpbin.org/get"
try:
# 访问URL,设置超时时间
response = urllib.request.urlopen(url , timeout = 0.2)
except urllib.error.URLError as e:
# 判断URLError原因,如果是原因是timeout,则打印提示
if isinstance(e.reason , socket.timeout):
print("访问网站超时啦~~~")
else:
# 读取并解码输出内容
str = response.read().decode("utf-8")
file = open("./timeout.txt" , "w+")
file.write(str)
file.close()
访问网站超时啦~~~
B)、Request
urlopen()
方法可以实现最基本请求的发起,但这几个简单的参数并不足以构建一个完整的请求。如果请求中需要加入Headers等信息时,就需要利用更强大的Request
类来构建;
语法:
urllib.request.Request(url, data , headers={}, origin_req_host , unverifiable , method)
参数:
参数 | 说明 |
URL | 请求URL,必传参数 |
data | data必须是bytes(字节流)类型;如果是字典型,使用urllib.parse模块里的urlencode()编码,即:urllib.parse.urlencode(dict).encode("utf-8") |
headers | headers是一个字典类型,是请求头。可以在构造请求时通过headers参数直接构造,也可以通过调用请求实例的add_header()方法添加。可以通过请求头伪装浏览器,默认User-Agent是Python-urllib。要伪装成火狐浏览器,可以设置User-Agent为Mozilla/5.0 (x11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11 |
origin_req_host | 指定请求方的host名称或者ip地址 |
unverifiable | 设置网页是否需要验证,默认是False,这个参数一般不需要设置 |
method | method是一个字符串,用来指定请求使用的方法,比如GET、POST或PUT |
返回值:
# 4、urllib.request.Request ()方法加上header信息
import urllib.request , urllib.parse
# 定义URL
URL = "http://httpbin.org/post"
# 定义data数据
dict = {"name":"Gavin"}
# data转化为bytes(字节流)类型
data = urllib.parse.urlencode(dict).encode("utf-8")
# 定义header,字典型
headers = {
"Host":"httpbin.org",
"Accept-Encoding":"gzip, deflate",
"Accept-Language":"zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Upgrade-Insecure-Requests":"1",
"User-Agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0",
"X-Amzn-Trace-Id":"Root=1-5ec92abf-e4f2e860fb6f15c0a0048060"
}
# urllib.request.Request() 返回 urllib.request.Request类
req = urllib.request.Request(url = URL, data = data, headers = headers, method = 'POST' )
# urllib.request.urlopen()发生请求,返回 HTTPResposne 类型
HTTPResposne = urllib.request.urlopen(req)
# 解码 HTTPResposne,转化为字符串str
str = HTTPResposne.read().decode("utf-8")
# 输出请求返回值
print("请求返回值:\n" , str)
# 打开一个文件,用来接收URL访问的返回结果
file = open("./Request_header.txt" , "w+")
# 字符串写入文件
file.write(str)
file.close()
请求返回值:
{
"args": {},
"data": "",
"files": {},
"form": {
"name": "Gavin"
},
"headers": {
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
"Content-Length": "10",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0",
"X-Amzn-Trace-Id": "Self=1-5ec931f9-45090d5e56953f6ee67620ba;Root=1-5ec92abf-e4f2e860fb6f15c0a0048060"
},
"json": null,
"origin": "120.204.140.60",
"url": "http://httpbin.org/post"
}
headers
也可以用add_header()
方法来添加:
req = urllib.request.Request(url = URL, data = data, method = 'POST' )
req.add_headers("User-Agent":"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:76.0) Gecko/20100101 Firefox/76.0")
import urllib.request
def load_baidu():
url = "http://www.baidu.com/s?"
#创建一个请求对象,目的是加出请求头信息,防止反扒
request = urllib.request.Request(url)
#动态的添加请求头信息
request.add_header("User-Agent",
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36')
#发送网络请求
reponse = urllib.request.urlopen(request)#请求结果返回
strdata = reponse.read().decode("utf-8")#返回结果的读取和解码
print(strdata)
#响应头
print(reponse.headers)#查看响应头 一般没有大用处
#请求头!!!重要!!
# 方法1:获取请求头的全部信息
requestheader = request.headers
print(requestheader)#这是手动在代码段里面写出来的
# 方法2:获取请求头信息,注意他是获取请求头中的一部分信息,需要传参
result = request.get_header("User-agent")
print(result)
#获取完整URL的方式
finurl = request.get_full_url()
print(finurl)
with open("./load_baidu.txt","w",encoding="utf-8") as f:
f.write(strdata)
load_baidu()
C)、Handler处理器和自定义Opener
1、Handler处理器
urllib.request
库中的Handler类提供了验证处理、Cookies处理、代理设置等操作;urllib.request库中的BaseHandler类是所有其他Handler的父类,常用的Handler子类包括:
2、自定义Opener
opener 是 request.OpenerDirector 的实例,之前使用的urlopen()是一个特殊的opener(即模块自动构建),但基本的urlopen()方法不支持代理、cookie等HTTP/HTTPS高级功能,如要支持这些功能需使用自定义的opener对象,调用open()方法发送请求
3、Handler处理器构建自定义opener步骤:
# Handler处理器构建自定义opener
import urllib.request
url = "http://httpbin.org/get"
# 5、Handler处理器构建自定义opener步骤:
# 第一步:使用HTTPHandler处理器构建一个HttpHandler处理器对象,支持处理HTTP请求
HttpHandler = urllib.request.HTTPHandler()
# 第二步:调用urllib.request.build_opener()方法,创建支持处理HTTP请求的opener对象
http_opener = urllib.request.build_opener(HttpHandler)
# 第三步:调用自定义opener对象的open()方法,发送request请求
response = http_opener.open(url)
# 解码返回值
str = response.read().decode("utf-8")
print("http://httpbin.org/get返回结果为:\n" , str)
http://httpbin.org/get返回结果为:
{
"args": {},
"headers": {
"Accept-Encoding": "identity",
"Host": "httpbin.org",
"User-Agent": "Python-urllib/3.6",
"X-Amzn-Trace-Id": "Root=1-5ec949e6-24091b908e8f45702507c630"
},
"origin": "120.204.140.60",
"url": "http://httpbin.org/get"
}
进程完成,退出码 0
4、ProxyHandler处理器(利用handler实现IP代理)
步骤:
1、代理IP设置,proxy,字典型;当有多个代理IP时,可以设置为列表,子元素为字典
2、通过request.ProxyHandler(proxy)设置代理Handler,返回httpproxy_handler
3、通过request.build_opener(httpproxy_handler)构建自定义opener
# ProxyHandler处理器(利用handler实现IP代理)
from urllib import request
import random
URL = "http://httpbin.org/get"
# 定义headers头文件
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
}
# 设置IP代理,当代理较多时,可设置为一个列表,子元素为字典
proxy_list = [
{"http": "61.135.155.82:443"},
{"http": "118.78.196.148:8118"},
{"http": "58.249.55.222:9797"},
{"http": "123.163.24.113:3128"},
{"http":"115.29.170.58:8118"}
]
# 随机选择一个代理
proxy = random.choice(proxy_list)
# 打印选择的代理
print("选择了如下代理:" , proxy)
# 构建两个代理Handler,一个有代理IP,一个没有代理IP
httpproxy_handler = request.ProxyHandler(proxy)
nullproxy_handler = request.ProxyHandler({})
#定义一个代理开关
proxySwitch = True
# 通过 request.build_opener()方法将代理器Handler对象,创建自定义opener对象
# 根据代理开关是否打开,使用不同的代理模式
if proxySwitch:
opener = request.build_opener(httpproxy_handler)
else:
opener = request.build_opener(nullproxy_handler)
# 返回 对象
req = request.Request(URL , headers = headers )
# 1. 如果这样写,只有使用opener.open()方法发送请求才使用自定义的代理,而urlopen()则不使用自定义代理
response = opener.open(req)
# 2. 如果这样写,就是将opener应用到全局,之后所有的,不管是opener.open()还是urlopen() 发送请求,都将使用自定义代理
# request.install_opener(opener)
# response = request.urlopen(req)
# 接收并解码返回内容
str = response.read().decode('utf-8')
with open("./ProxyHandler设置IP代理.txt" , "w+") as file:
file.write(str)
5、ProxyBasicAuthHandler处理器(代理授权验证)
步骤:
1、设置授权的账号、密码(需将字典型转化为byte型数据,才能输入到网页)
2、设置代理IP
3、urllib.request.HTTPPasswordMgrWithDefaultRealm()构建密码管理对象passwdmgr,用来保存需要处理的用户名和密码
4、passwdmgr.add_password(None, proxyserver, user, passwd)添加账户信息
5、request.ProxyBasicAuthHandler(passwdmgr)构建代理用户名/密码验证的ProxyBasicAuthHandler处理器对象proxyauth_handler
6、创建自定义opener对象
7、request.Request(url)构造Request 请求
8、opener().openurl()发生请求
from urllib import request
from urllib.error import URLError
import urllib.parse
# url地址
url = "https://www.iqianyue.com/mypost"
# 第一步:私密代理授权的账户和密码
data = {"name":"username" , "pass":"password"}
# 字典型转化为byte型,必须将账户和密码转化为byte型才能输入到网页
bytedata = urllib.parse.urlencode(data).encode("utf-8")
# 第二步:私密代理 IP
proxyserver = {"http":"61.158.163.130:16816"}
# 第三步:构建一个密码管理对象,用来保存需要处理的用户名和密码
passwdmgr = request.HTTPPasswordMgrWithDefaultRealm()
# 第四步:添加账户信息,第一个参数realm是与远程服务器相关的域信息,一般为 None,后面三个参数分别是 代理服务器、用户名、密码
passwdmgr.add_password(None, proxyserver, data["name"] , data["pass"])
# 第五步:构建一个代理基础用户名/密码验证的ProxyBasicAuthHandler处理器对象,参数是创建的密码管理对象
# 注意,这里不再使用普通ProxyHandler类
proxyauth_handler = request.ProxyBasicAuthHandler(passwdmgr)
# 第六步:通过 build_opener()方法使用这些代理Handler对象,创建自定义opener对象,参数包括构建的 proxy_handler 和 proxyauth_handler
opener = request.build_opener(proxyauth_handler)
# 第七步:构造Request 请求
req = request.Request(url , data = bytedata , method = 'POST')
try:
# 第八步:使用自定义opener发送请求
response = opener.open(req)
# 第九步:打印响应内容
str = response.read().decode("utf-8")
# 创建文件,用于保存结果
with open('./ProxyBasicAuthHandler处理器实现代理授权验证.html', "w+") as file:
file.write(str)
except URLError as e:
print("URLError原因为:" , e.reason)
6、HTTPBasicAuthHandler处理器(Web客户端授权验证)
步骤:
1、设置授权的账号、密码(需将字典型转化为byte型数据,才能输入到网页)
2、urllib.request.HTTPPasswordMgrWithDefaultRealm()构建密码管理对象passwdmgr,用来保存需要处理的用户名和密码
3、passwdmgr.add_password(None, proxyserver, user, passwd)添加账户信息
4、request.HTTPBasicAuthHandler(passwdmgr)构建代理用户名/密码验证的HTTPBasicAuthHandler处理器对象proxyauth_handler
5、创建自定义opener对象
6、request.Request(url)构造Request 请求
7、opener().openurl()发生请求
from urllib import request
from urllib.error import URLError
import urllib.parse
#字典型
data= {"user":"username" , "passwd":"password"}
bytedata = urllib.parse.urlencode(data).encode("utf-8")
# Web服务器 IP
webserver = "https://www.baidu.com"
# 第一步:构建一个密码管理对象,用来保存需要处理的用户名和密码
passwdmgr = request.HTTPPasswordMgrWithDefaultRealm()
# 第二步:添加账户信息,第一个参数realm是与远程服务器相关的域信息,一般为None,后面三个参数分别是 Web服务器、用户名、密码
passwdmgr.add_password(None, webserver, data['user'], data['passwd'])
# 第三步:构建一个HTTP基础用户名/密码验证的HTTPBasicAuthHandler处理器对象,参数是创建的密码管理对象
httpauth_handler = request.HTTPBasicAuthHandler(passwdmgr)
# 第四步:通过 build_opener()方法使用这些代理Handler对象,创建自定义opener对象,参数包括构建的 proxy_handler
opener = request.build_opener(httpauth_handler)
# 第五步:可以选择通过install_opener()方法定义opener为全局opener
request.install_opener(opener)
# 第六步:构建 Request对象
req = request.Request(webserver , data = bytedata)
# 第七步:定义opener为全局opener后,可直接使用urlopen()发送请求
response = request.urlopen(req)
try:
# 第八步:使用自定义opener发送请求
response = opener.open(req)
# 第九步:打印响应内容
str = response.read().decode("utf-8")
# 创建文件,用于保存结果
with open('./HTTPBasicAuthHandler处理器实现Web客户端授权验证.html' , "w+") as file:
file.write(str)
except URLError as e:
print("URLError原因为:" , e.reason)
7、http.cookiejar和HTTPCookieProcessor处理器处理cookie
Python3处理Cookie时,一般通过http.cookiejar模块和 urllib.request模块的HTTPCookieProcessor处理器类一起使用;
http.cookiejar模块主要有CookieJar、FileCookieJar、MozillaCookieJar、LWPCookieJar方法
一般情况下,使用CookieJar(),如需要和本地文件交互,则使用 MozillaCookjar() 或 LWPCookieJar()
7.1、获取Cookie,并保存到CookieJar()对象中
# 7.1、获取Cookie,并保存到CookieJar()对象中
from urllib import request
import http.cookiejar as cookielib # 使用cookielib代替http.cookiejar
# 构建一个CookieJar对象实例保存cookie
cookiejar = cookielib.CookieJar()
# 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象
handler=request.HTTPCookieProcessor(cookiejar)
# 通过 build_opener() 来构建opener
opener = request.build_opener(handler)
# 4. 以get方法访问页面,访问之后会自动保存cookie到cookiejar中
opener.open("http://www.baidu.com")
# 可以按标准格式将保存的Cookie打印出来
cookieStr = ""
for item in cookiejar:
cookieStr = cookieStr + item.name + "=" + item.value + ";" + "\n"
# 舍去最后一位的分号
print(cookieStr[:-1])
BAIDUID=3F95D98817DBF10BEA0342355DF33921:FG=1;
BIDUPSID=3F95D98817DBF10B31BB035074CFF0B8;
H_PS_PSSID=31727_1458_31325_21125_31589_31606_31270_31661_31463_30824;
PSTM=1590335743;
BDSVRTM=0;
BD_HOME=1;
7.2、访问网站获得cookie,并把获得的cookie保存在cookie文件中
# 7.2、访问网站获得cookie,并把获得的cookie保存在cookie文件中
from urllib import request
import http.cookiejar as cookielib
# 保存cookie的本地磁盘文件名
filename = './cookie.txt'
# 声明一个MozillaCookieJar(有save功能)对象实例来保存cookie,之后写入文件filename
cookiejar = cookielib.MozillaCookieJar(filename)
# 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象
handler = request.HTTPCookieProcessor(cookiejar)
# 通过 build_opener() 来构建opener
opener = request.build_opener(handler)
# 创建一个请求
response = opener.open("http://www.baidu.com")
# 保存cookie到本地文件
cookiejar.save()
7.3、从文件中获取cookies,作为请求的一部分
# 7.3、从文件中获取cookies,作为请求的一部分
from urllib import request
import http.cookiejar as cookielib
# 创建MozillaCookieJar(有load功能)实例对象,并从文件中读取cookie内容到变量
cookiejar = cookielib.MozillaCookieJar().load('./cookie.txt')
# 使用HTTPCookieProcessor()来创建cookie处理器对象,参数为CookieJar()对象
handler = request.HTTPCookieProcessor(cookiejar)
# 通过 build_opener() 来构建opener
opener = request.build_opener(handler)
response = opener.open("http://www.baidu.com")
with open("./cookies_baidu.txt" , "w+") as file:
file.write(response.read().decode("utf-8"))
7.4、使用Handler处理器获取网站cookies并发送请求(需将字典型转化为byte型数据,才能输入到网页)
# 使用处理器Handler携带网站cookies并发送请求
import urllib.request
import ssl
# 全局除去SSL的警告
ssl._create_default_https_context = ssl._create_unverified_context
#用来管理cookie
from http import cookiejar
#用来参数转码解析
from urllib import parse
# 1.1登陆之前设置用户账号密码(登陆界面)
# 1.2发送请求登陆用(账号密码)(查看登陆所需要的参数)
url = "https://www.wlyxmusic.net/"
header = {"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36",
"cookie":"BAIDUID=6EB65BD9F8F5377811634CAB0FA826EB:FG=1; "
"BIDUPSID=6EB65BD9F8F5377811634CAB0FA826EB; PSTM=1550312207; delPer=0; "
"H_PS_PSSID=1420_25810_21110_28607_28584_28558_28604_28626_28605; "
"BDUSS=lNNEE1NjdqcXNNZ1BTOFlTWmszSGdlQ0kwZUpLaWRXNkZSaDZESlZUaUpIS2RjQVFBQUFBJCQAAAAAAAAAAAEAAACUUKYhz9LBrMTjztIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAImPf1yJj39cbH; "
"PHPSESSID=b9073fqe459o63kh8bsn9gr1v1; "
"Hm_lvt_4010fd5075fcfe46a16ec4cb65e02f04=1551863694;"
"Hm_lpvt_4010fd5075fcfe46a16ec4cb65e02f04=1551863694"}#这个cookie是登陆界面的cookie
# 构造请求参数(post请求参数必须是字典形式)
login_datas = {
'username':"*******",
"password":"***********",
"formhash":"*****",
"referer":"https://www.wlyxmusic.net/"}
# post上传参数必须是二进制类型,将参数转码,会返回一个二进制数据
log_bytes_datas = parse.urlencode(login_datas).encode("utf-8")
# 构造请求头对象,发送请求
request = urllib.request.Request(url,headers=header,data=log_bytes_datas)
cook= cookiejar.CookieJar() # 保存cookie用
# 创建可以添加cookie的处理器(handler),原因还是urlopen没有保存cookie的参数
cookhandler = urllib.request.HTTPCookieProcessor(cook)
# 构建自定义opener
opener = urllib.request.build_opener(cookhandler)
# opener.open()发送请求
#既包含请求信息,又包含参数信息,还有cookie信息
#如果发送请求成功自动保存cookie,这个cookie是个人中心的cookie
reponse = opener.open(request)
#2 访问个人中心页面(opener对象里面有cookie)
# 2.1个人中心url
center_url = "https://www.wlyxmusic.net/space-uid-19759.html"
#构造请求对象
center_request = urllib.request.Request(center_url,headers=header)
#发送网络请求(拿刚刚创建好的opener中的cookie里面的信息去发送)
response2 = opener.open(center_request)
data = response2.read().decode("utf-8")
with open("06.html","w+",encoding="utf-8") as file:
file.write(data)
#到此就可以通过用户账号密码进入个人中心
7.5、通过cookie爬取需要用户名密码验证的网站(需将字典型转化为byte型数据,才能输入到网页)
# 7.5、通过cookie爬取需要用户名密码验证的网站
from urllib import request
import urllib.parse
import http.cookiejar as cookielib
# 通过CookieJar()类构建一个cookieJar()对象,用来保存cookie的值
cookie = cookielib.CookieJar()
# 通过HTTPCookieProcessor()处理器类构建一个处理器对象,用来处理cookie
# 参数就是构建的CookieJar()对象
cookie_handler = request.HTTPCookieProcessor(cookie)
# 自定义全局opener
opener = request.build_opener(cookie_handler)
# 自定义opener的addheadders参数,可以赋值HTTP报头参数
opener.addheaders = [("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")]
# 需要登录的账户和密码
data = {"email":"[email protected]", "password":"xxxxxx"}
# 通过urlencode()转码
postdata = urllib.parse.urlencode(data).encode("utf-8")
# 构建Request请求对象,包含需要发送的用户名和密码
request = request.Request("http://www.renren.com/PLogin.do", data = postdata)
# 通过opener发送这个请求,并获取登录后的Cookie值,
opener.open(request)
# opener包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
response = opener.open("http://www.renren.com/410043129/profile")
with open("./renren.txt" , "w+") as file:
file.write(response.read().decode("utf-8"))
8.2、urllib.error异常处理模块
urllib.
error
模块能处理urllib.request
模块产生的异常。如果request
模块出现异常,request
模块便会抛出error
模块中定义的异常
A)、URLError
URLError类来自urllib.error模块,继承自OSError类,是error异常模块的基类,由request模块产生的异常都可以通过这个类来捕获处理;URLError类有一个reason属性,用来返回错误的原因
# urllib.error模块能处理urllib.request模块产生的异常。
# 如果request模块出现异常,request模块便会抛出error模块中定义的异常
import urllib.error , urllib.request
URL= "http://gavin_bai.com/index.html"
try:
print(urllib.request.urlopen(URL))
except urllib.error.URLError as e:
print("异常原因:" , e.reason)
异常原因: [Errno -2] Name or service not known
B)、HTTPError
HTTPError类
是URLError
的子类,专门用来处理HTTP请求错误,有如下3个属性:
code
:返回HTTP状态码,比如404表示网页不存在,500表示服务器内部错误等;reason
:同父类一样,用于返回错误的原因;headers
:返回请求头;# HTTPError类是URLError的子类,专门用来处理HTTP请求错误
from urllib import request, error
try:
response = request.urlopen('http://www.zx.com/index.htm')
# URLError是HTTPError的父类,可以先捕获子类的错误,再捕获父类错误
except error.HTTPError as he:
print("he.reason:" , he.reason)
print("he.code:", he.code)
print("he.headers:" , he.headers)
except error.URLError as ue:
print("ue.reason:" , ue.reason)
else:
print('Request Successfully')
he.reason: Not Found
he.code: 404
he.headers: Date: Fri, 29 May 2020 14:24:17 GMT
Server: Apache/2.4.7 (Ubuntu)
Content-Length: 282
Connection: close
Content-Type: text/html; charset=iso-8859-1
reason
属性返回值不一定是字符串,也可能是一个对象
# reason属性返回值不一定是字符串,也可能是一个对象
from urllib import request , error
import socket
url = "https://www.baidu.com"
try:
response = request.urlopen(url , timeout=0.001)
except error.URLError as UE:
print("URLError.reason类型:" , type(UE.reason))
if isinstance(UE.reason , socket.timeout):
print("socket timeout")
URLError.reason类型:
socket timeout
8.3、urllib.parse链接解析模块
urllib.parse
模块定义了处理URL的标准接口,可以实现URL各部分的抽取、合并以及链接转换;
支持如下协议的URL处理:file、ftp、gopher、hdl、http、https、imap、mailto、 mms、news、nntp、prospero、rsync、rtsp、rtspu、sftp、 sip、sips、snews、svn、svn+ssh、telnet和wais;
8.3.1、urlparse()方法
urllib.parse.urlparse()方法实现URL的识别和分段
# 1、urlparse()方法
# urllib.parse.urlparse()方法实现URL的识别和分段
from urllib import parse
url = "https://www.baidu.com/index.html;user=10086?id=007#comment"
response = parse.urlparse(url)
print(type(response))
print(response)
ParseResult(scheme='https', netloc='www.baidu.com', path='/index.html', params='user=10086', query='id=007', fragment='comment')
urlparse()返回值解析:
urlparse()返回结果是一个ParseResult
类型的对象,返回结果是一个元组,包含6部分,分别是scheme
、netloc
、path
、params
、query
和fragment
;
scheme:协议,“://
”
之前的内容,即:httpsnetloc:域名,“://
”之后到第一个“/”之间的内容,即:
www.baidu.compath:路径,第一个“/”之后到分号“;”之间的内容,即:
/index.html分号“;”之后到问号“?”之间的内容,即:
user=10086query:查询,问号“?”和井号“#”之间的内容,即:
id=007fragment:信息片段
,井号“#”之后的内容,即:
commenturllib.parse.urlparse()的API格式为:
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
参数:
fragment参数
。如果被设置为False
,fragment
部分会被忽略,它会被解析为path
、parameters
或者query
的一部分,而fragment
部分为空;# 2、urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
urlstring = "https://www.baidu.com/index.html;user=10086?id=007#comment"
response = parse.urlparse(urlstring , scheme="http" , allow_fragments=False)
print(response)
print("response.scheme:" , response.scheme)
print("response.netloc:" , response.netloc)
ParseResult(scheme='https', netloc='www.baidu.com', path='/index.html', params='user=10086', query='id=007#comment', fragment='')
response.scheme: https
response.netloc: www.baidu.com
8.3.2、urlunparse
()方法
urllib.parse.urlunparse
()方法实现URL的构造,参数是一个可迭代对象,但是可迭代对象长度必须是6,否则会抛出参数数量不足或者过多的问题,参数包括:scheme
、netloc
、path
、params
、query、
fragment
# 8.3.2、urlunparse()方法
# urllib.parse.urlunparse()方法实现URL的构造,参数是一个可迭代对象,但是可迭代对象长度必须是6,否则会抛出参数数量不足或者过多的问题,
# 参数包括:scheme、netloc、path、params、query、fragment
from urllib import parse
list = ['https', 'www.baidu.com', '/index.html', 'user=10086', 'id=007', 'comment']
# urlunparse()实现URL拼接
url = parse.urlunparse(list)
print("url:" , url)
url: https://www.baidu.com/index.html;user=10086?id=007#comment
8.3.3、urlsplit()方法
urllib.parse.urlsplit()方法也可以实现URL的识别和分段,与urlparse()方法不同的是urlsplit()方法不解析params部分,因此仅返回5部分
# 8.3.3、urlsplit()方法
# urllib.parse.urlsplit()方法也可以实现URL的识别和分段,与urlparse()方法不同的是urlsplit()方法不解析params部分,因此仅返回5部分
from urllib import parse
url = "https://www.baidu.com/index.html;user=10086?id=007#comment"
result = parse.urlsplit(url)
print("result返回类型:" , type(result))
print(result)
print("result.scheme:" , result.scheme)
print("result.netloc:" , result.netloc)
result返回类型:
SplitResult(scheme='https', netloc='www.baidu.com', path='/index.html;user=10086', query='id=007', fragment='comment')
result.scheme: https
result.netloc: www.baidu.com
8.3.4、urlunsplit()方法
urlunsplit()方法与urlunparse()
方法类似,也是将链接各个部分组合成完整链接,传入的参数也是一个可迭代对象,唯一的区别是长度必须为5,不传入params
参数
# 8.3.4、urlunsplit()方法
# urlunsplit()方法与urlunparse()方法类似,也是将链接各个部分组合成完整链接,传入的参数也是一个可迭代对象,唯一的区别是长度必须为5,不传入params参数
from urllib import parse
list = ['https', 'www.baidu.com', '/index.html;user=10086' , 'id=007', 'comment']
# urlunsplit()实现URL拼接
url = parse.urlunsplit(list)
print("url:" , url)
url: https://www.baidu.com/index.html;user=10086?id=007#comment
8.3.5、urljoin()
方法
urljoin()
方法也可实现链接的解析、拼合与生成,可通过提供一个base_url
(基础链接)作为第一个参数,将新的链接作为第二个参数,urljoin()方法会分析base_url
的scheme
、netloc
和path
这3个参数并对新链接缺失的部分进行补充,最后返回结果;
如果这3个参数在新的链接里不存在,就予以补充;如果新的链接存在这三个参数,优先使用新的链接的部分,即base_url
中的params
、query
和fragment
是不起作用的;
# 8.3.5、urljoin()方法
# urljoin()方法也可实现链接的解析、拼合与生成,可通过提供一个base_url(基础链接)作为第一个参数,将新的链接作为第二个参数,urljoin()方法会分析base_url的scheme、netloc和path这3个参数并对新链接缺失的部分进行补充,最后返回结果;
# 如果这3个参数在新的链接里不存在,就予以补充;如果新的链接存在这三个参数,优先使用新的链接的部分,即base_url中的params、query和fragment是不起作用的;
from urllib import parse
print(parse.urljoin('http://www.baidu.com' , 'FAQ.html'))
print(parse.urljoin('http://www.baidu.com' , 'https://zx.com/FAQ.html'))
print(parse.urljoin('http://www.baidu.com/about.html' , 'https://zx.com/FAQ.html'))
print(parse.urljoin('http://www.baidu.com/about.html' , 'https://zx.com/FAQ.html?question=2'))
print(parse.urljoin('http://www.baidu.com?wd=abc' , 'https://zx.com/index.php'))
print(parse.urljoin('http://www.baidu.com' , '?category=2#comment'))
print(parse.urljoin('www.baidu.com' , '?category=2#comment'))
print(parse.urljoin('www.baidu.com#comment' , '?category=2'))
http://www.baidu.com/FAQ.html
https://zx.com/FAQ.html
https://zx.com/FAQ.html
https://zx.com/FAQ.html?question=2
https://zx.com/index.php
http://www.baidu.com?category=2#comment
www.baidu.com?category=2#comment
www.baidu.com?category=2
8.3.6、urlencode()方法
urlencode()方法
常用于GET请求参数的构造,将参数序列化为GET请求参数;
urlencode()方法常用于如下场景:部分场景下为了更方便地构造参数,提前将参数用字典来表示,要转化为URL的参数时,只需要调用urlencode()方法即可;
# 8.3.6、urlencode()方法
# urlencode()方法常用于GET请求参数的构造,将参数序列化为GET请求参数
from urllib import parse
# 定义基础URL
basic_url = "www.zx.com?"
# 定义参数
params = {
"name":"aaa",
"password":"bbb"
}
# urlencode()实现URL拼接
url = basic_url + parse.urlencode(params)
print("url:" , url)
url: www.zx.com?name=aaa&password=bbb
8.3.7、parse_qs()
方法
反序列化,parse_qs()
方法可将GET请求参数反序列化为字典
# 8.3.7、parse_qs()方法
# 反序列化,parse_qs()方法可将GET请求参数反序列化为字典
from urllib import parse
url = "https://www.baidu.com/index.html;user=10086?id=007#comment"
# parse_qs()方法将URL中的参数反序列化为字典类型
dict = parse.parse_qs(url)
print("dict:" , dict)
dict: {'user': ['10086?id=007#comment']}
8.3.8、parse_qsl()方法
parse_qsl()
方法用于将URL参数转化为元组组成的列表,返回结果是一个列表,列表中的每一个元素都是一个元组,元组的第一个内容是参数名,第二个内容是参数值;
# 8.3.8、parse_qsl()方法
# parse_qsl()方法用于将URL参数转化为元组组成的列表,
# 返回结果是一个列表,列表中的每一个元素都是一个元组,元组的第一个内容是参数名,第二个内容是参数值;
from urllib import parse
url = "https://www.baidu.com/index.html;user=10086?id=007#comment"
# parse_qsl()方法将URL中的参数反序列化为列表类型
listA = parse.parse_qsl(url)
print("listA:" , listA)
listA: [('user', '10086?id=007#comment')]
8.3.9、quote()方法
quote()方法
可将内容转化为URL编码的格式;
URL中带有中文参数时,可能会导致乱码的问题,用quote()方法可将中文字符转化为URL编码;
# 8.3.9、quote()方法
# quote()方法可将内容转化为URL编码的格式;
# URL中带有中文参数时,可能会导致乱码的问题,用quote()方法可将中文字符转化为URL编码;
from urllib import parse
basic_url = 'https://www.baidu.com/s?wd='
keyword = "科比"
# parse.quote()将中文转化为URL编码,并实现拼接
URL = basic_url + parse.quote(keyword)
print("URL:" , URL)
URL: https://www.baidu.com/s?wd=%E7%A7%91%E6%AF%94
8.3.10、unquote()方法
unquote()方法与quote()方法相反,实现URL解码功能
# 8.3.9、unquote()方法
# unquote()方法实现URL解码功能;
from urllib import parse
basic_url = 'https://www.baidu.com/s?wd='
keyword = "科比"
# parse.quote()将中文转化为URL编码,并实现拼接
URL = basic_url + parse.quote(keyword)
print("URL:" , URL)
# unquote()方法实现URL解码功能
url = parse.unquote(URL)
print("url:" , url)
URL: https://www.baidu.com/s?wd=%E7%A7%91%E6%AF%94
url: https://www.baidu.com/s?wd=科比
8.2、smtplib库发送邮件
步骤:
1、连接邮箱服务器,登录邮箱
邮箱服务器地址:smtp.xxx.com
端口号:465/25
connect = smtplib.SMTP_SSL(server , port)
2、登录邮箱
connect.login(name , pwd)
3、编写邮件内容
3.1)、创建邮件对象
msg = MIMEMultipart()
3.2)、设置邮件主题,添加邮件主题至邮件对象
subject = Header("smtplib库发送邮件" , "utf-8").encode()
msg["Subject"] = subject
3.3)、设置发件人
msg["From"] = "[email protected]"
3.4)、设置收件人
msg["To"] = "[email protected] ; [email protected]"
3.5)、设置邮件正文,添加邮件正文至邮件对象
普通文本:MIMEText(文本内容,文本类型,编码方式)
文本类型:plain(普通文本)、html(超链接)、base64(二进制文件,附件)
text = MIMEText("这个一封邮件" , "plain" , "utf-8")
msg.attach(text)
4、发送邮件
连接对象.sendemail(发件人,收件人,字符串类型的邮件对象)
connect.sendmail(sender , receivers , msg.as_string())
5、退出邮件连接
connect.quit()
# 一、smtplib库发送纯文本邮件
import smtplib
# 创建邮件对象(真正被发生的信息)
from email.mime.multipart import MIMEMultipart
# 邮件主题
from email.header import Header
# 构建邮件文本内容
from email.mime.text import MIMEText
# 第一步、连接邮箱服务器,登录邮箱
# 1)连接邮箱服务器:smtplib.SMTP_SSL(邮箱连接地址 , 端口号)
# 2)smtplib.SMTP_SSL()方法可避免邮箱被识别为垃圾邮件
# 3)邮箱服务器地址一般形式为:smtp.xxx.com,xxx为具体邮箱类型名,如139、126、qq等
# 4)端口号:465/25
QQserver = "smtp.qq.com" # QQ邮箱服务器地址
port = 465 # QQ邮箱服务端口号
# 发件人
sender = "[email protected]"
# 收件人
receivers = "[email protected] , [email protected]"
# 5)链接QQ邮箱服务器,返回链接对象
connect = smtplib.SMTP_SSL(QQserver , port)
# 第二步、登录邮箱
# 链接对象.login(账号 , 密码)
# 密码:一般邮箱直接写邮箱密码,QQ邮箱写授权码
name = "[email protected]"
pwd = "xxxxxx"
# 登录邮箱
connect.login(name , pwd)
# 第三步、准备邮件数据
# 1)、创建邮件对象
msg = MIMEMultipart()
# 2)、设置邮件主题,二进制格式
subject = Header("smtplib库发送邮件" , "utf-8").encode()
# 3)、邮件主题添加至邮件对象
msg["Subject"] = subject
# 4)、设置邮件发送者
msg["From"] = sender
# 5)、设置邮件接收者
msg["To"] = receivers
# 6)、设置邮件正文,添加邮件正文至邮件对象
# 普通文本:MIMEText(文本内容,文本类型,编码方式)
# 文本类型:plain(普通文本)、html(超链接)、base64(二进制文件,附件)
text = MIMEText("这个一封邮件" , "plain" , "utf-8")
msg.attach(text)
# 第四步、发送邮件
# 连接对象.sendemail(发件人,收件人,字符串类型的邮件对象)
connect.sendmail(sender , receivers.split(',') , msg.as_string())
# 第五步、退出邮件
connect.quit()
# 二、smtplib库发送HTML格式邮件
import smtplib
# 创建邮件对象
from email.mime.multipart import MIMEMultipart
# 邮件主题
from email.header import Header
# 创建邮件正文内容
from email.mime.text import MIMEText
# 第一步、连接邮箱服务器,登录邮箱
# 1)连接邮箱服务器:smtplib.SMTP_SSL(邮箱连接地址 , 端口号)
# 2)端口号:465/25
QQserver = "smtp.qq.com" # QQ邮箱服务器地址
port = 465 # QQ邮箱服务端口号
# 3)发件人
sender = "[email protected]"
# 4)收件人
receivers = "[email protected] , [email protected]"
# 5)链接QQ邮箱服务器
connect = smtplib.SMTP_SSL(QQserver , port)
# 第二步、登录邮箱
# 链接对象.login(账号 , 密码)
# 密码:一般邮箱直接写邮箱密码,QQ邮箱写授权码
name = "[email protected]"
pwd = "xxx"
# 登录邮箱
connect.login(name , pwd)
# 第三步、准备邮件数据
# 1)、创建邮件对象
msg = MIMEMultipart()
# 2)、设置邮件主题
subject = Header("发送HTML格式邮件" , "utf-8").encode()
# 3)、邮件主题添加至邮件对象
msg["Subject"] = subject
# 4)、设置邮件发送者
msg["From"] = sender
# 5)、设置邮件接收者
msg["To"] = receivers
# 6)、设置HTML格式邮件正文,添加邮件正文至邮件对象
# 普通文本:MIMEText(文本内容,文本类型,编码方式)
# 文本类型:plain(普通文本)、html(超链接)、base64(二进制文件,附件)
text = MIMEText("这个一封邮件" , "plain" , "utf-8") # 文本格式
# 创建HTML内容
htmlcontent = """
我是大标题
我是副标题
我是邮件正文内容
点击我试试
"""
htmltext = MIMEText(htmlcontent , 'html' , "utf-8")
msg.attach(htmltext)
# 第四步、发送邮件
# 连接对象.sendemail(发件人,收件人,字符串类型的邮件对象)
connect.sendmail(sender , receivers.split(',') , msg.as_string())
# 第五步、退出邮件
connect.quit()
# 三、smtplib发送图片附件和图片正文
import smtplib
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
# 1、连接邮件服务器,登录邮箱
server = "smtp.qq.com"
port = 465
name = "[email protected]"
pwd = "xxx"
# 连接邮件服务器
conn = smtplib.SMTP_SSL(server , port)
# 登录邮箱
conn.login(name , pwd)
# 2、创建邮件内容
# 创建邮件对象
msg = MIMEMultipart()
# 设置邮件主题,邮件主题添加至邮件对象
header = Header("发送图片邮件" , 'utf-8').encode()
msg["Subject"] = header
# 收件人
receivers = "[email protected] ; [email protected]"
msg['To'] = receivers
# 发件人
sender = "[email protected]"
msg['From'] = sender
# 创建纯文本内容
text = MIMEText("我是纯文本内容" , 'plain' , 'utf-8')
msg.attach(text)
# 创建HTML文本内容
htmlcontent = """
我是大标题
我是副标题
我是邮件正文内容
点我试试
"""
htmltext = MIMEText(htmlcontent , 'html' , "utf-8")
msg.attach(htmltext)
# 2.1)、发送图片附件,MIMEImage(图片二进制数据)
# A、获取图片数据,创建图片对象
image = open("./科比.png" , "rb").read()
imagecontent = MIMEImage(image)
# B、设置附件名称
# 附件名称为中文时的写法
imagecontent.add_header("Content-Disposition", "attachment", filename=("gbk", "", "科比.png"))
# 附件名称非中文时的写法
# imagecontent['Content-Disposition'] = 'attachment ; filename = "Kobe.png"'
# C、添加图片至邮件对象
msg.attach(imagecontent)
# 2.2)、发送图片内容(需要html格式内容实现)
# A、准备图片
# 获取图片数据(二进制格式)
image_data = open("./壁纸.jpg" , "rb").read()
# 创建图片对象
image = MIMEImage(image_data)
# 设置图片id
image.add_header('Content-ID' , '')
# 图片对象添加至邮件对象
msg.attach(image)
# 将图片以html形式添加至文本内容
content = """
这是一条发送图片的邮件
"""
imagehtml = MIMEText(content , "html" , "utf-8")
msg.attach(imagehtml)
# 3、发送邮件
conn.sendmail(sender , receivers , msg.as_string())
# 4、关闭邮件连接
conn.quit()
# 四、smtplib发送文件附件
import smtplib
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
# 1、连接邮件服务器,登录邮箱
server = "smtp.qq.com"
port = 465
name = "[email protected]"
pwd = "xxx"
# 连接邮件服务器
conn = smtplib.SMTP_SSL(server , port)
# 登录邮箱
conn.login(name , pwd)
# 2、创建邮件内容
# 2.1、创建邮件对象
msg = MIMEMultipart()
# 2.2、设置邮件主题,邮件主题添加至邮件对象
header = Header("测试发送附件邮件" , 'utf-8').encode()
msg["Subject"] = header
# 2.3、收件人
receivers = "[email protected] ; [email protected]"
msg['To'] = receivers
# 2.4、发件人
sender = "[email protected]"
msg['From'] = sender
# 2.5、发送附件
# ppt附件
# A)、读取文件内容(二进制形式)
content_ppt = open("./测试.pptx" , "rb").read()
# B)、设置邮件正文(文件内容,编码格式必须为base64)
fileppt = MIMEText(content_ppt , "base64" , "utf-8")
# C)、设置附件名称
# 附件名称为中文时方法
fileppt["Content-Type"] = "application/octet-stream"
fileppt.add_header("Content-Disposition", "attachment", filename=("gbk" , "" , "测试.pptx"))
msg.attach(fileppt)
# word附件
content_word = open("./测试.docx" , "rb").read()
file_word = MIMEText(content_word , "base64" , "utf-8")
# 附件名称为中文时方法
file_word["Content-Type"] = "application/octet-stream"
file_word.add_header("Content-Disposition" , 'attachment' , filename = ("gbk" , "" , "word.docx"))
msg.attach(file_word)
# excel附件
content_excel = open("./测试.xlsx" , "rb").read()
file_excel = MIMEText(content_excel , "base64" , "utf-8")
# 附件名称为中文时方法
file_excel["Content-Type"] = "application/octet-stream"
file_excel.add_header("Content-Disposition" , 'attachment' , filename = ('gbk' , "" , "测试.xlsx"))
msg.attach(file_excel)
# txt附件
content_txt = open("./测试.txt" , "rb").read()
file_txt = MIMEText(content_txt , "base64" , "utf-8")
# 附件名称为中文时方法
file_txt["Content-Type"] = "application/octet-stream"
file_txt.add_header("Content-Disposition" , "attachment" , filename = ("gbk" , "" , "测试.txt"))
msg.attach(file_txt)
# 图片附件
content_pic = open("./科比.png" , "rb").read()
# 设置邮件正文(不需要base64编码)
file_pic = MIMEImage(content_pic)
# 附件名称为中文时方法
file_pic["Content-Type"] = "application/octet-stream"
file_pic.add_header("Content-Disposition" , 'attachment' , filename = ("gbk" , "" , "老大.png"))
msg.attach(file_pic)
# 3、发送邮件
conn.sendmail(sender , receivers , msg.as_string())
# 4、关闭邮件连接
conn.quit()
九、日期和时间
Python datetime模块为日期和时间的处理提供各种方法,datetime模块包含了3个类,分别是date、time、datetime:
9.1、date模块
import datetime
import time
# 1、date类
# 年月日拼接为日期格式
date = datetime.date(2020 , 6 , 2)
print("Date:" , date)
# 获取当前日期
today = datetime.date.today()
# 输出当前日期格式
print("当前日期为:{0}-{1}-{2}".format(today.day , today.month , today.year))
# fromtimestamp()传入时间戳,返回date对象
time = time.time()
today = datetime.date.fromtimestamp(time)
print("today:" , today)
# strftime格式化日期
today = datetime.date.today().strftime('%Y-%m-%d')
print("today:" , today)
# timedelta()对天数进行操作
today = datetime.date.today()
# 计算365天之前日期
date = today - datetime.timedelta(365)
print("date:" , date)
Date: 2020-06-02
当前日期为:2-6-2020
today: 2020-06-02
today: 2020-06-02
date: 2019-06-03
9.2、time模块
time模块中时间表现的格式主要有三种:
a、timestamp:时间戳,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量
b、struct_time:结构体时间,时间元组,共有九个元素组
c、format time:格式化时间,已格式化的结构使时间更具可读性。包括自定义格式和固定格式
1、时间格式转换图:
2、主要time生成方法和time格式转换方法
import time
# 1、生成timestamp
timestamp = time.time()
print("生成timestamp:" , timestamp)
# 2、生成struct_time
struct_time = time.localtime()
print("生成struct_time:" , struct_time)
# struct_time to timestamp
print("struct_time -> timestamp:" , time.mktime(struct_time))
# timestamp to struct_time 本地时间
print("本地时间timestamp -> struct_time:", time.localtime(timestamp))
# timestamp to struct_time 格林威治时间
print("格林威治时间timestamp -> struct_time:" , time.gmtime(timestamp))
# 3、生成format_time
# struct_time to format_time
print("本地时间struct_time -> format_time:" , time.strftime("%Y-%m-%d %X" , time.localtime()))
print("格林威治时间struct_time -> format_time:" , time.strftime("%Y-%m-%d %X" , time.gmtime()))
# format_time to struct_time
print("format_time -> struct_time:" , time.strptime('2011-05-05 16:37:06', '%Y-%m-%d %X'))
# 4、生成固定格式的时间表示格式
print("本地时间format_time -> 字符串类型:" , time.asctime(time.localtime()))
print("格林威治时间format_time -> 字符串类型:" , time.asctime(time.gmtime()))
print("时间戳timestamp -> 字符串类型:" , time.ctime(time.time()))
# timestamp加减单位以秒为单位
time1 = time.time()
time2 = time1 + 100
print("time1:" , time.ctime(time1))
print("time2:" , time.ctime(time2))
生成timestamp: 1591093153.8028092
生成struct_time: time.struct_time(tm_year=2020, tm_mon=6, tm_mday=2, tm_hour=18, tm_min=19, tm_sec=13, tm_wday=1, tm_yday=154, tm_isdst=0)
struct_time -> timestamp: 1591093153.0
本地时间timestamp -> struct_time: time.struct_time(tm_year=2020, tm_mon=6, tm_mday=2, tm_hour=18, tm_min=19, tm_sec=13, tm_wday=1, tm_yday=154, tm_isdst=0)
格林威治时间timestamp -> struct_time: time.struct_time(tm_year=2020, tm_mon=6, tm_mday=2, tm_hour=10, tm_min=19, tm_sec=13, tm_wday=1, tm_yday=154, tm_isdst=0)
本地时间struct_time -> format_time: 2020-06-02 18:19:13
格林威治时间struct_time -> format_time: 2020-06-02 10:19:13
format_time -> struct_time: time.struct_time(tm_year=2011, tm_mon=5, tm_mday=5, tm_hour=16, tm_min=37, tm_sec=6, tm_wday=3, tm_yday=125, tm_isdst=-1)
本地时间format_time -> 字符串类型: Tue Jun 2 18:19:13 2020
格林威治时间format_time -> 字符串类型: Tue Jun 2 10:19:13 2020
时间戳timestamp -> 字符串类型: Tue Jun 2 18:19:13 2020
time1: Tue Jun 2 18:19:13 2020
time2: Tue Jun 2 18:20:53 2020
struct_time元组元素结构:
属性 值
tm_year(年) 比如2011
tm_mon(月) 1 - 12
tm_mday(日) 1 - 31
tm_hour(时) 0 - 23
tm_min(分) 0 - 59
tm_sec(秒) 0 - 61
tm_wday(weekday) 0 - 6(0表示周日)
tm_yday(一年中的第几天) 1 - 366
tm_isdst(是否是夏令时) 默认为-1
format time结构化表示:
格式 | 含义 |
%a | 本地(locale)简化星期名称 |
%A | 本地完整星期名称 |
%b | 本地简化月份名称 |
%B | 本地完整月份名称 |
%c | 本地相应的日期和时间表示 |
%d | 一个月中的第几天(01 - 31) |
%H | 一天中的第几个小时(24小时制,00 - 23) |
%I | 第几个小时(12小时制,01 - 12) |
%j | 一年中的第几天(001 - 366) |
%m | 月份(01 - 12) |
%M | 分钟数(00 - 59) |
%p | 本地am或者pm的相应符 |
%S | 秒(01 - 61) |
%U | 一年中的星期数。(00 - 53星期天是一个星期的开始。)第一个星期天之前的所有天数都放在第0周。 |
%w | 一个星期中的第几天(0 - 6,0是星期天) |
%W | 和%U基本相同,不同的是%W以星期一为一个星期的开始。 |
%x | 本地相应日期 |
%X | 本地相应时间 |
%y | 去掉世纪的年份(00 - 99) |
%Y | 完整的年份 |
%Z | 时区的名字(如果不存在为空字符) |
%% | ‘%’字符 |
3、time加减
timestamp:加减单位以秒为单位
9.3、datetime模块
datatime 模块重新封装了time模块,提供更多接口,提供的类有:date、time、datetime、timedelta和tzinfo
A)、date类
datetime.date(year , month , day)
1.静态方法和字段:
date.max、date.min :date对象所能表示的最大、最小日期;
date.resolution:date对象表示日期的最小单位,一般为天;
date.today():返回一个表示当前本地日期的date对象;
date.fromtimestamp(timestamp):根据给定的时间戮,返回一个date对象;
import datetime , time
# 1、静态方法和字段
print("datetime.date.max:" , datetime.date.max)
print("datetime.date.min:" , datetime.date.min)
print("datetime.date.resolution:" , datetime.date.resolution)
print("datetime.date.today:" , datetime.date.today())
print("datetime.date.fromtimestamp:" , datetime.date.fromtimestamp(time.time()))
datetime.date.max: 9999-12-31
datetime.date.min: 0001-01-01
datetime.date.resolution: 1 day, 0:00:00
datetime.date.today: 2020-06-02
datetime.date.fromtimestamp: 2020-06-02
2.方法和属性
date = date(2020 , 06 , 03) # date对象
# 2、方法和属性
import datetime , time
# 获取当日日期
today = datetime.date.today()
print("today is :" , today)
# 特定格式输出年月日
print("今天是{0}年{1}月{2}日".format(today.year , today.month , today.day))
# 生成新的日期对象
tomorrow = today.replace(day = 3)
print("tomorrow is :" , tomorrow)
# 生成日期对应的time.struct_time对象
print("生成日期对应的time.struct_time对象:" , today.timetuple())
# 返回weekday,星期一返回0;星期二返回1
print("today.weekday:" , today.weekday())
# 返回weekday,星期一返回1;星期二返回2
print("today.isoweekday:" , today.isoweekday())
# 返回(year,month,day)格式的元组
print("today.isocalendar:" , today.isocalendar())
# 返回'YYYY-MM-DD’格式字符串
print("today.isoformat:" , today.isoformat())
# 设置日期格式
print("today.strftime:" , today.strftime("%d - %m - %Y"))
today is : 2020-06-02
今天是2020年6月2日
tomorrow is : 2020-06-03
生成日期对应的time.struct_time对象: time.struct_time(tm_year=2020, tm_mon=6, tm_mday=2, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=1, tm_yday=154, tm_isdst=-1)
today.weekday: 1
today.isoweekday: 2
today.isocalendar: (2020, 23, 2)
today.isoformat: 2020-06-02
today.strftime: 02 - 06 - 2020
B)、time类
datetime.time( hour , minute , second , microsecond , tzinfo )
1.静态字段和方法
time.min、time.max:time类所能表示的最小、最大时间。其中time.min = time(0, 0, 0, 0), time.max = time(23, 59, 59, 999999);
time.resolution:时间的最小单位,这里是1微秒;
2.方法和属性
timedate = datetime.time(10,23,15) #time对象
timedate.hour、timedate.minute、timedate.second、timedate.microsecond:时、分、秒、微秒;
timedate.tzinfo:时区信息;
timedate.replace(hour , minute , second , microsecond , tzinfo ):创建一个新的时间对象,用参数指定的时、分、秒、微秒代替原有对象中的属性(原有对象仍保持不变);
timedate.isoformat():返回形如"HH:MM:SS"格式的字符串表示;
timedate.strftime(fmt):同time模块中的format;
from datetime import time
time_date = time(22 , 13 , 14)
# 1、静态方法和字段
print("time_date.max:" , time_date.max)
print("time_date.min:" , time_date.min)
print("time_date.resolution:" , time_date.resolution)
# 2、方法和属性
# 输入时分秒,返回datetime.time对象
print("time_date对象:" , type(time_date))
print("time_date:" , time_date)
# 特定格式输出时间
print("现在时间是{0}:{1}:{2}".format(time_date.hour , time_date.minute , time_date.second))
# 更新时间
time_date_update = time_date.replace(hour=20 , minute=20 , second=20)
# 更新时间后之前时间未改变
print("time_date:" , time_date)
print("time_date_update:" , time_date_update)
# 返回形如"HH:MM:SS"格式的字符串
print("time_date.isoformat():" , time_date.isoformat())
print("time_date.strftime():" , time_date.strftime("%X"))
# 时区信息
print("time_date.tzinfo:" , time_date.tzinfo)
time_date.max: 23:59:59.999999
time_date.min: 00:00:00
time_date.resolution: 0:00:00.000001
time_date对象:
time_date: 22:13:14
现在时间是22:13:14
time_date: 22:13:14
time_date_update: 20:20:20
time_date.isoformat(): 22:13:14
time_date.strftime(): 22:13:14
time_date.tzinfo: None
C)、datetime类
datetime类相当于date类和time类的结合,datetime类提供了如下方法和属性:
datetime.datetime (year , month , day , hour , minute , second , microsecond , tzinfo )
1.静态方法和字段
2.方法和属性
date_time = datetime.now() # 返回datetime对象
date_time.year:年份
date_time.month:月份
date_time.day:日期
date_time.hour:小时
date_time.minute:分钟
date_time.second:秒
date_time.microsecond:微秒
date_time.tzinfo:时区
date_time.date():获取date对象
date_time.time():获取time对象
date_time. replace (year , month , day , hour , minute , second , microsecond , tzinfo):更新时间
date_time. timetuple ():返回日期对应的datetime.struct_time结构体时间对象
date_time. utctimetuple ():返回日期对应的datetime.struct_time结构体时间对象,即UTC时间元组 #格林威治时间
date_time. toordinal ():返回公元公历开始到现在的天数,公元1年1月1日为1
date_time. weekday ():返回weekday,星期一返回0;星期二返回1,以此类推
date_time. isocalendar ():返回(年 , 月 , 日 )的元组
date_time. isoformat ([ sep ] ):返回格式如'YYYY-MM-DD-HH-MM-SS’的字符串;
date_time. ctime ():返回一个日期时间的C格式字符串,等效于time.ctime(time.mktime(date_time.timetuple()));
date_time. strftime (format):和time模块format相同功能
from datetime import datetime , timezone
import time
# 1.静态方法和字段
# 本地时间
today_time = datetime.today()
print("today_time:" , today_time)
print("today_time类型:" , type(today_time))
# 本地时间
now_time = datetime.now()
print("now_time:" , now_time)
print("now_time类型:" , type(now_time))
# 格林尼治时间
today_time_utc = datetime.utcnow()
print("today_time_utc:" , today_time_utc)
# 根据时间戮创建一个datetime对象,参数tz指定时区信息;
print("datetime.fromtimestamp(timestamp):" , datetime.fromtimestamp(time.time()))
print("datetime.fromtimestamp(timestamp , timezone.utc):", datetime.fromtimestamp(time.time(), timezone.utc))
# 根据时间戮创建一个datetime对象,格林尼治时间
print("datetime.utcfromtimestamp(timestamp)" , datetime.utcfromtimestamp(time.time()))
date = datetime.today().date()
time = datetime.today().time()
print("datetime.today().date():" , date)
print("datetime.today().time():" , time)
# 根据date和time对象,创建一个datetime对象
print("datetime.combine(date,time):" , datetime.combine(date , time))
# 格式字符串转换为datetime对象
print("datetime.strptime(date_string , formant):" , datetime.strptime("2020-06-03 11:15:20" , "%Y-%m-%d %H:%M:%S"))
# 2、属性和方法
now_time = datetime.now()
print("now_time.year:" , now_time.year) # 年
print("now_time.month:" , now_time.month) # 月
print("now_time.day:" , now_time.day) # 日
print("now_time.hour:" , now_time.hour) # 时
print("now_time.minute:" , now_time.minute) # 分
print("now_time.second:" , now_time.second) # 秒
print("now_time.microsecond:" , now_time.microsecond) # 毫秒
print("now_time.tzinfo:" , now_time.tzinfo) # 时区
print("now_time.date():" , now_time.date()) # date对象
print("now_time.time():" , now_time.time()) # time对象
print("now_time更新时间:" , now_time.replace(year=2021)) # 更新时间
print("now_time.timetuple:" , now_time.timetuple()) # 返回datetime.struct_time结构体时间对象
print("now_time.utctimetuple:" , now_time.utctimetuple()) # 返回datetime.struct_time结构体时间对象,格林尼治时间
print("now_time.toordinal:" , now_time.toordinal()) # 返回公元公历开始到现在的天数
print("now_time.weekday:" , now_time.weekday()) # 返回weekday,星期一返回0;星期二返回1,以此类推
print("now_time.isoweekday:" , now_time.isoweekday()) # 返回weekday,星期一返回1;星期二返回2,以此类推
print("now_time.isocalendar:" , now_time.isocalendar()) # 返回(年,月,日)的元组
print("now_time.ctime:" , now_time.ctime())
print("now_time.isoformat:" , now_time.isoformat())
print("now_time.strftime:" , now_time.strftime("%X"))
today_time: 2020-06-03 14:49:23.727944
today_time类型:
now_time: 2020-06-03 14:49:23.727981
now_time类型:
today_time_utc: 2020-06-03 06:49:23.727990
datetime.fromtimestamp(timestamp): 2020-06-03 14:49:23.727995
datetime.fromtimestamp(timestamp , timezone.utc): 2020-06-03 06:49:23.728000+00:00
datetime.utcfromtimestamp(timestamp) 2020-06-03 06:49:23.728009
datetime.today().date(): 2020-06-03
datetime.today().time(): 14:49:23.728017
datetime.combine(date,time): 2020-06-03 14:49:23.728017
datetime.strptime(date_string , formant): 2020-06-03 11:15:20
now_time.year: 2020
now_time.month: 6
now_time.day: 3
now_time.hour: 14
now_time.minute: 49
now_time.second: 23
now_time.microsecond: 734133
now_time.tzinfo: None
now_time.date(): 2020-06-03
now_time.time(): 14:49:23.734133
now_time更新时间: 2021-06-03 14:49:23.734133
now_time.timetuple: time.struct_time(tm_year=2020, tm_mon=6, tm_mday=3, tm_hour=14, tm_min=49, tm_sec=23, tm_wday=2, tm_yday=155, tm_isdst=-1)
now_time.utctimetuple: time.struct_time(tm_year=2020, tm_mon=6, tm_mday=3, tm_hour=14, tm_min=49, tm_sec=23, tm_wday=2, tm_yday=155, tm_isdst=0)
now_time.toordinal: 737579
now_time.weekday: 2
now_time.isoweekday: 3
now_time.isocalendar: (2020, 23, 3)
now_time.ctime: Wed Jun 3 14:49:23 2020
now_time.isoformat: 2020-06-03T14:49:23.734133
now_time.strftime: 14:49:23
9.4、timedelta类,时间加减
timedelta类提供天days,小时hour,分钟,秒,毫秒,微妙的时间计算方法,但不支持月份时间计算
# timedelta类实现时间加减
from datetime import datetime , timedelta
datetime = datetime.now()
#日期减一天
dt1 = datetime + timedelta(days=-1) # 昨天
dt2 = datetime - timedelta(days=1) # 昨天
dt3 = datetime + timedelta(days=1) # 明天
print("dt1:" , dt1)
print("dt2:" , dt2)
print("dt3:" , dt3)
delta_obj = dt3 - datetime
print("delta_obj类型:" , type(delta_obj))
print("delta_obj:" , delta_obj)
print("delta_obj.days:" , delta_obj.days)
print("delta_obj.total_seconds:" , delta_obj.total_seconds())
dt1: 2020-06-02 15:06:29.688281
dt2: 2020-06-02 15:06:29.688281
dt3: 2020-06-04 15:06:29.688281
delta_obj类型:
delta_obj: 1 day, 0:00:00
delta_obj.days: 1
delta_obj.total_seconds: 86400.0
9.5、tzinfo时区类
# tzinfo类实现时区切换
from datetime import tzinfo , datetime , timedelta
"""
tzinfo是关于时区信息的类
tzinfo是一个抽象类,不能直接被实例化
"""
class UTC(tzinfo):
"""UTC"""
def __init__(self,offset = 0):
self._offset = offset
def utcoffset(self, dt):
return timedelta(hours=self._offset)
def tzname(self, dt):
return "UTC +%s" % self._offset
def dst(self, dt):
return timedelta(hours=self._offset)
#北京时间
beijing = datetime(2020 , 6 , 3 , 15 , 15 , 30 , tzinfo=UTC(8))
print("beijing time:" , beijing)
#曼谷时间
bangkok = datetime(2020 , 6 , 3 , 15 , 15 , 30 , tzinfo = UTC(7))
print("bangkok time",bangkok)
#北京时间转成曼谷时间
print("beijing-time to bangkok-time:",beijing.astimezone(UTC(7)))
#计算时间差时需要考虑时区的问题
timespan = beijing - bangkok
print("时差:", timespan)
beijing time: 2020-06-03 15:15:30+08:00
bangkok time 2020-06-03 15:15:30+07:00
beijing-time to bangkok-time: 2020-06-03 14:15:30+07:00
时差: -1 day, 23:00:00
补充常用时间处理方法:
today = datetime.date.today()
yesterday = today - datetime.timedelta(days=1)
last_month = today.month - 1 if today.month - 1 else 12
time_stamp = time.time()
datetime.datetime.fromtimestamp(time_stamp)
int:(time.mktime(today.timetuple()))
today_str = today.strftime("%Y-%m-%d")
today = datetime.datetime.strptime(today_str, "%Y-%m-%d")
today + datetime.timedelta(hours=8)