目录:
一、xlrd与xlwt读写excel文件
(一)xlrd涉及到的属性与方法
(二)xlrd使用实例
(三)xlutils模块写入excel
(四)综合实例(一)
(五)综合实例二(解决实例一的缺陷)
二、pandas读写excel
(一)pandas读取excel
(二)pandas写入excel
二、openpyxl读写excel
(一)openpyxl读取excel
1.openpyxl读取单元格内容
2.openpyxl读取整列内容
(二)openpyxl写入excel
前言:
前面分享了使用数据驱动结合CSV文件的相关文章,现在本篇分享结合excel的数据驱动。
本篇将使用两种方法来读写excel,需要安装相应的模块,其他与示例相关的模块,可以看示例导入什么模块,没有就安装。
excel读写方法一安装模块:xlrd,xlutils
excel读写方法二安装模块:pandas
excel读写方法三安装模块:openpyxl
一、xlrd与xlwt读写excel文件
说明:此方法只能读写以“.xls”结尾的excel文件,也就是相对老版本的文件,所以准备数据时需要注意文件的尾缀。
(一)xlrd涉及到的属性与方法
第一级:打开文件
- open_workbook() 打开文件,所有后续操作的前提,需要参数:文件名
第二级:打开表单的方法: - sheet_by_index() 通过索引数字打开表单,需要参数:索引号。
- sheets() 获取所有表单,返回的是一个表单列表,需要通过列表索引访问。
- sheet_by_name() 通过表单名访问表单,需要参数:表单名
第三级:读取行列的方法:
- row(行号) 读取行数据,数据类型为列表,样式为,单元格类型:值
- col_values(colx,start_rowx=0, end_rowx=None)
若读取整列,只需要行号 colx,直到读取完所有数据(模块自动识别);
若需要从指定行开始读取,需要设置参数start_rowx=行号
若需要到指定行结束读取,需要设置参数end_rowx=行号
第三级:行列的属性
- ncols 列数
- nrows 行数
(二)xlrd使用实例
1.简单用法
import xlrd,xlwt
import pandas
#打印第一张表的第一
text1=xlrd.open_workbook('CVS数据表.xls').sheet_by_index(1).row(0)
#返回单元格类型+内容
print("序号:1")
print(text1)
#通过表名的索引,打印第一张表的第一列
text=xlrd.open_workbook('CVS数据表.xls').sheet_by_index(0).col_values(0)
print("序号:2")
print(text)
#打印第一张表的第一列,通过sheets()加索引方式,为前面一种方法的原始版,前面的相当于封装过的,推介使用前面一种
text=xlrd.open_workbook('CVS数据表.xls').sheets()[0].col_values(0)
print("序号:3")
print(text)
#通过表名访问表单
text=xlrd.open_workbook('CVS数据表.xls').sheet_by_name('Sheet1').col_values(0)
print("序号:4")
print(text)
结果:
2.xlrd实际使用中常用方法
接续前面的内容,在读取内容时,最重要的两点是跳过首行读取数据,和获取行数
import xlrd,xlwt
#读取第二张表的第一列,从第二行开始
text=xlrd.open_workbook('CVS数据表.xls').sheet_by_name('Sheet2').col_values(0,start_rowx=1)
print(text)
#一般用在循环中
#获取列数
cols_account=xlrd.open_workbook('CVS数据表.xls').sheet_by_name('Sheet2').ncols
print(cols_account)
#获取行数
rows_account=xlrd.open_workbook('CVS数据表.xls').sheet_by_name('Sheet2').nrows
print(rows_account)
3.封装xlrd读取excel
def read_excel(filename,sheet_index,col_num):
import xlrd, xlwt
#跳过首行
text=xlrd.open_workbook(filename).sheet_by_index(sheet_index).col_values(col_num,start_rowx=1)
#必须要有返回值,没有返回值,调用函数得到的是空值
return text
write_excel('CVS数据表.xls',1,0)
(三)xlutils模块写入excel
import xlrd
from xlutils.copy import copy
#xlrd模块打开表格
book=xlrd.open_workbook('CVS数据表.xls')
#xlutils的copy文件的copy方法复制一个表,用于实际操作
book_copy=copy(book)
#copy到的对象获取表单
sheet=book_copy.get_sheet(1)
#写入指定表单单元格:write(行号,列号,要写入的内容)
sheet.write(1,1,'pass')
#保存写入的内容,这不能漏掉,不然白写了
book_copy.save('CVS数据表.xls')
封装方法,方便后续调用:
def write_excel(filename,sheet_index,row_num,col_num,content):
from xlutils.copy import copy
import xlrd
book=xlrd.open_workbook(filename)
book_copy=copy(book)
sheet=book_copy.get_sheet(sheet_index)
sheet.write(row_num,col_num,content)
book_copy.save(filename)
#下面只是为了看的更直观,实际可以直接按顺序写入数据
write_excel(filename='CVS数据表.xls',sheet_index=1,row_num=2,col_num=1,content='pass')
(四)综合实例(一)
原创内容:
由于使用Unittest结合数据驱动会自动读取数据,并重复执行,所以想要得到一个和取得数据相同的索引比较困难,所以需要改进代码。
思路:由于我们读取到的数据是一个列表,那么我们可以获取列表内数据的索引,当取一个数据时得到一个索引。但我们写的读取数据去掉了首行,所以最后在使用索引时需要+1才能匹配上。
缺陷:当列表内存在重复的数据时,会返回第一个出现的索引,所以不能用于列表数据有重复值的场合,比如注册测试。改进方法可以看(五)
from selenium import webdriver
import unittest,time
from ddt import ddt,data,unpack
def write_excel(filename,sheet_index,row_num,col_num,content):
from xlutils.copy import copy
import xlrd
book=xlrd.open_workbook(filename)
book_copy=copy(book)
sheet=book_copy.get_sheet(sheet_index)
sheet.write(row_num,col_num,content)
book_copy.save(filename)
def read_excel(filename,sheet_index,col_num):
import xlrd, xlwt
#跳过首行
text=xlrd.open_workbook(filename).sheet_by_index(sheet_index).col_values(col_num,start_rowx=1)
return text
search_data=read_excel('CVS数据表.xls',1,0)
print(search_data)
#使用装饰器,表明该测试集采用ddt驱动
@ddt
#使用unittest必须先使用class定义一个类,且以Test开头,并继承unittest.TestCase
class Testbaidu_search(unittest.TestCase):
# 必须使用@classmethod装饰器,这是使用tearDownClass与setUpClass的基本要求
#setUpClass表示下面的代码Testbaidu_search测试集只会在开始时运行一次
@classmethod
def setUpClass(cls) -> None:
global driver
driver=webdriver.Chrome()
driver.get('https://www.baidu.com/')
#data取数据,如果传入的是一个变量接收的数据集,那么需要在变量前面加*
@data(*search_data)
#unpack解压数据包
# @unpack
#由于只有一个变量,在测试用例用中,加入一个变量名,用于接收解压到的数据,针对多个的情况后面再详细说明
def test_search(self,value):
"""
非常重要的核心:
由于使用Unittest结合数据驱动会自动读取数据,并重复执行,所以想要得到一个和取得数据相同的索引比较困难.
由于我们读取到的数据是一个列表,那么我们可以获取列表内数据的索引,当取一个数据时得到一个索引。
但我们写的读取数据去掉了首行,所以最后在使用索引时需要+1才能匹配上
:param value:
:return:
"""
i=search_data.index(value)
print(i)
driver.find_element_by_id('kw').send_keys(value)
text=driver.find_element_by_id('kw').get_attribute('value')
driver.find_element_by_id('su').click()
time.sleep(3)
driver.find_element_by_id('kw').clear()
if text in ['孔子','孟子']:
write_excel(filename='CVS数据表.xls', sheet_index=1, row_num=i+1, col_num=1, content='pass')
else:
write_excel(filename='CVS数据表.xls',sheet_index=1,row_num=i+1,col_num=1,content='unpass')
#原创内容,转载请注明出处,有用请点赞
@classmethod
# tearDownClass表示下面的代码Testbaidu_search测试集只会在结束时运行一次
def tearDownClass(cls) -> None:
driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
(五)综合实例二(解决实例一的缺陷)
原创内容:
思路:
观察测试运行结果,每次运行之后,产生的用例会有一个名字,并且里面有一个不重复的序号,那么我们可以想办法获取这个数字。
查看unittest.TestCase的方法中有一个id方法,返回运行用例的名称,也就是Test Results下的全部完整路径。但是这个方法只能在用例里面调用才能得到当前运行用例的名称,结果类型为字符串。然后进行字符串提取,并进行类型转换(int型)。
图片是因为selenium访问百度太频繁了,必须要验证才能继续访问导致的。
定义成方法,只是好看一点:
def get_case_num():
import re
case_name = unittest.TestCase.id(self)
pattern = '.*_+(\d{1,3})_+'
case_num = int(re.findall(pattern, case_name)[0])
return case_num
i=get_case_num()
#后面引用i,就不用+1了,因为用例就是以1开头的。
完整代码:
from selenium import webdriver
import unittest,time
from ddt import ddt,data,unpack
def write_excel(filename,sheet_index,row_num,col_num,content):
from xlutils.copy import copy
import xlrd
book=xlrd.open_workbook(filename)
book_copy=copy(book)
sheet=book_copy.get_sheet(sheet_index)
sheet.write(row_num,col_num,content)
book_copy.save(filename)
def read_excel(filename,sheet_index,col_num):
import xlrd, xlwt
#跳过首行
text=xlrd.open_workbook(filename).sheet_by_index(sheet_index).col_values(col_num,start_rowx=1)
return text
search_data=read_excel('CVS数据表.xls',1,0)
print(search_data)
#使用装饰器,表明该测试集采用ddt驱动
@ddt
#使用unittest必须先使用class定义一个类,且以Test开头,并继承unittest.TestCase
class Testbaidu_search(unittest.TestCase):
# 必须使用@classmethod装饰器,这是使用tearDownClass与setUpClass的基本要求
#setUpClass表示下面的代码Testbaidu_search测试集只会在开始时运行一次
@classmethod
def setUpClass(cls) -> None:
global driver
driver=webdriver.Chrome()
driver.get('https://www.baidu.com/')
#data取数据,如果传入的是一个变量接收的数据集,那么需要在变量前面加*
@data(*search_data)
#unpack解压数据包
# @unpack
#由于只有一个变量,在测试用例用中,加入一个变量名,用于接收解压到的数据,针对多个的情况后面再详细说明
def test_search(self,value):
print(search_data)
"""
非常重要的核心:
由于使用Unittest结合数据驱动会自动读取数据,并重复执行,所以想要得到一个和取得数据相同的索引比较困难.
由于我们读取到的数据是一个列表,那么我们可以获取列表内数据的索引,当取一个数据时得到一个索引。
但我们写的读取数据去掉了首行,所以最后在使用索引时需要+1才能匹配上
:param value:
:return:
"""
def get_case_num():
import re
case_name = unittest.TestCase.id(self)
pattern = '.*_+(\d{1,3})_+'
case_num = int(re.findall(pattern, case_name)[0])
return case_num
i=get_case_num()
driver.find_element_by_id('kw').send_keys(value)
text=driver.find_element_by_id('kw').get_attribute('value')
driver.find_element_by_id('su').click()
time.sleep(3)
driver.find_element_by_id('kw').clear()
if text in ['孔子','孟子']:
write_excel(filename='CVS数据表.xls', sheet_index=1, row_num=i, col_num=1, content='pass')
else:
write_excel(filename='CVS数据表.xls',sheet_index=1,row_num=i,col_num=1,content='unpass')
#原创内容,转载请注明出处,有用请点赞
@classmethod
# tearDownClass表示下面的代码Testbaidu_search测试集只会在结束时运行一次
def tearDownClass(cls) -> None:
driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
二、pandas读写excel
(一)pandas读取excel
def read_excel_pandas(filename,sheet_name,col_name):
import pandas as pd
#pandas可以直接根据读取到的列名,得到到想要列的数据,为pandas数据类型,可以通过列表索引访问列的内容
excel_data=pd.read_excel(filename,sheet_name)[col_name]
#需要转换为list,才是我们需要的可迭代对象
return list(excel_data)
(二)pandas写入excel
查看源代码,发现to_excel方法没有读写模式控制,不能像csv一样在新表中进行追加,写一次数据,就覆盖了整个表,不能达到我们的要请求
如下代码,若start_row不断进行迭代,最终文件中只有最后一行的数据,如果想要使用pandas达到想要的效果,需要结合其他openpyxl库,这方面,暂时还未进行学习总结。
def write_excel_pandas(filename,sheet_name,col_text,result,start_col,start_row):
import pandas as pd
#简单测试输入框,只有两个字段,一个是输入内容,一个接收结果
data_dic = {
'name': col_text,
'result': result
}
#index=[0]必须写,不然会报错,我目前是这样的
excel_data = pd.DataFrame(data=data_dic, index=[0])
#mode='a'为追加模式,这种不停写入旧文件一般都用追加,不会覆盖原来的内容
# header=False,不会在写入数据时添加首行标题,否则结果看起来会很乱
excel_data.to_excel(filename,sheet_name=sheet_name, startcol=start_col,startrow=start_row,index=False,header=False,encoding='utf-8')
附源码:
from selenium import webdriver
import unittest,time
from ddt import ddt,data,unpack
def read_excel_pandas(filename,sheet_name,col_name):
import pandas as pd
excel_data=pd.read_excel(filename,sheet_name)[col_name]
return list(excel_data)
def write_excel_pandas(filename,sheet_name,col_text,result,start_col,start_row):
import pandas as pd
#简单测试输入框,只有两个字段,一个是输入内容,一个接收结果
data_dic = {
'name': col_text,
'result': result
}
#index=[0]必须写,不然会报错,我目前是这样的
excel_data = pd.DataFrame(data=data_dic, index=[0])
#mode='a'为追加模式,这种不停写入旧文件一般都用追加,不会覆盖原来的内容
# header=False,不会在写入数据时添加首行标题,否则结果看起来会很乱
excel_data.to_excel(filename,sheet_name=sheet_name, startcol=start_col,startrow=start_row,index=False,header=False,encoding='utf-8')
search_data=read_excel_pandas('CVS数据表.xls','Sheet1','name')
print(search_data)
#使用装饰器,表明该测试集采用ddt驱动
@ddt
#使用unittest必须先使用class定义一个类,且以Test开头,并继承unittest.TestCase
class Testbaidu_search(unittest.TestCase):
# 必须使用@classmethod装饰器,这是使用tearDownClass与setUpClass的基本要求
#setUpClass表示下面的代码Testbaidu_search测试集只会在开始时运行一次
@classmethod
def setUpClass(cls) -> None:
global driver
driver=webdriver.Chrome()
driver.get('https://www.baidu.com/')
#data取数据,如果传入的是一个变量接收的数据集,那么需要在变量前面加*
@data(*search_data)
#unpack解压数据包
# @unpack
#由于只有一个变量,在测试用例用中,加入一个变量名,用于接收解压到的数据,针对多个的情况后面再详细说明
def test_search(self,value):
print(search_data)
"""
非常重要的核心:
由于使用Unittest结合数据驱动会自动读取数据,并重复执行,所以想要得到一个和取得数据相同的索引比较困难.
由于我们读取到的数据是一个列表,那么我们可以获取列表内数据的索引,当取一个数据时得到一个索引。
但我们写的读取数据去掉了首行,所以最后在使用索引时需要+1才能匹配上
:param value:
:return:
"""
def get_case_num():
import re
case_name = unittest.TestCase.id(self)
pattern = '.*_+(\d{1,3})_+'
case_num = int(re.findall(pattern, case_name)[0])
return case_num
row_num=get_case_num()
driver.find_element_by_id('kw').send_keys(value)
text=driver.find_element_by_id('kw').get_attribute('value')
driver.find_element_by_id('su').click()
time.sleep(3)
driver.find_element_by_id('kw').clear()
if text in ['孔子','孟子']:
write_excel_pandas('CVS数据表2.xls','Sheet2',value,'pass',start_col=0,start_row=row_num)
else:
write_excel_pandas('CVS数据表2.xls','Sheet2',value,'unpass',start_col=0,start_row=row_num)
#原创内容,转载请注明出处,有用请点赞
@classmethod
# tearDownClass表示下面的代码Testbaidu_search测试集只会在结束时运行一次
def tearDownClass(cls) -> None:
driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
三、openpyxl读写excel
注意:
openpyxl只能读写“.xlsx”尾缀的excel文件,不能读写“.xls”
(一)openpyxl读取excel数据
1.读取指定单元格
def read_excel_openpyxl(filename,sheet_name,row_num,col_num):
from openpyxl import load_workbook
"""
注意,必须是.xlsx结尾的文件才能被操作,而且不能是被重命名未知的文件
:param filename:
:param sheet_name:
:return:
"""
book=load_workbook(filename)
#由于默认激活的是第一张sheet,因此需要book.active=book[sheet_name]定义需要激活名称的sheet
ws=book.active=book[sheet_name]
data=ws.cell(row_num,col_num)
book.save(filename)
return data.value
2.读取整列
def read_excel_openpyxl_col(filename,sheet_name,col_name):
"""
去除首行读取列,需要读取首行,就将row+1改为row
:param filename:
:param sheet_name: 如Sheet1
:param col_name: 如A,B列
:return:
"""
from openpyxl import load_workbook
wb = load_workbook(filename = filename)
sheet_ranges = wb[sheet_name]
col_content=sheet_ranges[col_name]
content=[]
for row in range(len(col_content)-1):
content.append(col_content[row+1].value)
return content
(二)openpyxl写入excel
def write_excel_openpyxl(filename,sheet_name,row_num,col_num,value):
from openpyxl import load_workbook
"""
注意,必须是.xlsx结尾的文件才能被操作,而且不能是被重命名未知的文件
:param filename:
:param sheet_name:
:return:
"""
book=load_workbook(filename)
#由于默认激活的是第一张sheet,因此需要book.active=book[sheet_name]定义需要激活名称的sheet
ws=book.active=book[sheet_name]
data=ws.cell(row_num,col_num,value)
book.save(filename)
print(data.value)
(三)实例
实例就不写了,和前面一样,只是将读写的函数修改以下就行
原创内容,转载请注明出处,有用请点赞!!!!