2 Selenium Python 框架基础

1 单元测试

1.1 什么是单元测试?

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。

对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类。

总的来说,单元就是人为规定的最小的被测功能模块。

单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。

1.2 名词解释

  单元测试主要包含概念如下:test case、test suite、test runner、test fixture

  • test case:

  一个TestCase的实例就是一个测试用例。

  什么是测试用例呢?就是一个完整的测试流程,包括测试前准备环境的搭建(setUp),执行测试代码(run),以及测试后环境的还原(tearDown)。

  • test suite:

  而多个测试用例集合在一起,就是TestSuite,而且TestSuite也可以嵌套TestSuite。

  TestLoader是用来加载TestCase到TestSuite中的,其中有几个loadTestsFrom__()方法,就是从各个地方寻找TestCase,创建它们的实例,

  然后add到TestSuite中,再返回一个TestSuite实例。

  • test runner:

  TextTestRunner是来执行测试用例的,其中的run(test)会执行TestSuite/TestCase中的run(result)方法。

  测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息。

  • test fixture:

    对一个测试用例环境的搭建和销毁,是一个fixture,通过覆盖TestCase的setUp()和tearDown()方法来实现。

  这个有什么用呢?比如说在这个测试用例中需要访问数据库,那么可以在setUp()中建立数据库连接以及进行一些初始化,在tearDown()中清除在数据库中产生的数据,

  然后关闭连接。注意tearDown的过程很重要,要为以后的TestCase留下一个干净的环境。

 1.3 如何单元测试

 1 #被测类
 2 class Index(object):
 3     
 4     def login(self , username , password):
 5         if username == 'root' and password == '123456':
 6             print '登录成功 !'
 7         else:
 8             print '用户名或密码错误 !'
 9         
10 #单元测试
11 import unittest2
12 
13 class TestLogin(unittest2.TestCase):
14     index = Index()
15     
16     def testLoginSuccess(self):   
17         self.index.login('root', '123456')
18     
19     def testLoginUsernameError(self):
20         self.index.login('aaron', '123456')
21         print '--用户名错误'
22         
23     def testLoginPasswordError(self):
24         self.index.login('root', '654321')
25         print '--密码错误'
26         
27 #执行测试
28 if __name__ == '__main__':
29     unittest2.main()
30 
31 #结果
32 用户名或密码错误 !
33 --密码错误
34 登录成功 !
35 用户名或密码错误 !
36 --用户名错误
View Code

 1.4 执行测试的不同方法

  • 使用unittest.main()执行测试用例
  • 使用testsuit来执行测试用例
  • 使用TestLoader构建suite来执行测试用例
 1 #被测类
 2 class Index(object):
 3     
 4     def login(self , username , password):
 5         if username == 'root' and password == '123456':
 6             print '登录成功 !'
 7         else:
 8             print '用户名或密码错误 !'
 9     def search(self , item):
10         if item == 'Python':
11             print '搜索成功 !'
12         else:
13             print '搜索失败 !'
14         
15 #单元测试
16 import unittest2
17 
18 class TestLogin(unittest2.TestCase):
19     index = Index()
20     
21     def testLoginSuccess(self):   
22         self.index.login('root', '123456')
23     
24     def testLoginUsernameError(self):
25         self.index.login('aaron', '123456')
26         print '--用户名错误'
27         
28     def testLoginPasswordError(self):
29         self.index.login('root', '654321')
30         print '--密码错误'
31         
32 class TestSearch(unittest2.TestCase):  
33     index = Index()
34     
35     def testSearchSuccess(self):   
36         self.index.search('Python')
37     
38     def testSearchFail(self):
39         self.index.search('Java')
40 
41 #使用unittest.main()执行测试用例------
42 if __name__ == '__main__':
43     unittest2.main()
44 
45 #使用addTest构建suite来执行测试用例------
46 if __name__ == '__main__':
47     #以测试用例为单位构造测试集
48     #TestSuit:组织测试用例的实例,支持测试用例的添加和删除,最终将传递给  testRunner进行测试执行
49     suite = unittest2.TestSuite()
50     suite.addTest(TestLogin.testLoginSuccess())
51     suite.addTest(TestLogin.testLoginUsernameError())
52     suite.addTest(TestLogin.testLoginPasswordError())
53     #执行测试
54     #TextTestRunner:进行测试用例执行的实例,其中Text的意思是以文本形式显示测试结果。
55     #测试的结果会保存到TextTestResult实例中,包括运行了多少测试用例,成功了多少,失败了多少等信息
56     runner = unittest2.TextTestRunner()
57     runner.run(suite)
58     
59 #使用TestLoader构建suite来执行测试用例------
60 if __name__ == '__main__':
61     #以测试类为单位构造测试集
62     #TestLoader:用来加载TestCase到TestSuite中
63     #其中有几个  loadTestsFromXX()方法,就是从各个地方寻找TestCase,创建它们的实例
64     #然后add到TestSuite中,再返回一个TestSuite实例;
65     suite1 = unittest2.TestLoader().loadTestsFromTestCase(TestLogin)
66     suite2 = unittest2.TestLoader().loadTestsFromTestCase(TestSearch)
67     suite = unittest2.TestSuite([suite1 , suite2])  
68     unittest2.TextTestRunner(verbosity=2).run(suite)
View Code

 1.5 测试执行顺序

  • setUpClass:类中所有用例执行前执行一次
  • tearDownClass:类中所有用例执行后执行一次
  • setUp:每个用例执行前执行一次
  • tearDown:每个用例执行后执行一次
  • 测试用例执行顺序:用例名称test后面按字母顺序执行
 1 import unittest2
 2 
 3 class TestDemo(unittest2.TestCase):
 4     @classmethod
 5     def setUpClass(self):
 6         print 'setUpClass'
 7     @classmethod
 8     def tearDownClass(self):
 9         print 'tearDownClass'
10     def setUp(self):
11         print 'setUp'
12     def tearDown(self):
13         print 'tearDown'
14     def testLogin(self):
15         print 'login'
16     def testAdd(self):
17         print 'add'
18     def testUpdate(self):
19         print 'update'
20     def testLogout(self):
21         print 'logout'
22 
23 #使用unittest.main()执行测试用例------
24 if __name__ == '__main__':
25     unittest2.main()
26 
27 #结果
28 setUpClass
29 setUp
30 add
31 tearDown
32 setUp
33 login
34 tearDown
35 setUp
36 logout
37 tearDown
38 setUp
39 update
40 tearDown
41 tearDownClass
View Code

2 测试报告

2.1 测试报告

报告名称:HTMLTestRunner为单元测试报告

下载地址:http://tungwaiyip.info/software/HTMLTestRunner.html

使用方法:HTMLTestRunner.py文件放在C:Python27Lib下

 1 #被测类
 2 import unittest2
 3 import time
 4 import HTMLTestRunner
 5 
 6 class TestDemo(unittest2.TestCase):
 7     @classmethod
 8     def setUpClass(self):
 9         print 'setUpClass'
10     @classmethod
11     def tearDownClass(self):
12         print 'tearDownClass'
13     def testLogin(self):
14         print 'login'
15     def testAdd(self):
16         print 'add'
17     def testUpdate(self):
18         print 'update'
19     def testLogout(self):
20         print 'logout'
21 
22 #测试类
23 import time
24 import HTMLTestRunner
25 from testcase.demo5 import *
26 
27 #使用addTest构建suite来执行测试用例------
28 suite = unittest2.TestSuite()
29 suite.addTest(TestDemo('testAdd'))
30 #报告准备
31 reportName = time.strftime('%Y%m%d%H%M%S')             #文件名
32 fp = open('../' + reportName + '.html' , 'wb')         #文件路径
33 runner = HTMLTestRunner.HTMLTestRunner(stream = fp ,   #定义报告
34                                        title = '测试报告' ,
35                                        description = '自动化测试报告Demo')
36 #执行测试
37 result = runner.run(suite)
38 #关闭文件
39 fp.close()
40 print result
41 
42 #测试结果
43 Finding files... done.
44 Importing test modules ... setUpClass
45 tearDownClass
46 .
47 Time Elapsed: 0:00:00
48 <HTMLTestRunner._TestResult run=1 errors=0 failures=0>
View Code

2.2 文档注释

python在注释中有一个非常有用的东西是 doc String ,它可以用于模块、函数和类的描述。

使用三个双引号或三个单引号进行注释。

文档字符串的惯例是一个多行字符串,它的首行以大写字母开始,句号结尾。第二行是空行,从第三行开始是详细的描述。

 1 #被测类
 2 #!/usr/bin/env python
 3 # coding=utf-8
 4 
 5 import unittest2
 6 import time
 7 import HTMLTestRunner
 8 
 9 class TestDemo(unittest2.TestCase):
10     '''(测试Demo类)'''
11     @classmethod
12     def setUpClass(self):
13         print 'setUpClass'
14     @classmethod
15     def tearDownClass(self):
16         print 'tearDownClass'
17         
18     def testLogin(self):
19         """(登录)"""
20         print 'login'
21 
22     def testAdd(self):
23         '''(新增)'''
24         print 'add'
25     
26     def testUpdate(self):
27         '''(修改)'''
28         print 'update'
29 
30     def testLogout(self):
31         '''(退出)'''
32         print 'logout'
33 
34 #测试类
35 #!/usr/bin/env python
36 # coding=utf-8
37 
38 import time
39 import HTMLTestRunner
40 from testcase.demo5 import *
41 
42 #使用addTest构建suite来执行测试用例------
43 suite = unittest2.TestSuite()
44 suite.addTest(TestDemo('testLogin'))
45 suite.addTest(TestDemo('testAdd'))
46 suite.addTest(TestDemo('testUpdate'))
47 suite.addTest(TestDemo('testLogout'))
48 #报告准备
49 reportName = time.strftime('%Y%m%d%H%M%S')             #文件名
50 fp = open('../' + reportName + '.html' , 'wb')         #文件路径
51 runner = HTMLTestRunner.HTMLTestRunner(stream = fp ,   #定义报告
52                                        title = '测试报告' ,
53                                        description = '自动化测试报告Demo')
54 #执行测试
55 result = runner.run(suite)
56 #关闭文件
57 fp.close()
58 print result
View Code

 3 配置文件

3.1 配置文件

1 #配置selenium
2 [selenium]
3 browser = firefox
4 timeout = 10
View Code

3.2 操作配置文件

Python标准库的ConfigParser模块提供一套API操作配置文件。

 1 #!/usr/bin/env python
 2 # coding=utf-8
 3 
 4 import ConfigParser
 5 
 6 class Configer(object):
 7     
 8     #构造函数,初始化ConfigParser类,并读取config文件
 9     def __init__(self , filePath):
10         self.conf = ConfigParser.ConfigParser()
11         self.conf.read(filePath)
12     
13     #获取key的value 
14     def getConf(self , section , key):
15         result = self.conf.get(section, key)
16         return result
View Code

3.3 配置文件解析

将配置文件中内容解析出来方便使用

1 #!/usr/bin/env python
2 # coding=utf-8
3 
4 from libs.Configer import *
5 
6 class SelConf(object):
7     conf = Configer("../config/selenium.conf")
8     browser = conf.getConf('selenium', 'browser')
9     timeout = conf.getConf('selenium', 'timeout')
View Code

3.4 配置文件使用

 1 #!/usr/bin/env python
 2 # coding=utf-8
 3 
 4 from config.SeleniumConf import *
 5 
 6 if __name__ == '__main__':
 7     print SelConf.browser
 8 
 9 #结果
10 firefox
View Code

 4 日志

4.1 logging模块四大类

python通过logging模块提供简单易用、且功能强大的日志功能。logging模块四大类如下:

  • logger:提供了应用程序可以直接使用的接口
  • handler将(logger创建的)日志发送到指定的输出路径
  • filter决定输出哪条日志
  • formatter决定日志的最终输出格式

4.1.1 logger类

每个程序在输出信息之前都要通过 logging.getlogger() 来获得一个log实例

源码如下:

def getLogger(name=None):

"""
Return a logger with the specified name, creating it if necessary.

If no name is specified, return the root logger.
"""
if name:
return Logger.manager.getLogger(name)
else:
return root

logger的level有以下几个级别:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL

如果把looger的级别设置为INFO, 那么小于INFO级别的日志都不输出, 大于等于INFO级别的日志都输出

4.1.2 handlers

handler对象负责发送相关的信息到指定目的地。如:控制台、文件、网络等

4.1.3 Formatters

Formatter对象设置日志信息格式,默认的时间格式为%Y-%m-%d %H:%M:%S

关于formatter的配置,采用的是%(<dict key>)s的形式,就是字典的关键字替换。提供的关键字包括:

  • %(name)s             Name of the logger (logging channel).
  • %(levelno)s           Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
  • %(levelname)s       Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
  • %(pathname)s       Full pathname of the source file where the logging call was issued (if available).
  • %(filename)s         Filename portion of pathname.
  • %(module)s           Module (name portion of filename).
  • %(funcName)s       Name of function containing the logging call.
  • %(lineno)d            Source line number where the logging call was issued (if available).
  • %(created)f           Time when the LogRecord was created (as returned by time.time()).
  • %(relativeCreated)d     Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
  • %(asctime)s          Human-readable time when the LogRecord was created. By default this is of the form “2003-07-08 16:49:45,896” (the numbers after the comma are millisecond portion of the time).
  • %(msecs)d            Millisecond portion of the time when the LogRecord was created.
  • %(thread)d           Thread ID (if available).
  • %(threadName)s   Thread name (if available).
  • %(process)d          Process ID (if available).
  • %(message)s        The logged message, computed as msg % args.

 4.1.4 TimeRotatingFileHandler

TimeRotatingFileHandler根据时间日志文件的记录。

格式:TimedRotatingFileHandler(filename [,when [,interval [,backupCount]]])

  • filename 是输出日志文件名的前缀
  • when 是一个字符串的定义如下:

“S”: Seconds
“M”: Minutes
“H”: Hours
“D”: Days
“W”: Week day (0=Monday)
“midnight”: Roll over at midnight

  • interval 是指等待多少个单位when的时间后,Logger会自动重建文件
  • backupCount 是保留日志个数。默认的0是不会自动删除掉日志。若设10,则在文件的创建过程中库会判断是否有超过这个10,若超过,则会从最先创建的开始删除。

 4.2 实战

4.2.1 log配置文件

 1 ###############################################
 2 #root 必须有
 3 #propagate 是否继承父类的log信息,0:否 1:是
 4 #propagate 默认1,如果设置为1会打印两次
 5 #handlers  对应下面handler
 6 #qualname  getLogger时输入的名字
 7 ###############################################
 8 
 9 [loggers]
10 keys = root,errorLogger
11 
12 [logger_root]
13 level = ERROR
14 handlers = errorHandler
15 
16 [logger_errorLogger]
17 level = ERROR
18 propagate = 0
19 handlers = errorHandler
20 qualname = errorLogger
21 
22 ###############################################
23 #按照时间的滚动方式记录日志
24 #formatter 对应下面日志格式
25 ###############################################
26 
27 [handlers]
28 keys = errorHandler
29 
30 [handler_errorHandler]
31 class=logging.handlers.TimedRotatingFileHandler
32 level=ERROR
33 args = ('../logs/selenium.log','D',1,5,) 
34 formatter = errorFmt
35 
36 ###############################################
37 #日志格式
38 ###############################################
39 
40 [formatters]
41 keys = errorFmt
42 
43 [formatter_errorFmt]
44 class = logging.Formatter
45 format = %(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - [line:%(lineno)d] - %(message)s
46 datefmt = %Y-%m-%d %H:%M:%S
View Code

4.2.2 初始化文件

 1 #!/usr/bin/python
 2 # coding=utf8
 3 
 4 import ConfigParser
 5 import logging
 6 import logging.config
 7 
 8 class Logger(object):
 9     
10     @staticmethod
11     def append():
12         logging.config.fileConfig('../config/logger.conf')
13         append = logging.getLogger("errorLogger")
14         return append
View Code

4.2.3 测试

 1 #!/usr/bin/python
 2 # coding=utf8
 3 
 4 from libs.Logger import *
 5 
 6 def testLog():
 7     Logger.append().error('error11111')
 8 
 9 def testLog2():
10     Logger.append().error('error22222')
11 
12 if __name__ == '__main__':
13     testLog()
14     testLog2()
15 
16 #结果 - 文件
17 selenium.log
18 selenium.log.2017-03-14
19 
20 #结果 - 内容
21 2017-04-02 23:32:33 - ERROR - testConfig.py - testLog - [line:7] - error11111
22 2017-04-02 23:32:33 - ERROR - testConfig.py - testLog2 - [line:11] - error22222
View Code

 5 邮件

5.1 简介

SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议

Python对SMTP支持有smtplib和email两个模块,email负责构造邮件,smtplib负责发送邮件

可以发送纯文本邮件、HTML邮件、带附件的邮件等

发送邮件时,我们一般使用第三方SMTP服务,163邮箱的SMTP服务开启步骤:进入163邮箱 - 设置 - POP3/SMTP/IMAP

POP3与SMTP区别:POP3用于接收邮件;SMTP用于发送邮件

5.1 构造邮件

email.mime:creating email and MIME objects from scratch,也就是一点点地构造一封邮件

  • MIMEText对象,表示一个文本邮件
  • MIMEImage对象,表示一个作为附件的图片
  • MIMEMultipart对象,表示把多个对象组合起来
  • MIMEBase对象,可以表示任何对象

 5.2 发送文本邮件

 1 #配置文件================
 2 [email]
 3 #构造邮件
 4 from_addr=XXX@163.com
 5 to_addr=XXX@qq.com
 6 #发送邮件
 7 host=smtp.163.com
 8 port=25
 9 user=XXX@163.com
10 password=XXX
11 
12 #解析文件================
13 #!/usr/bin/env python
14 # coding=utf-8
15 
16 from libs.Configer import *
17 
18 class email(object):
19     conf = Configer("../config/email.conf")
20     #构造邮件
21     from_addr = conf.getConf('email', 'from_addr')
22     to_addr = conf.getConf('email', 'to_addr') 
23     #发送邮件
24     host = conf.getConf('email', 'host')
25     port = conf.getConf('email', 'port')
26     user = conf.getConf('email', 'user')
27     password = conf.getConf('email', 'password')
28 
29 #测试文件================
30 #!/usr/bin/python
31 # coding=utf8
32 
33 from libs.email import *
34 from email.mime.text import MIMEText
35 from email.header import Header
36 #构造邮件
37 msg = MIMEText('请大家自学Python...', 'plain', 'utf-8')  #邮件主体
38 #不赋值msg['Subject']、msg['From']、msg['To'],会导致出现554情况
39 msg['Subject'] = Header('请大家自学Python', 'utf-8')    #邮件标题
40 msg['From'] = email.from_addr  #发件人   
41 msg['To'] = email.to_addr #收件人
42  
43 import smtplib
44 #发送邮件
45 server = smtplib.SMTP() 
46 server.connect(email.host, int(email.port))  # 连接网易SMTP服务,默认端口号25
47 # server.set_debuglevel(1)    #打印与SMTP服务器交互的所有信息
48 server.login(email.from_addr, email.password)   #登录
49 server.sendmail(email.from_addr, email.to_addr, msg.as_string()) #发送邮件,传入msg
50 server.quit()
View Code

 163退信的常见问题连接:http://help.163.com/09/1224/17/5RAJ4LMH00753VB8.html

5.3 给多人发送邮件

  • 配置文件修改:to_addr=XXX@qq.com;XXX@163.com
  • email解析文件修改:to_addr = conf.getConf('email', 'to_addr').split(';')
  • 测试文件修改:msg['To'] = ";".join(email.to_addr) #收件人
 1 #配置文件=============================
 2 [email]
 3 #构造邮件
 4 from_addr=XXX@163.com
 5 to_addr=XXX@qq.com;XXX@163.com
 6 #发送邮件
 7 host=smtp.163.com
 8 port=25
 9 user=XXX@163.com
10 password=XXX
11 
12 #解析文件=============================
13 #!/usr/bin/env python
14 # coding=utf-8
15 
16 from libs.Configer import *
17 
18 class email(object):
19     conf = Configer("../config/email.conf")
20     #构造邮件
21     from_addr = conf.getConf('email', 'from_addr')
22     to_addr = conf.getConf('email', 'to_addr').split(';') 
23     #发送邮件
24     host = conf.getConf('email', 'host')
25     port = conf.getConf('email', 'port')
26     user = conf.getConf('email', 'user')
27     password = conf.getConf('email', 'password')
28 
29 #测试文件=============================
30 #!/usr/bin/python
31 # coding=utf8
32 
33 from libs.email import *
34 from email.mime.text import MIMEText
35 from email.header import Header
36 
37 #构造邮件
38 msg = MIMEText('请大家自学Python...', 'plain', 'utf-8')  #邮件主体
39 #不赋值msg['Subject']、msg['From']、msg['To'],会导致出现554情况
40 msg['Subject'] = Header('请大家自学Python', 'utf-8')    #邮件标题
41 msg['From'] = email.from_addr  #发件人   
42 msg['To'] = ";".join(email.to_addr) #收件人
43   
44 import smtplib
45 #发送邮件
46 server = smtplib.SMTP() 
47 server.connect(email.host, int(email.port))  # 连接网易SMTP服务,默认端口号25
48 # server.set_debuglevel(1)    #打印与SMTP服务器交互的所有信息
49 server.login(email.from_addr, email.password)   #登录
50 server.sendmail(email.from_addr, email.to_addr, msg.as_string()) #发送邮件,传入msg
51 server.quit()
View Code

5.4 发送html邮件

msg = MIMEText('<html><a href="http://www.cnblogs.com/lizitest/">栗子自学Python</a></html>', 'html', 'utf-8')

注意:

  • 163不支持群发html邮件
  • 163邮箱需要<html>标签,其他邮箱没试过
 1 #配置文件================
 2 [email]
 3 #构造邮件
 4 from_addr=XXX@163.com
 5 to_addr=XXX@qq.com
 6 #发送邮件
 7 host=smtp.163.com
 8 port=25
 9 user=XXX@163.com
10 password=XXX
11 
12 #解析文件================
13 #!/usr/bin/env python
14 # coding=utf-8
15 
16 from libs.Configer import *
17 
18 class email(object):
19     conf = Configer("../config/email.conf")
20     #构造邮件
21     from_addr = conf.getConf('email', 'from_addr')
22     to_addr = conf.getConf('email', 'to_addr').split(';') 
23     #发送邮件
24     host = conf.getConf('email', 'host')
25     port = conf.getConf('email', 'port')
26     user = conf.getConf('email', 'user')
27     password = conf.getConf('email', 'password')
28 
29 #测试文件================
30 #!/usr/bin/python
31 # coding=utf8
32 
33 from libs.email import *
34 from email.mime.text import MIMEText
35 from email.header import Header
36 
37 #构造邮件
38 msg = MIMEText('<html><a href="http://www.cnblogs.com/lizitest/">栗子自学Python</a></html>', 'html', 'utf-8')
39 msg['Subject'] = Header('请大家自学Python', 'utf-8')    #邮件标题
40 msg['From'] = email.from_addr  #发件人   
41 msg['To'] = ";".join(email.to_addr) #收件人
42   
43 import smtplib
44 #发送邮件
45 server = smtplib.SMTP() 
46 server.connect(email.host, int(email.port))  # 连接网易SMTP服务,默认端口号25
47 server.set_debuglevel(1)    #打印与SMTP服务器交互的所有信息
48 server.login(email.from_addr, email.password)   #登录
49 server.sendmail(msg['From'], msg['To'], msg.as_string()) #发送邮件,传入msg
50 server.quit()
View Code

 5.5发送带附件的邮件

附件和文本均可以看作是邮件的一部分,先使用 MIMEMultipart 对象来表示邮件,再往邮件中添加正文和附件(MIMEText)

 1 #配置文件================
 2 [email]
 3 #构造邮件
 4 from_addr=XXX@163.com
 5 to_addr=XXX@qq.com
 6 #发送邮件
 7 host=smtp.163.com
 8 port=25
 9 user=XXX@163.com
10 password=XXX
11 
12 #解析文件================
13 #!/usr/bin/env python
14 # coding=utf-8
15 
16 from libs.Configer import *
17 
18 class email(object):
19     conf = Configer("../config/email.conf")
20     #构造邮件
21     from_addr = conf.getConf('email', 'from_addr')
22     to_addr = conf.getConf('email', 'to_addr').split(';') 
23     #发送邮件
24     host = conf.getConf('email', 'host')
25     port = conf.getConf('email', 'port')
26     user = conf.getConf('email', 'user')
27     password = conf.getConf('email', 'password')
28 
29 #测试文件================
30 #!/usr/bin/python
31 # coding=utf8
32 
33 from libs.email import *
34 from email.mime.multipart import MIMEMultipart
35 from email.mime.text import MIMEText
36 from email.header import Header
37 
38 #构造邮件
39 msg = MIMEMultipart()
40 msg['Subject'] = Header('请大家自学Python', 'utf-8')    #邮件标题
41 msg['From'] = email.from_addr  #发件人   
42 msg['To'] = ";".join(email.to_addr) #收件人
43 #添加正文
44 body = MIMEText('<html><a href="http://www.cnblogs.com/lizitest/">栗子自学Python</a></html>', 'html', 'utf-8')
45 msg.attach(body)
46 #添加附件1
47 att = MIMEText(open('../logs/selenium.log', 'rb').read(), 'base64', 'utf-8')  
48 att["Content-Type"] = 'application/octet-stream'  
49 att["Content-Disposition"] = 'attachment; filename="selenium.log"'  
50 msg.attach(att)  
51 #添加附件2
52 att = MIMEText(open('../logs/selenium.log.2017-03-30', 'rb').read(), 'base64', 'utf-8')  
53 att["Content-Type"] = 'application/octet-stream'  
54 att["Content-Disposition"] = 'attachment; filename="selenium.log.2017-03-30"'  
55 msg.attach(att) 
56   
57 import smtplib
58 #发送邮件
59 server = smtplib.SMTP() 
60 server.connect(email.host, int(email.port))  # 连接网易SMTP服务,默认端口号25
61 server.set_debuglevel(1)    #打印与SMTP服务器交互的所有信息
62 server.login(email.from_addr, email.password)   #登录
63 server.sendmail(msg['From'], msg['To'], msg.as_string()) #发送邮件,传入msg
64 server.quit()
View Code

 5.6 发送带图片附件的邮件

可以使用MIMEText进行发送,可以使用MIMEImage进行发送

 1 #配置文件================
 2 [email]
 3 #构造邮件
 4 from_addr=XXX@163.com
 5 to_addr=XXX@qq.com
 6 #发送邮件
 7 host=smtp.163.com
 8 port=25
 9 user=XXX@163.com
10 password=XXX
11 
12 #解析文件================
13 #!/usr/bin/env python
14 # coding=utf-8
15 
16 from libs.Configer import *
17 
18 class email(object):
19     conf = Configer("../config/email.conf")
20     #构造邮件
21     from_addr = conf.getConf('email', 'from_addr')
22     to_addr = conf.getConf('email', 'to_addr').split(';') 
23     #发送邮件
24     host = conf.getConf('email', 'host')
25     port = conf.getConf('email', 'port')
26     user = conf.getConf('email', 'user')
27     password = conf.getConf('email', 'password')
28 
29 #测试文件================
30 #!/usr/bin/python
31 # coding=utf8
32 
33 from libs.email import *
34 from email.mime.multipart import MIMEMultipart
35 from email.mime.text import MIMEText
36 from email.mime.image import MIMEImage
37 from email.header import Header
38 
39 #构造邮件
40 msg = MIMEMultipart()
41 msg['Subject'] = Header('请大家自学Python', 'utf-8')    #邮件标题
42 msg['From'] = email.from_addr  #发件人   
43 msg['To'] = ";".join(email.to_addr) #收件人
44 #添加正文
45 body = MIMEText('<html>' + 
46         '<a href="http://www.cnblogs.com/lizitest/">栗子自学Python</a>' +
47 #         '<p><img src="cid:report"></p>' +
48         '</html>', 'html', 'utf-8')
49 msg.attach(body)
50 #添加附件1
51 file1 = open('../logs/selenium.log', 'rb') 
52 att = MIMEText(file1.read(), 'base64', 'utf-8')
53 file1.close()  
54 att["Content-Type"] = 'application/octet-stream'  
55 att["Content-Disposition"] = 'attachment; filename="selenium.log"'  
56 msg.attach(att)  
57 #添加附件2
58 file2 = open('../logs/selenium.log.2017-03-30', 'rb') 
59 att = MIMEText(file2.read(), 'base64', 'utf-8')  
60 file2.close()  
61 att["Content-Type"] = 'application/octet-stream'  
62 att["Content-Disposition"] = 'attachment; filename="selenium.log.2017-03-30"'  
63 msg.attach(att) 
64 #添加图片附件1
65 file3 = open('../logs/report.jpg', 'rb')
66 msgImage = MIMEImage(file3.read()) 
67 file3.close()
68 msgImage.add_header('Content-ID', 'report') 
69 msg.attach(msgImage)
70 #添加图片附件2
71 #file3 = open('../logs/report.jpg', 'rb') 
72 #att = MIMEText(file3.read(), 'base64', 'utf-8')  
73 #file3.close()
74 # att["Content-Type"] = 'application/octet-stream'  
75 # att["Content-Disposition"] = 'attachment; filename="report"'  
76 # msg.attach(att) 
77   
78 import smtplib
79 #发送邮件
80 server = smtplib.SMTP() 
81 server.connect(email.host, int(email.port))  # 连接网易SMTP服务,默认端口号25
82 server.set_debuglevel(1)    #打印与SMTP服务器交互的所有信息
83 server.login(email.from_addr, email.password)   #登录
84 server.sendmail(msg['From'], msg['To'], msg.as_string()) #发送邮件,传入msg
85 server.quit()
View Code
原文地址:https://www.cnblogs.com/lizitest/p/6622274.html