python自动化测试之如何解析excel文件


Posted in Python onJune 27, 2019

前言

自动化测试中我们存放数据无非是使用文件或者数据库,那么文件可以是csv,xlsx,xml,甚至是txt文件,通常excel文件往往是我们的首选,无论是编写测试用例还是存放测试数据,excel都是很方便的。那么今天我们就把不同模块处理excel文件的方法做个总结,直接做封装,方便我们以后直接使用,增加工作效率。

openpyxl

openpyxl是个第三方库,首先我们使用命令 pip install openpyxl 直接安装

注:openpyxl操作excel时,行号和列号都是从1开始计算的

封装代码

"""
------------------------------------
@Time : 2019/5/13 18:00
@Auth : linux超
@File : ParseExcel.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
------------------------------------
"""
from openpyxl import load_workbook
from openpyxl.styles import Font
from openpyxl.styles.colors import BLACK
from collections import namedtuple


class ParseExcel(object):
"""解析excel文件"""

def __init__(self, filename, sheet_name=None):
try:
self.filename = filename
self.sheet_name = sheet_name
self.wb = load_workbook(self.filename)
if self.sheet_name is None:
self.work_sheet = self.wb.active
else:
self.work_sheet = self.wb[self.sheet_name]
except FileNotFoundError as e:
raise e

def get_max_row_num(self):
"""获取最大行号"""
max_row_num = self.work_sheet.max_row
return max_row_num

def get_max_column_num(self):
"""获取最大列号"""
max_column = self.work_sheet.max_column
return max_column

def get_cell_value(self, coordinate=None, row=None, column=None):
"""获取指定单元格的数据"""
if coordinate is not None:
try:
return self.work_sheet[coordinate].value
except Exception as e:
raise e
elif coordinate is None and row is not None and column is not None:
if isinstance(row, int) and isinstance(column, int):
return self.work_sheet.cell(row=row, column=column).value
else:
raise TypeError('row and column must be type int')
else:
raise Exception("Insufficient Coordinate of cell!")

def get_row_value(self, row):
"""获取某一行的数据"""
column_num = self.get_max_column_num()
row_value = []
if isinstance(row, int):
for column in range(1, column_num + 1):
values_row = self.work_sheet.cell(row, column).value
row_value.append(values_row)
return row_value
else:
raise TypeError('row must be type int')

def get_column_value(self, column):
"""获取某一列数据"""
row_num = self.get_max_column_num()
column_value = []
if isinstance(column, int):
for row in range(1, row_num + 1):
values_column = self.work_sheet.cell(row, column).value
column_value.append(values_column)
return column_value
else:
raise TypeError('column must be type int')

def get_all_value_1(self):
"""获取指定表单的所有数据(除去表头)"""
max_row_num = self.get_max_row_num()
max_column = self.get_max_column_num()
values = []
for row in range(2, max_row_num + 1):
value_list = []
for column in range(1, max_column + 1):
value = self.work_sheet.cell(row, column).value
value_list.append(value)
values.append(value_list)
return values

def get_all_value_2(self):
"""获取指定表单的所有数据(除去表头)"""
rows_obj = self.work_sheet.iter_rows(min_row=2, max_row=self.work_sheet.max_row,
values_only=True) # 指定values_only 会直接提取数据不需要再使用cell().value
values = []
for row_tuple in rows_obj:
value_list = []
for value in row_tuple:
value_list.append(value)
values.append(value_list)
return values

def get_excel_title(self):
"""获取sheet表头"""
title_key = tuple(self.work_sheet.iter_rows(max_row=1, values_only=True))[0]
return title_key

def get_listdict_all_value(self):
"""获取所有数据,返回嵌套字典的列表"""
sheet_title = self.get_excel_title()
all_values = self.get_all_value_2()
value_list = []
for value in all_values:
value_list.append(dict(zip(sheet_title, value)))
return value_list

def get_list_nametuple_all_value(self):
"""获取所有数据,返回嵌套命名元组的列表"""
sheet_title = self.get_excel_title()
values = self.get_all_value_2()

excel = namedtuple('excel', sheet_title)
value_list = []
for value in values:
e = excel(*value)
value_list.append(e)
return value_list
def write_cell(self, row, column, value=None, bold=True, color=BLACK):
"""
指定单元格写入数据
:param work_sheet:
:param row: 行号
:param column: 列号
:param value: 待写入数据
:param bold: 加粗, 默认加粗
:param color: 字体颜色,默认黑色
:return:
"""
try:
if isinstance(row, int) and isinstance(column, int):
cell_obj = self.work_sheet.cell(row, column)
cell_obj.font = Font(color=color, bold=bold)
cell_obj.value = value
self.wb.save(self.filename)
else:
raise TypeError('row and column must be type int')
except Exception as e:
raise e
if __name__ == '__main__':
pe = ParseExcel('testdata.xlsx')
# sheet = pe.get_sheet_object('testcase')
column_row = pe.get_max_column_num()
print('最大列号:', column_row)
max_row = pe.get_max_row_num()
print('最大行号:', max_row)
#
cell_value_1 = pe.get_cell_value(row=2, column=3)
print('第%d行, 第%d列的数据为: %s' % (2, 3, cell_value_1))
cell_value_2 = pe.get_cell_value(coordinate='A5')
print('A5单元格的数据为: {}'.format(cell_value_2))
value_row = pe.get_row_value(3)
print('第{}行的数据为:{}'.format(3, value_row))
value_column = pe.get_column_value(2)
print('第{}列的数据为:{}'.format(2, value_column))
#
values_1 = pe.get_all_value_1()
print('第一种方式获取所有数据\n', values_1)
values_2 = pe.get_all_value_2()
print('第二种方式获取所有数据\n', values_2)
title = pe.get_excel_title()
print('表头为\n{}'.format(title))
dict_value = pe.get_listdict_all_value()
print('所有数据组成的嵌套字典的列表:\n', dict_value)
#
namedtuple_value = pe.get_list_nametuple_all_value()
print('所有数据组成的嵌套命名元组的列表:\n', namedtuple_value)
pe.write_cell(1, 2, 'Tc_title')

# add by linux超 at 2019/05/22 15:58

上面这个封装如如果用来同时操作同一个excel文件的两个sheet写入数据时,会有点小bug(写完后你会发现两个表单有一个是没有数据的)

其实原因很简单:不同对象拥有自己独立的属性, 当你写操作的时候其实每个对象只针对自己的表单做了保存,所以最后一个对象写完数据后,只保存了自己的表单,其他的对象的表单实际是没有保存的。针对这个问题,对上面封装的代码进行了轻微改动

"""
------------------------------------
@Time : 2019/5/22 9:11
@Auth : linux超
@File : ParseExcel.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
------------------------------------
"""
from openpyxl import load_workbook
from openpyxl.styles import Font
from openpyxl.styles.colors import BLACK
from collections import namedtuple
class ParseExcel(object):
"""解析excel文件"""
def __init__(self, filename):
try:
self.filename = filename
self.__wb = load_workbook(self.filename)
except FileNotFoundError as e:
raise e
def get_max_row_num(self, sheet_name):
"""获取最大行号"""
max_row_num = self.__wb[sheet_name].max_row
return max_row_num
def get_max_column_num(self, sheet_name):
"""获取最大列号"""
max_column = self.__wb[sheet_name].max_column
return max_column
def get_cell_value(self, sheet_name, coordinate=None, row=None, column=None):
"""获取指定单元格的数据"""
if coordinate is not None:
try:
return self.__wb[sheet_name][coordinate].value
except Exception as e:
raise e
elif coordinate is None and row is not None and column is not None:
if isinstance(row, int) and isinstance(column, int):
return self.__wb[sheet_name].cell(row=row, column=column).value
else:
raise TypeError('row and column must be type int')
else:
raise Exception("Insufficient Coordinate of cell!")
def get_row_value(self, sheet_name, row):
"""获取某一行的数据"""
column_num = self.get_max_column_num(sheet_name)
row_value = []
if isinstance(row, int):
for column in range(1, column_num + 1):
values_row = self.__wb[sheet_name].cell(row, column).value
row_value.append(values_row)
return row_value
else:
raise TypeError('row must be type int')
def get_column_value(self, sheet_name, column):
"""获取某一列数据"""
row_num = self.get_max_column_num(sheet_name)
column_value = []
if isinstance(column, int):
for row in range(1, row_num + 1):
values_column = self.__wb[sheet_name].cell(row, column).value
column_value.append(values_column)
return column_value
else:
raise TypeError('column must be type int')
def get_all_value_1(self, sheet_name):
"""获取指定表单的所有数据(除去表头)"""
max_row_num = self.get_max_row_num(sheet_name)
max_column = self.get_max_column_num(sheet_name)
values = []
for row in range(2, max_row_num + 1):
value_list = []
for column in range(1, max_column + 1):
value = self.__wb[sheet_name].cell(row, column).value
value_list.append(value)
values.append(value_list)
return values
def get_all_value_2(self, sheet_name):
"""获取指定表单的所有数据(除去表头)"""
rows_obj = self.__wb[sheet_name].iter_rows(min_row=2, max_row=self.__wb[sheet_name].max_row, values_only=True)
values = []
for row_tuple in rows_obj:
value_list = []
for value in row_tuple:
value_list.append(value)
values.append(value_list)
return values
def get_excel_title(self, sheet_name):
"""获取sheet表头"""
title_key = tuple(self.__wb[sheet_name].iter_rows(max_row=1, values_only=True))[0]
return title_key
def get_listdict_all_value(self, sheet_name):
"""获取所有数据,返回嵌套字典的列表"""
sheet_title = self.get_excel_title(sheet_name)
all_values = self.get_all_value_2(sheet_name)
value_list = []
for value in all_values:
value_list.append(dict(zip(sheet_title, value)))
return value_list
def get_list_nametuple_all_value(self, sheet_name):
"""获取所有数据,返回嵌套命名元组的列表"""
sheet_title = self.get_excel_title(sheet_name)
values = self.get_all_value_2(sheet_name)
excel = namedtuple('excel', sheet_title)
value_list = []
for value in values:
e = excel(*value)
value_list.append(e)
return value_list
def write_cell(self, sheet_name, row, column, value=None, bold=True, color=BLACK):
if isinstance(row, int) and isinstance(column, int):
try:
cell_obj = self.__wb[sheet_name].cell(row, column)
cell_obj.font = Font(color=color, bold=bold)
cell_obj.value = value
self.__wb.save(self.filename)
except Exception as e:
raise e
else:
raise TypeError('row and column must be type int')
if __name__ == '__main__':
pe = ParseExcel('testdata.xlsx')
print(pe.get_all_value_2('division'))
print(pe.get_list_nametuple_all_value('division'))
column_row = pe.get_max_column_num('division')
print('最大列号:', column_row)
max_row = pe.get_max_row_num('division')
print('最大行号:', max_row)
cell_value_1 = pe.get_cell_value('division', row=2, column=3)
print('第%d行, 第%d列的数据为: %s' % (2, 3, cell_value_1))
cell_value_2 = pe.get_cell_value('division', coordinate='A5')
print('A5单元格的数据为: {}'.format(cell_value_2))
value_row = pe.get_row_value('division', 3)
print('第{}行的数据为:{}'.format(3, value_row))
value_column = pe.get_column_value('division', 2)
print('第{}列的数据为:{}'.format(2, value_column))
values_1 = pe.get_all_value_1('division')
print('第一种方式获取所有数据\n', values_1)
values_2 = pe.get_all_value_2('division')
print('第二种方式获取所有数据\n', values_2)
title = pe.get_excel_title('division')
print('表头为\n{}'.format(title))
dict_value = pe.get_listdict_all_value('division')
print('所有数据组成的嵌套字典的列表:\n', dict_value)
namedtuple_value = pe.get_list_nametuple_all_value('division')
print('所有数据组成的嵌套命名元组的列表:\n', namedtuple_value)
pe.write_cell('division', 1, 2, 'Tc_title')

xlrd

安装xlrd,此模块只支持读操作, 如果要写需要使用xlwt或者使用xlutils配合xlrd, 但是使用xlwt只能对新的excel文件进行写操作,无法对原有文件进行写, 所以这里选择是用xlutils

但是还有一个问题就是,如果使用xlutils, 那么我们的excel文件需要以.xls 为后缀。因为以xlsx为后缀无法实现写,会报错(亲测,因为formatting_info参数还没有对新版本的xlsx的格式完成兼容)

注:xlrd操作excel时,行号和列号都是从0开始计算的

封装代码

"""
------------------------------------
@Time : 2019/5/13 21:22
@Auth : linux超
@File : ParseExcel_xlrd.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
------------------------------------
"""
import xlrd
from xlutils import copy
from collections import namedtuple

class ParseExcel(object):
# xlrd 解析excel, 行号和列号都是从0开始的
def __init__(self, filename, sheet):
try:
self.filename = filename
self.sheet = sheet
self.wb = xlrd.open_workbook(self.filename, formatting_info=True)
if isinstance(sheet, str):
self.sheet = self.wb.sheet_by_name(sheet)
elif isinstance(sheet, int):
self.sheet = self.wb.sheet_by_index(sheet)
else:
raise TypeError('sheet must be int or str')
except Exception as e:
raise e

def get_max_row(self):
"""获取表单的最大行号"""
max_row_num = self.sheet.nrows
return max_row_num

def get_max_column(self):
"""获取表单的最大列号"""
min_row_num = self.sheet.ncols
return min_row_num

def get_cell_value(self, row, column):
"""获取某个单元格的数据"""
if isinstance(row, int) and isinstance(column, int):
values = self.sheet.cell(row-1, column-1).value
return values
else:
raise TypeError('row and column must be type int')

def get_row_values(self, row):
"""获取某一行的数据"""
if isinstance(row, int):
values = self.sheet.row_values(row-1)
return values
else:
raise TypeError('row must be type int')

def get_column_values(self, column):
"""获取某一列的数据"""

if isinstance(column, int):
values = self.sheet.col_values(column-1)
return values
else:
raise TypeError('column must be type int')

def get_table_title(self):
"""获取表头"""
table_title = self.get_row_values(1)
return table_title

def get_all_values_dict(self):
"""获取所有的数据,不包括表头,返回一个嵌套字典的列表"""
max_row = self.get_max_row()
table_title = self.get_table_title()
value_list = []
for row in range(2, max_row):
values = self.get_row_values(row)
value_list.append(dict(zip(table_title, values)))
return value_list

def get_all_values_nametuple(self):
"""获取所有的数据,不包括表头,返回一个嵌套命名元组的列表"""
table_title = self.get_table_title()
max_row = self.get_max_row()
excel = namedtuple('excel', table_title)
value_list = []
for row in range(2, max_row):
values = self.get_row_values(row)
e = excel(*values)
value_list.append(e)
return value_list

def write_value(self, sheet_index, row, column, value):
"""写入某个单元格数据"""
if isinstance(row, int) and isinstance(column, int):
if isinstance(sheet_index, int):
wb = copy.copy(self.wb)
worksheet = wb.get_sheet(sheet_index)
worksheet.write(row-1, column-1, value)
wb.save(self.filename)
else:
raise TypeError('{} must be int'.format(sheet_index))
else:
raise TypeError('{} and {} must be int'.format(row, column))

if __name__ == '__main__':
pe = ParseExcel('testdata.xls', 'testcase')
print('最大行号:', pe.get_max_row())
print('最大列号:', pe.get_max_column())
print('第2行第3列数据:', pe.get_cell_value(2, 3))
print('第2行数据', pe.get_row_values(2))
print('第3列数据', pe.get_column_values(3))
print('表头:', pe.get_table_title())
print('所有的数据返回嵌套字典的列表:', pe.get_all_values_dict())
print('所有的数据返回嵌套命名元组的列表:', pe.get_all_values_nametuple())
 pe.write_value(0, 1, 3, 'test')

pandas

pandas是一个做数据分析的库, 总是感觉在自动化测试中使用pandas解析excel文件读取数据有点大材小用,不论怎样吧,还是把pandas解析excel文件写一下把

我这里只封装了读,写的话我这有点小问题,后面改好再追加代码吧。

请先pip install pandas安装pandas

封装代码

"""
------------------------------------
@Time : 2019/5/13 14:00
@Auth : linux超
@File : ParseExcel_pandas.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
------------------------------------
"""
import pandas as pd


class ParseExcel(object):
def __init__(self, filename, sheet_name=None):
try:
self.filename = filename
self.sheet_name = sheet_name
self.df = pd.read_excel(self.filename, self.sheet_name)
except Exception as e:
raise e

def get_row_num(self):
"""获取行号组成的列表, 从0开始的"""
row_num_list = self.df.index.values
return row_num_list

def get_cell_value(self, row, column):
"""获取某一个单元格的数据"""
try:
if isinstance(row, int) and isinstance(column, int):
cell_value = self.df.ix[row-2, column-1] # ix的行参数是按照有效数据行,且从0开始
return cell_value
else:
raise TypeError('row and column must be type int')
except Exception as e:
raise e

def get_table_title(self):
"""获取表头, 返回列表"""
table_title = self.df.columns.values
return table_title

def get_row_value(self, row):
"""获取某一行的数据, 行号从1开始"""
try:
if isinstance(row, int):
row_data = self.df.ix[row-2].values
return row_data
else:
raise TypeError('row must be type int')
except Exception as e:
raise e

def get_column_value(self, col_name):
"""获取某一列数据"""
try:
if isinstance(col_name, str):
col_data = self.df[col_name].values
return col_data
else:
raise TypeError('col_name must be type str')
except Exception as e:
raise e
def get_all_value(self):
"""获取所有的数据,不包括表头, 返回嵌套字典的列表"""
rows_num = self.get_row_num()
table_title = self.get_table_title()
values_list = []
for i in rows_num:
row_data = self.df.ix[i, table_title].to_dict()
values_list.append(row_data)
return values_list
if __name__ == '__main__':
pe = ParseExcel('testdata.xlsx', 'testcase')
print(pe.get_row_num())
print(pe.get_table_title())
print(pe.get_all_value())
print(pe.get_row_value(2))
print(pe.get_cell_value(2, 3))
print(pe.get_column_value('Tc_title'))

总结

使用了3种方法,4个库 xlrd,openpyxl,xlwt,pandas 操作excel文件,个人感觉还是使用openpyxl比较适合在自动化中使用,当然不同人有不同选择,用哪个区别也不是很大。

以上3种方法,都可以拿来直接使用,不需要再做封装了 !

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python编程中的反模式实例分析
Dec 08 Python
python使用socket进行简单网络连接的方法
Apr 29 Python
Python中selenium实现文件上传所有方法整理总结
Apr 01 Python
老生常谈进程线程协程那些事儿
Jul 24 Python
python操作列表的函数使用代码详解
Dec 28 Python
浅谈pytorch grad_fn以及权重梯度不更新的问题
Aug 20 Python
Python 使用 Pillow 模块给图片添加文字水印的方法
Aug 30 Python
python实现超市商品销售管理系统
Oct 25 Python
查看端口并杀进程python脚本代码
Dec 17 Python
如何在django中添加日志功能
Feb 06 Python
python求解汉诺塔游戏
Jul 09 Python
Python中Selenium对Cookie的操作方法
Jul 09 Python
python算法与数据结构之单链表的实现代码
Jun 27 #Python
python多线程并发实例及其优化
Jun 27 #Python
int在python中的含义以及用法
Jun 27 #Python
Pycharm运行加载文本出现错误的解决方法
Jun 27 #Python
基于python-opencv3的图像显示和保存操作
Jun 27 #Python
pycharm new project变成灰色的解决方法
Jun 27 #Python
python之mock模块基本使用方法详解
Jun 27 #Python
You might like
php函数与传递参数实例分析
2014/11/15 PHP
Thinkphp调用Image类生成缩略图的方法
2015/03/07 PHP
PHP输出一个等腰三角形的方法
2015/05/12 PHP
PHP入门教程之自定义函数用法详解(创建,调用,变量,参数,返回值等)
2016/09/11 PHP
CakePHP框架Session设置方法分析
2017/02/23 PHP
javascript innerHTML、outerHTML、innerText、outerText的区别
2008/11/24 Javascript
javascript 实用的文字链提示框效果
2010/06/30 Javascript
谈谈JavaScript中的函数与闭包
2013/04/14 Javascript
DOM基础教程之事件对象
2015/01/20 Javascript
JS控制表格实现一条光线流动分割行的方法
2015/03/09 Javascript
js/jquery判断浏览器类型的方法小结
2015/05/12 Javascript
jQuery基于扩展实现的倒计时效果
2016/05/14 Javascript
JavaScript简单获取系统当前时间完整示例
2016/08/02 Javascript
微信小程序 location API实例详解
2016/10/02 Javascript
微信小程序 欢迎页面的制作(源码下载)
2017/01/09 Javascript
javascript内存分配原理实例分析
2017/04/10 Javascript
详解如何将angular-ui的图片轮播组件封装成一个指令
2017/05/09 Javascript
vue router仿天猫底部导航栏功能
2017/10/18 Javascript
sublime text配置node.js调试(图文教程)
2017/11/23 Javascript
vue项目部署到Apache服务器中遇到的问题解决
2018/08/24 Javascript
Python SQLite3数据库操作类分享
2014/06/10 Python
Python Sleep休眠函数使用简单实例
2015/02/02 Python
不可错过的十本Python好书
2017/07/06 Python
Python实现解析Bit Torrent种子文件内容的方法
2017/08/29 Python
pytorch permute维度转换方法
2018/12/14 Python
把pandas转换int型为str型的方法
2019/01/29 Python
python做反被爬保护的方法
2019/07/01 Python
Python selenium 自动化脚本打包成一个exe文件(推荐)
2020/01/14 Python
Python中的sys.stdout.write实现打印刷新功能
2020/02/21 Python
WEB控件可以激发服务端事件,请谈谈服务端事件是怎么发生并解释其原理?自动传回是什么?为什么要使用自动传回?
2012/02/21 面试题
金融管理专业毕业生求职信
2014/03/12 职场文书
信息工作经验交流材料
2014/05/28 职场文书
好听的队名和口号
2014/06/09 职场文书
幼儿园教师节演讲稿
2014/09/03 职场文书
2015年信贷员工作总结
2015/04/28 职场文书
财务管理制度范本
2015/08/04 职场文书