xlwings使用教程,让excel飞起来!----Python读写Excel工具

一、xlwings简介

image

xlwings优点

excel已经成为必不可少的数据处理软件,几乎天天在用。python有很多支持操作excel的第三方库,xlwings是其中一个。

关于xlwings
xlwings开源免费,能够非常方便的读写Excel文件中的数据,并且能够进行单元格格式的修改。

xlwings还可以和matplotlib、numpy以及pandas无缝连接,支持读写numpy、pandas数据类型,将matplotlib可视化图表导入到excel中。

最重要的是xlwings可以调用Excel文件中VBA写好的程序,也可以让VBA调用用Python写的程序。

开源免费,一直在更新

xlwings同类工具

python操作Excel的模块,网上提到的模块大致有:xlwings、xlrd、xlwt、openpyxl,pandas等。

xlwings功能总结

一、用python读写Excel文件,实际上就是读写有格式的文本文件,操作excel文件和操作text、csv文件没有区别,Excel文件只是用来储存数据。

二、除了操作数据,还可以调整Excel文件的表格宽度、字体颜色等。

另外需要提到的是用COM调用Excel的API操作Excel文档也是可行的,相当麻烦基本和VBA没有区别

xlwings中文文档

https://www.kancloud.cn/gnefnuy/xlwings-docs/1127474

xlwings结构图

image

二、xlwings基本操作

(一)引入库

import xlwings as xw

(二)打开 excel

# 打开Excel程序,默认设置:程序可见,只打开不新建工作薄,屏幕更新关闭
app=xw.App(visible=True,add_book=False)
app.display_alerts=False
app.screen_updating=False

# 其他操作:
# 屏幕更新。就是说代码对于excel的操作你可以看见。关闭实时更新,可以加快脚本运行。默认是True。
# app.screen_updating = False  

# App进程pid
# app.pid       

# 返回一个打开的全部workbook的列表。Python打开的和手动打开的是不互通的
# app.books     
                
# 终止进程,强制退出。
# app.quit() #不保存的情况下,退出excel程序

(三)工作簿

注意工作簿应该首先被打开

1、新建Excel文档

# 创建新的book
# 方式一
wb = app.books.add()
# 方式二
wk = xw.Book()

很多教程在提到新建App时都说这两种方式是一样的,实际上是有区别的,
方式1是在当前App下新建一个Book,
方式2是创建一个新的App,并在新App中新建一个Book

# 方式三,与方式一方法相似
wk = xw.books.add()

2、 打开Excel文档

# 支持绝对路径和相对路径
wb = app.books.open('filepath')
wk = xw.Book('filepath')
wk = xw.books.open('filepath')

# 练习的时候建议直接用下面这条
# wb = xw.Book('example.xlsx')
# 这样的话就不会频繁打开新的Excel

3、打开未储存或未关闭的excel实例

wk = xw.Book('Book1')    
wk = xw.books['Book1']  #也可以使用索引

如果在两个Excel实例中打开了相同的文件,则需要完全限定它并包含应用程序实例。

您将通过xw.apps.keys()找到您的应用实例密钥(PID):

xw.apps[10559].books['FileName.xlsx']
查看所有的实例进程:
xw.apps.keys() #输出list

kill所有的实例进程:
for i in xw.apps.keys():
  i = 'taskkill/pid ' + str(i) + ' -t -f'     
  os.system(i)

4、打开活动的工作簿

wb = xw.books.active

5、保存

# 保存工作簿,若未指定路径,保存在当前工作目录。
wb.save(path=None)

6、关闭

#在没有保存的情况下关闭。
wk.close()  

7、退出Excel

app.quit()

(四)工作表

1、打开工作表

# 可以用名字也可以用索引
sheet = xw.books['工作簿的名字'].sheets['sheet的名字']
sheet = xw.books['工作簿的名字'].sheets[0]

2、打开活动工作表

sheet = xw.sheets.active

3、返回sheet指定的book

book_name = sheet.book

4、返回一个range对象,表示sheet上所有的单元格

sheet_cells = sheet.cells

5、获取或设置Sheet的名称

sheet.name
# 返回所有的工作表特定名称。
sheet_names_list = sheet.names

6、获取sheet中的所有图表集合

sheet.charts

7、清空表中所有数据和格式。

sheet.clear()

8、清除工作表的内容,但保留格式

sheet.clear_contents()

9、删除工作表

sheet.delete()

10、返回表索引(与excel相同)

sheet.index

11、创建一个新的Sheet并使其成为活动工作表

wb.sheets.add(name=None, before=None, after=None) 
#参数:
name(str,default None) - 新工作表的名称。 如果为None,则默认为Excel的name.

before (Sheet, default None) - 一个对象,指定在新工作表添加之前的added.

after (Sheet, default None) - 指定工作表之后的新工作表的对象。

12、在整个工作表上自动调整列,行或两者的宽度

sheet.autofit(axis=None) 

# 参数:
axis (string, default None)
要自动调整行, 使用以下之一: rows 或 r,
要自动调整列, 使用以下之一: columns h c,
要自动调整行和列, 不提供参数

13、获取excel sheet多少行多少列

app = xw.App(visible=False, add_book=False)
xls = app.books.open(excel_file)
sheet = xls.sheets[0]
last_cell = sheet.used_range.last_cell
nrows = sheet.used_range.last_cell.row
ncols = sheet.used_range.last_cell.colum

(五)单元格

1、引用A1单元格

rng = xw.books['工作簿的名字'].sheets['sheet的名字'].range('A1')
# 或者
sheet=xw.books['工作簿的名字'].sheets['sheet的名字']
rng=sheet.range('A1')

2、引用活动工作表上的单元格

# 注意Range首字母大写
rng=xw.Range('A1')

其中需要注意的是单元格的完全引用路径是:
# 第一个Excel程序的第一个工作薄的第一张sheet的第一个单元格
xw.apps[0].books[0].sheets[0].range('A1')

迅速引用单元格的方式是
sht=xw.books['名字'].sheets['名字']

# A1单元格
rng=sht[’A1']
rng=sht['a1']

# A1:B5单元格
rng=sht['A1:B5']

# 第一行的第一列即a1
rng=sht[0,0] 

# B1单元格
rng=sht[0,1]

3、引用区域单元格

# A1:J10
rng=sht[:10,:10]

# A1:E10
rng=sht[:10,:5]

rng=sht.range('a1:a5')
#rng = sht['a1:a5']
#rng = sht[:5,0]

4、对于单元格也可以用表示行列的tuple进行引用

# A1单元格的引用
xw.Range(1,1)

#A1:C3单元格的引用
xw.Range((1,1),(3,3))

(六)写入数据

1、写入单个值

# 注意".value“
sht.range('A1').value=1

2、写入列表

默认按行插入

# 将列表[1,2,3]储存在A1:C1中
sht.range('A1').value=[1,2,3]

# 等同于
sht.range('A1:C1').value = [1,2,3]

按列插入

# 将列表[1,2,3]储存在A1:A3中
sht.range('A1').options(transpose=True).value=[1,2,3]

其他方法

列表
一维列表:
表示Excel中行或列的范围作为简单列表返回,
这意味着一旦它们在Python中,您就丢失了有关方向的信息。
如果这是一个问题,下一点将向您展示如何保留此信息:


######################## 列方向(嵌套列表)################
列表中,每个元素都已列表方式保存,存储时,是按照列方向保存的
sht = xw.Book().sheets[0]
sht.range('A1').value = [[1],[2],[3],[4],[5]]  # 列方向(嵌套列表)

返回值为
sht.range('A1:A5').value
[1.0, 2.0, 3.0, 4.0, 5.0]


################## 行方向,普通列表 #######################
sht.range('A1').value = [1, 2, 3, 4, 5]
sht.range('A1:E1').value

返回值为
[1.0, 2.0, 3.0, 4.0, 5.0]    


要强制单个单元格作为列表到达,请使用:

sht.range('A1').options(ndim=1).value

返回值为
[1.0]

多行输入就要用二维列表

重点:

# 将2x2表格,即二维数组,储存在A1:B2中,如第一行1,2,第二行3,4

sht.range('A1').options(expand='table').value=[[1,2],[3,4]]

(七)读取数据

1、读取单个值

# 将A1的值,读取到a变量中
a=sht.range('A1').value

2、读取范围的值

  • 返回的值是列表形式,多行多列为二维列表。
  • 但有一点要注意,返回的数值默认是浮点数
#将第一行的值,即将A1到A2的值,读取到a列表中
a=sht.range('A1:A2').value

# 将第一行和第二行的数据按二维数组的方式读取
a=sht.range('A1:B2').value

3、读取Excel表格的行、列

  • 读取excel的第一列,先计算单元格的行数
  • 通过这种方法统计的工作区域的行或者列,不能被空值分隔
  • 空值分隔后面的区域,不在统计范围内。
  • 更好的方式是通过last_cell方式获取最下边且最右边的一个单元格。
  • last_cell = sheet.used_range.last_cell
  • last_row = last_cell.row
  • last_col = last_cell.column
读取excel的第一列,先计算单元格的行数
- 读取excel的第一列,先计算单元格的行数
- 通过这种方法统计的工作区域的行或者列,不能被空值分隔
- 空值分隔后面的区域,不在统计范围内。
- 更好的方式是通过last_cell方式获取最下边且最右边的一个单元格。

# 获取工作表的活动区域
rng = sht.range('a1').expand('table')

# 获取活动区域的行数
nrows = rng.rows.count

# 接着就可以按准确范围读取了
a = sht.range(f'a1:a{nrows}').value

同理选取一行的数据也一样
ncols = rng.columns.count

#用切片
fst_col = sht[0,:ncols].value
获取行数、列数,更好且更准确的方法
# 更好的方式是通过last_cell方式获取最下边且最右边的一个单元格。

last_cell = sheet.used_range.last_cell
last_row = last_cell.row
last_col = last_cell.column

(八)常用函数和方法

1、Book 工作簿常用的api

# 新建工作簿
xw.books.add()

# 引用当前活动工作簿
xw.books.active
wb=xw.books[‘工作簿名称']
wb.activate()激活为当前工作簿
wb.fullname 返回工作簿的绝对路径
wb.name 返回工作簿的名称
wb.save(path=None) 保存工作簿,默认路径为工作簿原路径,若未保存则为脚本所在的路径
wb.close() 关闭工作簿


代码例子:
# 引用Excel程序中,当前的工作簿
wb=xw.books.acitve

# 返回工作簿的绝对路径
x=wb.fullname

# 返回工作簿的名称
x=wb.name

# 保存工作簿,默认路径为工作簿原路径,若未保存则为脚本所在的路径
x=wb.save(path=None)

# 关闭工作簿
x=wb.close()

2、sheet 常用的api

# 新建工作表
xw.sheets.add(name=None,before=None,after=None)

# 引用当前活动sheet
xw.sheets.active

# 引用某指定sheet
sht=xw.books['工作簿名称'].sheets['sheet的名称']

# 激活sheet为活动工作表
sht.activate()

# 清除sheet的内容和格式
sht.clear()

# 清除sheet的内容
sht.contents()

# 获取sheet的名称
sht.name

# 删除sheet
sht.delete

3、range常用的api

# 引用当前活动工作表的单元格
rng=xw.Range('A1')

# 加入超链接
# rng.add_hyperlink(r'www.baidu.com','百度',‘提示:点击即链接到百度')

# 获得range的超链接
rng.hyperlink

# 取得当前range的地址
rng.address
rng.get_address()

# 获得单元格的绝对地址
rng.get_address(row_absolute=True, column_absolute=True,include_sheetname=False, external=False)





# 清除range的内容
rng.clear_contents()

# 清除格式和内容
rng.clear()




# 取得range的背景色,以元组形式返回RGB值
rng.color

# 设置range的颜色
rng.color=(255,255,255)

# 清除range的背景色
rng.color=None




# 返回range中单元格的数量
rng.count

# 返回current_region当前区域
rng.current_region

# 返回ctrl + 方向
rng.end('down')





# 获取公式或者输入公式
rng.formula='=SUM(B1:B5)'

# 数组公式
rng.formula_array



# range平移
rng.offset(row_offset=0,column_offset=0)

#range进行resize改变range的大小
rng.resize(row_size=None,column_size=None)



# 获得range的第一列列标
rng.column

# 获得列宽
rng.column_width

# 返回range的总宽度
rng.width



# range的第一行行标
rng.row

# 行的高度,所有行一样高返回行高,不一样返回None
rng.row_height

# 返回range的总高度
rng.height



###################################################

# 获得range中右下角最后一个单元格
rng.last_cell






# 返回range的行数和列数
rng.shape

# 返回range所在的sheet
rng.sheet



#返回range的所有行
rng.rows

# range的第一行
rng.rows[0]

# range的总行数
rng.rows.count



# 返回range的所有列
rng.columns

# 返回range的第一列
rng.columns[0]

# 返回range的列数
rng.columns.count






# 所有range的大小自适应
rng.autofit()

# 所有列宽度自适应
rng.columns.autofit()

# 所有行宽度自适应
rng.rows.autofit()

三、Python工具类,通过代码操作Excel表格

以下是我的工具类代码,转载请注明出处。

#!/usr/bin/python
# -*- coding: UTF-8 -*-

import os
import xlwings


class ToolExcel(object):
    __file_name = "workbook.xlsx"
    __sheet_name = "Sheet1"

    # 新建工作簿
    @staticmethod
    def workbook_new(file_name: str = __file_name):

        # 工作簿文件路径
        workbook_file_path = os.path.join(os.getcwd(), "workbook", file_name)
        # 工作簿当前目录
        workbook_dir_path = os.path.dirname(workbook_file_path)

        # 如果不存在目录路径,就创建
        if not os.path.exists(workbook_dir_path):
            # 创建工作簿路径,makedirs可以创建级联路径
            os.makedirs(workbook_dir_path)

        # 如果不存在,Excel工作簿文件,就创建工作簿
        if not os.path.exists(workbook_file_path):
            # 打开Excel程序,APP程序(即Excel程序)不可见,只打开不新建工作薄,屏幕更新关闭
            app = xlwings.App(visible=False, add_book=False)
            # Excel工作簿显示警告,不显示
            app.display_alerts = False
            # 工作簿屏幕更新,不更新
            app.screen_updating = False
            # 创建工作簿
            wb = app.books.add()
            # 保存工作簿,若未指定路径,保存在当前工作目录。
            wb.save(workbook_file_path)
            # 关闭工作簿
            wb.close()
            # 退出Excel
            app.quit()

    # 读取工作簿全部内容,返回二维列表
    @staticmethod
    def workbook_read(file_name=__file_name, sheet_name=__sheet_name):
        # 工作簿文件路径
        workbook_file_path = os.path.join(os.getcwd(), "workbook", file_name)
        # 如果文件存在,就执行
        if os.path.exists(workbook_file_path):
            # 打开Excel程序,APP程序(即Excel程序)不可见,只打开不新建工作薄,屏幕更新关闭
            app = xlwings.App(visible=False, add_book=False)
            # Excel工作簿显示警告,不显示
            app.display_alerts = False
            # 工作簿屏幕更新,不更新
            app.screen_updating = False
            # 打开工作簿
            wb = app.books.open(workbook_file_path)
            # 获取活动的工作表
            sheet = wb.sheets[sheet_name]

            # 获取已编辑的矩形区域,最底部且最右侧的单元格
            last_cell = sheet.used_range.last_cell
            # 最大行数
            last_row = last_cell.row
            # 最大列数
            last_col = last_cell.column

            """
            # 读取二维列表
            # 注释:如果含有 .options(expand='table').value 参数,空值隔断的部分,不会被读取
            # data = sheet.range((1, 1), (last_row, last_col)).options(expand='table').value
            """

            # 读取二维列表
            data = sheet.range((1, 1), (last_row, last_col)).value

            # 关闭工作簿
            wb.close()
            # 退出Excel
            app.quit()
            return data

    # 写入二维列表,追加模式
    @staticmethod
    def workbook_append(data: list = None, file_name=__file_name, sheet_name=__sheet_name):
        # 工作簿文件路径
        workbook_file_path = os.path.join(os.getcwd(), "workbook", file_name)

        # 如果工作簿不存在,就创建工作簿
        if not os.path.exists(workbook_file_path):
            ToolExcel.workbook_new()

        # 如果文件存在,就执行
        if os.path.exists(workbook_file_path):
            # 打开Excel程序,APP程序(即Excel程序)不可见,只打开不新建工作薄,屏幕更新关闭
            app = xlwings.App(visible=False, add_book=False)
            # Excel工作簿显示警告,不显示
            app.display_alerts = False
            # 工作簿屏幕更新,不更新
            app.screen_updating = False
            # 打开工作簿
            wb = app.books.open(workbook_file_path)
            # 获取活动的工作表
            sheet = wb.sheets[sheet_name]

            # 获取已编辑的矩形区域,最底部且最右侧的单元格
            last_cell = sheet.used_range.last_cell
            # 最大行数
            last_row = last_cell.row

            # 写入二维列表,追加模式
            sheet.range((last_row + 1, 1)).options(expand='table').value = data

            # # 保存文件,保存以后重新读取单元格,重新获取所有活动区域的cell.
            # # 是否保存, 有待考证?
            # wb.save()

            # 获取已编辑的矩形区域,最底部且最右侧的单元格
            last_cell = sheet.used_range.last_cell
            # 最大行数
            last_row = last_cell.row
            # 最大列数
            last_col = last_cell.column
            # 在range中,cell的大小自适应
            sheet.range((1, 1), (last_row, last_col)).columns.autofit()

            # 保存文件
            wb.save()
            # 关闭工作簿
            wb.close()
            # 退出Excel
            app.quit()

    # 写入二维列表,重写模式
    @staticmethod
    def workbook_rewrite(data: list = None, file_name=__file_name, sheet_name=__sheet_name):
        # 工作簿文件路径
        workbook_file_path = os.path.join(os.getcwd(), "workbook", file_name)

        # 如果工作簿不存在,就创建工作簿
        if not os.path.exists(workbook_file_path):
            ToolExcel.workbook_new()

        # 如果文件存在,就执行
        if os.path.exists(workbook_file_path):
            # 打开Excel程序,APP程序(即Excel程序)不可见,只打开不新建工作薄,屏幕更新关闭
            app = xlwings.App(visible=False, add_book=False)
            # Excel工作簿显示警告,不显示
            app.display_alerts = False
            # 工作簿屏幕更新,不更新
            app.screen_updating = False
            # 打开工作簿
            wb = app.books.open(workbook_file_path)
            # 获取活动的工作表
            sheet = wb.sheets[sheet_name]

            # 清除sheet的内容和格式
            sheet.clear()

            # 写入二维列表,重写模式
            sheet.range("A1").options(expand='table').value = data

            # 获取已编辑的矩形区域,最底部且最右侧的单元格
            last_cell = sheet.used_range.last_cell
            # 最大行数
            last_row = last_cell.row
            # 最大列数
            last_col = last_cell.column
            # 所有range的大小自适应
            sheet.range((1, 1), (last_row, last_col)).columns.autofit()

            # 保存文件
            wb.save()
            # 关闭工作簿
            wb.close()
            # 退出Excel
            app.quit()


四、参考文献:

xlwings使用教程
https://blog.csdn.net/qq_37289115/article/details/106666073

xlwings 中文文档
https://www.kancloud.cn/gnefnuy/xlwings-docs/1127450

办公自动化系列(3)| 全网最详细的xlwings库解析-上篇 https://www.jianshu.com/p/5b1cbb0637bb

彻底搞懂Python切片操作
https://www.jianshu.com/p/15715d6f4dad

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335