python:openpyxl基础操作(一):创建.xlsx文件
目录
前言:
本文仅供个人学习记录+复习所用,探索过程中难免出现差错和纰漏,如文中有错误,以及可以改进的地方,还请各位不吝赐教。
安装openpyxl:
安装openpyxl的时候,我遇到了各种各样的错误,首先在pycharm内部解释器中进行安装,显示安装失败。
搜索后发现,是由于自己的pip没有达到最新版本,在cmd中更新了pip,并直接pip install openpyxl
结果依然出了错,无法安装。
(由于目前已经安装完毕,没有保存当时出错的流程图,但我自己总结了下原因,如果有相同情况的小伙伴可以尝试下)
1. 更新pip:我在pycharm中遇到过“有新版本,但无法刷新出新版本,无法更新的情况”
曾使用cmd对pip进行更新,但由于我的pycharm和其项目均在D盘,而我更新的操作是在C:/user里进行的,可能导致“更新”没有发生在d盘中。
(这一点的确是我没想到的,不过也暴露了我非科班、对计算机了解太浅显的短板。)
解决这一问题,是我在pycharm里再次尝试安装openpyxl的时候,根据pycharm给的提示,在cmd中D盘的某一地址下进行操作。
这次更新成功了。
2. 更新完pip就可以直接在解释器内安装openpyxl了。
大部分情况下,pycharm里会在打开解释器的时候显示可以更新的包,直接更新即可。
创建.xlsx文件:
首先引入包:
from openpyxl import Workbook
from openpyxl import load_workbook
使用Workbook创建excel表格。注意首字母需要大写。如果忽略,会报错。
创建表格后需要进行保存,接下来的内容会介绍具体操作,但要注意,创建、修改后都不要忘记保存,否则修改后的内容只会出现在pycharm里,而不是表格中。
使用load_workbook加载已经创建好的表格。
wb = Workbook() # pay attention to the first letter
'''创建一个表格,注意,wb并非是保存文件的名字,而是变量。
此时wb是一个文件,里面什么都没有,没有sheet表单'''
sheet = wb.active
'''此时我们在文件wb中创建了一个sheet'''
创建单个表单的时候可以直接使用wb.active,这种情况适用于在空文件中创建第一个sheet。
提问:是否可以多次调用active?
答:可以多次调用,但只能生成第一个调用active的表单,其余调用结果不予显示。
提问:那么如何创建多个表单?
答:
sheet_1 = wb.create_sheet('sheet_1')
sheet_2 = wb.create_sheet('sheet_2')
括号内传入的参数是表单的名称,生成的表单是空表单。
保存:
wb.save('theFstSample.xlsx')
这一步骤可以放在所有语句结尾。传入的参数是excel文件的文件名,注意不要忘记其扩展名。
保存的位置和所编写的py文件的位置一样。
添加单元格内容
单个添加:
sheet_2['A1'] = 56
sheet_2['A2'] = 78
sheet_2['A3'] = 90
注意添加的表单,是sheet_2:
当打开表格查看输出结果的时候,一定要关闭文档,否则再次修改时会出现:
Traceback (most recent call last):
File "D:\pythonProject\ExcelImport.py", line 31, in <module>
wb.save('theFstSample.xlsx')
File "D:\pythonProject\venv\lib\site-packages\openpyxl\workbook\workbook.py", line 386, in save
save_workbook(self, filename)
File "D:\pythonProject\venv\lib\site-packages\openpyxl\writer\excel.py", line 291, in save_workbook
archive = ZipFile(filename, 'w', ZIP_DEFLATED, allowZip64=True)
File "C:\Users\Suen\AppData\Local\Programs\Python\Python310\lib\zipfile.py", line 1240, in __init__
self.fp = io.open(file, filemode)
PermissionError: [Errno 13] Permission denied: 'theFstSample.xlsx'
遇到这样的情况,只需要关闭excel文档,重新运行程序即可。
多个添加:
问题:单个添加挺慢啊,有快一些的方法吗?
答:有的。
rows = (
(998, 997, 996),
(787, 988, 876),
(233, 445, 786)
)
for row in rows:
sheet.append(row)
使用append()可以完成填充表格。(万金油append)
增删单元格:
两个函数的调用:
sheet.insert_rows(idx=2, amount=4) # we insert blank cells.
print(sheet.max_row, sheet.max_column)
# 7 3 测试是否插入,如果不想测试,可以直接打开文件
sheet.insert_cols(idx=2, amount=4)
print(sheet.max_row, sheet.max_column)
# 7 7
sheet.delete_rows(idx=2)
注意:如果是在空白格的地方添加单元格,比如在A7下面或G1右面添加,表格不会发生改变。
遍历表格中的值:
在遍历之前,有一个问题需要解决:
如何输出某一个单元格(cell)的值呢?
答:直接打印输出的是cell对象,需要在后面调用下value
print(sheet['A1'])
# <Cell 'Sheet'.A1> 单元格对象
sheet_1['A3'] = 10
print(sheet_1['A3'].value, sheet_1['A2'].value)
# 10 None
如果单元格内没有值,则会返回None。(这个和pandas里面不一样,pandas如果没有值会返回NaN)
迭代:
for col_ in sheet.columns:
print(col_, ", ")
# u cannot output the value of per cell based on method above.
'''
(<Cell 'Sheet'.A1>, <Cell 'Sheet'.A2>, <Cell 'Sheet'.A3>, <Cell 'Sheet'.A4>, <Cell 'Sheet'.A5>, <Cell 'Sheet'.A6>) ,
(<Cell 'Sheet'.B1>, <Cell 'Sheet'.B2>, <Cell 'Sheet'.B3>, <Cell 'Sheet'.B4>, <Cell 'Sheet'.B5>, <Cell 'Sheet'.B6>) ,
(<Cell 'Sheet'.C1>, <Cell 'Sheet'.C2>, <Cell 'Sheet'.C3>, <Cell 'Sheet'.C4>, <Cell 'Sheet'.C5>, <Cell 'Sheet'.C6>) ,
(<Cell 'Sheet'.D1>, <Cell 'Sheet'.D2>, <Cell 'Sheet'.D3>, <Cell 'Sheet'.D4>, <Cell 'Sheet'.D5>, <Cell 'Sheet'.D6>) ,
(<Cell 'Sheet'.E1>, <Cell 'Sheet'.E2>, <Cell 'Sheet'.E3>, <Cell 'Sheet'.E4>, <Cell 'Sheet'.E5>, <Cell 'Sheet'.E6>) ,
(<Cell 'Sheet'.F1>, <Cell 'Sheet'.F2>, <Cell 'Sheet'.F3>, <Cell 'Sheet'.F4>, <Cell 'Sheet'.F5>, <Cell 'Sheet'.F6>) ,
'''
iter_col = sheet.iter_cols(min_col=1, min_row=1, max_col=6, max_row=6, values_only=True)
for col_ in iter_col:
print(col_, ', ')
'''
(998, None, None, None, 787, 233) ,
(None, None, None, None, None, None) ,
(None, None, None, None, None, None) ,
(None, None, None, None, None, None) ,
(997, None, None, None, 988, 445) ,
(996, None, None, None, 876, 786) ,
'''
for i in sheet.values:
print(i, ', ')
'''
(998, None, None, None, 787, 233) ,
(None, None, None, None, None, None) ,
(None, None, None, None, None, None) ,
(None, None, None, None, None, None) ,
(997, None, None, None, 988, 445) ,
(996, None, None, None, 876, 786) ,
'''
以上是三种不同的迭代方式。但注意他们的区别。为什么第一个迭代出来的是对象,而不是单元格内的值。
于是我又产生了一个问题,在迭代的过程中,我可以设置迭代的范围(注意函数内部的参数)。是否可以将参数的范围设定在一个单元格内部,并输出值?
i = sheet.iter_cols(min_col=1, min_row=1, max_col=1, max_row=1, values_only=True)
print(i)
'''
<generator object Worksheet._cells_by_col at 0x000001DDFEC9AF80>
'''
print(type(i))
'''<class 'generator'>'''
然而并不行。
合并拆分单元格:
sheet.merge_cells('A1:B2')
sheet.merge_cells(start_row=3, start_column=1, end_column=2, end_row=4)
sheet.unmerge_cells("A1:B2")
sheet.unmerge_cells(start_row=3, start_column=1, end_column=2, end_row=4)
在这段处理中,我直接合并后又拆分了,在尝试的过程中,可以通过打开文件来确认单元格是否被合并/拆分。
检查完之后不要忘记关闭文件窗口哦。
另外,合并的函数时:merge_cells();pycharm里会有提示,需要选择后面带有参数项的merge而不是merged,否则会报错。