python中使用xlrd、xlwt操作excel表格详解


Posted in Python onJanuary 29, 2015

最近遇到一个情景,就是定期生成并发送服务器使用情况报表,按照不同维度统计,涉及python对excel的操作,上网搜罗了一番,大多大同小异,而且不太能满足需求,不过经过一番对源码的"研究"(用此一词让我觉得颇有成就感)之后,基本解决了日常所需。主要记录使用过程的常见问题及解决。

python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库。可从这里下载https://pypi.python.org/pypi。下面分别记录python读和写excel.

python读excel——xlrd

这个过程有几个比较麻烦的问题,比如读取日期、读合并单元格内容。下面先看看基本的操作:

首先读一个excel文件,有两个sheet,测试用第二个sheet,sheet2内容如下:

python中使用xlrd、xlwt操作excel表格详解

python 对 excel基本的操作如下:

# -*- coding: utf-8 -*-
import xlrd
import xlwt
from datetime import date,datetime

def read_excel():
  # 打开文件
  workbook = xlrd.open_workbook(r'F:\demo.xlsx')
  # 获取所有sheet
  print workbook.sheet_names() # [u'sheet1', u'sheet2']
  sheet2_name = workbook.sheet_names()[1]

  # 根据sheet索引或者名称获取sheet内容
  sheet2 = workbook.sheet_by_index(1) # sheet索引从0开始
  sheet2 = workbook.sheet_by_name('sheet2')

  # sheet的名称,行数,列数
  print sheet2.name,sheet2.nrows,sheet2.ncols

  # 获取整行和整列的值(数组)
  rows = sheet2.row_values(3) # 获取第四行内容
  cols = sheet2.col_values(2) # 获取第三列内容
  print rows
  print cols

  # 获取单元格内容
  print sheet2.cell(1,0).value.encode('utf-8')
  print sheet2.cell_value(1,0).encode('utf-8')
  print sheet2.row(1)[0].value.encode('utf-8')
  
  # 获取单元格内容的数据类型
  print sheet2.cell(1,0).ctype

if __name__ == '__main__':
  read_excel()

运行结果如下:

python中使用xlrd、xlwt操作excel表格详解

那么问题来了,上面的运行结果中红框框中的字段明明是出生日期,可显示的确实浮点数。好的,来解决第一个问题:

1、python读取excel中单元格内容为日期的方式

python读取excel中单元格的内容返回的有5种类型,即上面例子中的ctype:

ctype : 0 empty,1 string, 2 number, 3 date, 4 boolean, 5 error

即date的ctype=3,这时需要使用xlrd的xldate_as_tuple来处理为date格式,先判断表格的ctype=3时xldate才能开始操作。现在命令行看下:

>>> sheet2.cell(2,2).ctype #1990/2/22
>>> sheet2.cell(2,1).ctype #24
>>> sheet2.cell(2,0).ctype #小胖
>>> sheet2.cell(2,4).ctype #空值(这里是合并单元格的原因)
>>> sheet2.cell(2,2).value #1990/2/22
33656.0
>>> xlrd.xldate_as_tuple(sheet2.cell_value(2,2),workbook.datemode)
(1992, 2, 22, 0, 0, 0)
>>> date_value = xlrd.xldate_as_tuple(sheet2.cell_value(2,2),workbook.datemode)
>>> date_value
(1992, 2, 22, 0, 0, 0)
>>> date(*date_value[:3])
datetime.date(1992, 2, 22)
>>> date(*date_value[:3]).strftime('%Y/%m/%d') 
'1992/02/22'

即可以做下简单处理,判断ctype是否等于3,如果等于3,则用时间格式处理:

if (sheet.cell(row,col).ctype == 3):
  date_value = xlrd.xldate_as_tuple(sheet.cell_value(rows,3),book.datemode)
  date_tmp = date(*date_value[:3]).strftime('%Y/%m/%d')

那么问题又来了,上面 sheet2.cell(2,4).ctype 返回的值是0,说明这个单元格的值是空值,明明是合并的单元格内容"好朋友",这个是我觉得这个包功能不完善的地方,如果是合并的单元格那么应该合并的单元格的内容一样,但是它只是合并的第一个单元格的有值,其它的为空。

>>> sheet2.col_values(4)
[u'\u5173\u7cfb', u'\u597d\u670b\u53cb', '', u'\u540c\u5b66', '', '', u'\u4e00\u4e2a\u4eba', '']
>>> for i in range(sheet2.nrows):
  print sheet2.col_values(4)[i]
关系
好朋友

同学


一个人

>>> sheet2.row_values(7)
[u'\u65e0\u540d', 20.0, u'\u6682\u65e0', '', '']
>>> for i in range(sheet2.ncols):
  print sheet2.row_values(7)[i]
无名
20.0
暂无


>>>

2、读取合并单元格的内容

这个是真没技巧,只能获取合并单元格的第一个cell的行列索引,才能读到值,读错了就是空值。

即合并行单元格读取行的第一个索引,合并列单元格读取列的第一个索引,如上述,读取行合并单元格"好朋友"和读取列合并单元格"暂无"只能如下方式:

>>> print sheet2.col_values(4)[1]
好朋友
>>> print sheet2.row_values(7)[2]
暂无

 >>> sheet2.merged_cells # 明明有合并的单元格,为何这里是空
 []

疑问又来了,合并单元格可能出现空值,但是表格本身的普通单元格也可能是空值,要怎么获取单元格所谓的"第一个行或列的索引"呢?

这就要先知道哪些是单元格是被合并的!

3、获取合并的单元格

读取文件的时候需要将formatting_info参数设置为True,默认是False,所以上面获取合并的单元格数组为空,

>>> workbook = xlrd.open_workbook(r'F:\demo.xlsx',formatting_info=True)
>>> sheet2 = workbook.sheet_by_name('sheet2')
>>> sheet2.merged_cells
[(7, 8, 2, 5), (1, 3, 4, 5), (3, 6, 4, 5)]

merged_cells返回的这四个参数的含义是:(row,row_range,col,col_range),其中[row,row_range)包括row,不包括row_range,col也是一样,即(1, 3, 4, 5)的含义是:第1到2行(不包括3)合并,(7, 8, 2, 5)的含义是:第2到4列合并。

利用这个,可以分别获取合并的三个单元格的内容:

>>> print sheet2.cell_value(1,4)  #(1, 3, 4, 5)
好朋友
>>> print sheet2.cell_value(3,4)  #(3, 6, 4, 5)
同学
>>> print sheet2.cell_value(7,2)  #(7, 8, 2, 5)
暂无

发现规律了没?是的,获取merge_cells返回的row和col低位的索引即可! 于是可以这样一劳永逸:

>>> merge = []
>>> for (rlow,rhigh,clow,chigh) in sheet2.merged_cells:
  merge.append([rlow,clow])
  
>>> merge
[[7, 2], [1, 4], [3, 4]]
>>> for index in merge:
  print sheet2.cell_value(index[0],index[1])
  
暂无
好朋友
同学
>>>

python写excel——xlwt

写excel的难点可能不在构造一个workbook的本身,而是填充的数据,不过这不在范围内。在写excel的操作中也有棘手的问题,比如写入合并的单元格就是比较麻烦的,另外写入还有不同的样式。这些要看源码才能研究的透。

我"构思"了如下面的sheet1,即要用xlwt实现的东西:

python中使用xlrd、xlwt操作excel表格详解

基本上看起来还算复杂,而且看起来"很正规",完全是个人杜撰。

代码如下:

'''
设置单元格样式
'''

def set_style(name,height,bold=False):
  style = xlwt.XFStyle() # 初始化样式

  font = xlwt.Font() # 为样式创建字体
  font.name = name # 'Times New Roman'
  font.bold = bold
  font.color_index = 4
  font.height = height

  # borders= xlwt.Borders()
  # borders.left= 6
  # borders.right= 6
  # borders.top= 6
  # borders.bottom= 6

  style.font = font
  # style.borders = borders

  return style


#写excel
def write_excel():
  f = xlwt.Workbook() #创建工作簿

  '''
  创建第一个sheet:
    sheet1
  '''
  sheet1 = f.add_sheet(u'sheet1',cell_overwrite_ok=True) #创建sheet
  row0 = [u'业务',u'状态',u'北京',u'上海',u'广州',u'深圳',u'状态小计',u'合计']
  column0 = [u'机票',u'船票',u'火车票',u'汽车票',u'其它']
  status = [u'预订',u'出票',u'退票',u'业务小计']

  #生成第一行
  for i in range(0,len(row0)):
    sheet1.write(0,i,row0[i],set_style('Times New Roman',220,True))

  #生成第一列和最后一列(合并4行)
  i, j = 1, 0
  while i < 4*len(column0) and j < len(column0):
    sheet1.write_merge(i,i+3,0,0,column0[j],set_style('Arial',220,True)) #第一列
    sheet1.write_merge(i,i+3,7,7) #最后一列"合计"
    i += 4
    j += 1

  sheet1.write_merge(21,21,0,1,u'合计',set_style('Times New Roman',220,True))

  #生成第二列
  i = 0
  while i < 4*len(column0):
    for j in range(0,len(status)):
      sheet1.write(j+i+1,1,status[j])
    i += 4

  f.save('demo1.xlsx') #保存文件

if __name__ == '__main__':
  #generate_workbook()
  #read_excel()
  write_excel()

需要稍作解释的就是write_merge方法:

write_merge(x, x + m, y, w + n, string, sytle)
x表示行,y表示列,m表示跨行个数,n表示跨列个数,string表示要写入的单元格内容,style表示单元格样式。其中,x,y,w,h,都是以0开始计算的。

这个和xlrd中的读合并单元格的不太一样。

如上述:sheet1.write_merge(21,21,0,1,u'合计',set_style('Times New Roman',220,True))

即在22行合并第1,2列,合并后的单元格内容为"合计",并设置了style。

 

如果需要创建多个sheet,则只要f.add_sheet即可。

如在上述write_excel函数里f.save('demo1.xlsx') 这句之前再创建一个sheet2,效果如下:

python中使用xlrd、xlwt操作excel表格详解

代码也是真真的easy的了:

'''
  创建第二个sheet:
    sheet2
  '''
  sheet2 = f.add_sheet(u'sheet2',cell_overwrite_ok=True) #创建sheet2
  row0 = [u'姓名',u'年龄',u'出生日期',u'爱好',u'关系']
  column0 = [u'小杰',u'小胖',u'小明',u'大神',u'大仙',u'小敏',u'无名']

  #生成第一行
  for i in range(0,len(row0)):
    sheet2.write(0,i,row0[i],set_style('Times New Roman',220,True))

  #生成第一列
  for i in range(0,len(column0)):
    sheet2.write(i+1,0,column0[i],set_style('Times New Roman',220))

  sheet2.write(1,2,'1991/11/11')
  sheet2.write_merge(7,7,2,4,u'暂无') #合并列单元格
  sheet2.write_merge(1,2,4,4,u'好朋友') #合并行单元格
  
  f.save('demo1.xlsx') #保存文件
Python 相关文章推荐
python中文乱码的解决方法
Nov 04 Python
Python3 能振兴 Python的原因分析
Nov 28 Python
使用Python的PEAK来适配协议的教程
Apr 14 Python
python类和函数中使用静态变量的方法
May 09 Python
Python实现列表转换成字典数据结构的方法
Mar 11 Python
Python实现类似jQuery使用中的链式调用的示例
Jun 16 Python
神经网络相关之基础概念的讲解
Dec 29 Python
django框架基于queryset和双下划线的跨表查询操作详解
Dec 11 Python
python 正则表达式参数替换实例详解
Jan 17 Python
解决pyecharts运行后产生的html文件用浏览器打开空白
Mar 11 Python
如何在pycharm中安装第三方包
Oct 27 Python
浅谈Python从全局与局部变量到装饰器的相关知识
Jun 21 Python
Python中实现常量(Const)功能
Jan 28 #Python
Python使用random和tertools模块解一些经典概率问题
Jan 28 #Python
Python中的异常处理学习笔记
Jan 28 #Python
Python中集合类型(set)学习小结
Jan 28 #Python
Python中使用装饰器和元编程实现结构体类实例
Jan 28 #Python
Python实现Const详解
Jan 27 #Python
python映射列表实例分析
Jan 26 #Python
You might like
PHP代码网站如何防范SQL注入漏洞攻击建议分享
2012/03/01 PHP
PHP生成网站桌面快捷方式代码分享
2014/10/11 PHP
Laravel 4 初级教程之Pages、表单验证
2014/10/30 PHP
yii权限控制的方法(三种方法)
2015/12/28 PHP
php实现的XML操作(读取)封装类完整实例
2017/02/23 PHP
PHP 实现链式操作
2021/03/09 PHP
Ext JS Grid在IE6 下宽度的问题解决方法
2009/02/15 Javascript
jquery ready(fn)事件使用介绍
2013/08/21 Javascript
动态的绑定事件addEventListener方法的使用
2014/01/24 Javascript
Jquery操作js数组及对象示例代码
2014/05/11 Javascript
jquery控制表单输入框显示默认值的方法
2015/05/22 Javascript
深入理解node exports和module.exports区别
2016/06/01 Javascript
JavaScript中的事件委托及好处
2016/07/12 Javascript
EasyUI框架 使用Ajax提交注册信息的实现代码
2017/09/27 Javascript
apicloud拉起小程序并传递参数的方法示例
2018/11/21 Javascript
vue.draggable实现表格拖拽排序效果
2018/12/01 Javascript
JS高阶函数原理与用法实例分析
2019/01/15 Javascript
Vue数据绑定简析小结
2019/05/07 Javascript
Vue开发中常见的套路和技巧总结
2020/11/24 Vue.js
[14:25]教你分分钟做大人:主宰(HEROS)
2014/12/08 DOTA
Python map和reduce函数用法示例
2015/02/26 Python
python使用点操作符访问字典(dict)数据的方法
2015/03/16 Python
攻击者是如何将PHP Phar包伪装成图像以绕过文件类型检测的(推荐)
2018/10/11 Python
详解如何用django实现redirect的几种方法总结
2018/11/22 Python
对python中的控制条件、循环和跳出详解
2019/06/24 Python
win10系统Anaconda和Pycharm的Tensorflow2.0之CPU和GPU版本安装教程
2019/12/03 Python
pycharm导入源码的具体步骤
2020/08/04 Python
北京银河万佳Java面试题
2012/03/21 面试题
linux系统都有哪些运行级别
2016/03/26 面试题
销售人员个人求职信
2013/09/26 职场文书
商场主管竞聘书
2014/03/31 职场文书
《望庐山瀑布》教学反思
2014/04/22 职场文书
元旦联欢会策划方案
2014/06/11 职场文书
初中同学会活动方案
2014/08/22 职场文书
外出学习心得体会范文
2016/01/18 职场文书
Python捕获、播放和保存摄像头视频并提高视频清晰度和对比度
2022/04/14 Python