第四十章:openpyxl模块

1.安装

pip install openpyxl

2.快速使用

1.新建文件

from openpyxl import Workbook

# 创建一个新的工作簿
wb = Workbook()

# 激活默认的工作表,如果没有指定,默认就是第一个工作表
ws = wb.active

# 给工作表命名
ws.title = "Sheet1"
# 改变 sheet 标签按钮颜色(很少用)
# ws.sheet_properties.tabColor = "1072BA"

# 添加数据
ws["A1"] = "Hello"
ws["B1"] = "World"
ws["A2"] = 42
ws["B2"] = 3.14

# 保存工作簿到文件
wb.save("first_workbook.xlsx")

2.打开文件

from openpyxl import load_workbook

wb = load_workbook('文件名称.xlsx')
ws = wb.active		# 获取当前活动的工作表

3.pandas 方式

import pandas as pd

# 读取 Excel 文件
ra_path = "文件路径/文件名.xlsx"
df = pd.read_excel(ra_path)

# 获取指定列的数据
column_name = "列名称"
column_data = df[column_name]

# 获取多个列的数据
columns = ["列名1", "列名2", "列名3"]
selected_data = df[columns]

# 输出列数据
print(column_data)
print(selected_data)

3.性能介绍

如果文件较大,最好参考下优化模式中的只读模式、只写模式

来源:https://openpyxl-chinese-docs.readthedocs.io/zh-cn/latest/performance.html

1.只读模式

from openpyxl import load_workbook
wb = load_workbook(filename='large_file.xlsx', read_only=True)
ws = wb['big_data']

for row in ws.rows:
    for cell in row:
        print(cell.value)

2.只写模式

from openpyxl import Workbook
wb = Workbook(write_only=True)
ws = wb.create_sheet()

# now we'll fill it with 100 rows x 200 columns
for irow in range(100):
	...ws.append(['%d' % i for i in range(200)])

  # save the file
wb.save('new_big_file.xlsx') # doctest: +SKIP

4.详细介绍

1.sheet 增删改查

from openpyxl import load_workbook

wb = load_workbook('first_workbook.xlsx')


# 创建
## 方式一:插入到最后(default)
ws = wb.create_sheet("Sheet2")

## 方式二:插入到最开始的位置
ws = wb.create_sheet("Sheet3", 0)

## 方式三:复制工作簿中的第一个工作表(放在了最后)
new_ws = wb.copy_worksheet(wb.worksheets[1])


# 删除
## 删除工作表 Sheet2
del wb['Sheet2']


# 查询
## 查询所有工作表,输出列表: [<Worksheet "Sheet3">, <Worksheet "Sheet1">, <Worksheet "Sheet1 Copy">]
all_work = wb.worksheets
print(all_work)	

## 获取当前活动的工作表: <Worksheet "Sheet1 Copy">
ws = wb.active
print(ws)

## 访问工作簿中名为"Sheet1"的工作表: <Worksheet "Sheet1">
ws = wb["Sheet1"]
print(ws)


# 修改
## 修改工作表名称: 将名为 Sheet1 修改为 Sheet11
ws = wb["Sheet1"]
ws.title = "Sheet11"


# 注意:
1.在创建、访问或操作工作表时,都需要先确保工作簿已经被加载
2.在对工作表进行任何修改后,都需要调用 wb.save() 方法来保存工作簿
wb.save("first_workbook.xlsx")

2.call 单元格操作

from openpyxl import load_workbook

wb = load_workbook('first_workbook.xlsx')
ws = wb.active

1.获取最大行、列

# 返回值类型:int
ws.max_row: 获取最大行
ws.max_column:获取最大列

2.单元格

# 方法一:坐标
a = ws['A4']
print(type(a))  # <class 'openpyxl.cell.cell.Cell'>

# 方法二:row 行;column 列
b = ws.cell(row=4, column=2)  
print(type(b))  # <class 'openpyxl.cell.cell.Cell'>

# 方法三:只要访问就创建
for row in range(1, ws.max_row + 1):
    for col in range(1, ws.max_column + 1):
        val = ws.cell(row=row, column=col)
        print(type)
# 注意:
## 常用
# 基础单元格对象: <class 'openpyxl.cell.cell.Cell'>
# 合并单元格对象: <class 'openpyxl.cell.cell.MergedCell'>

## 不常用
# 只读单元格: <class 'openpyxl.cell.cell.ReadOnlyCell'>
# 只写单元格: <class 'openpyxl.cell.cell.WriteOnlyCell'>

2.多单元格

from openpyxl import load_workbook

wb = load_workbook('first_workbook.xlsx')

1.切片、行、列

返回类型:元祖,<class 'tuple'>

元祖内的值:单元格对象
((<Cell 'Sheet1'.A1>, <MergedCell 'Sheet1'.B1>, <MergedCell 'Sheet1'.C1>), (<Cell 'Sheet1'.A2>, <MergedCell 'Sheet1'.B2>, <MergedCell 'Sheet1'.C2>))

# 方法一:
cell_range = ws['A1':'C2']
print(type(cell_range), cell_range)

# 方法二:
col_c = ws['C']	 # 列
row_5 = ws[5]		 # 行

2.行、列索引

使用行和列的索引,按行从工作表中生成单元格,指定迭代范围。
如果没有指定索引,则范围从A1开始。
1.如果指定 min_row=3, min_col=4,表示行从第 3 行起,末行止;列从第 4 列起,末列止
2.如果指定 max_row=7, max_col=4,表示行从第 1 行起,第 7 行止;列从第 1 列起,第 4 列止

如果工作表中没有单元格,则将返回一个空元组。

# min_row: 开始行数
# max_row: 结束行数
# min_col: 开始列数
# max_col: 结束列数
# values_only:是否返回单元格值
## 是:返回值,为空时 None
## 否:返回单元格对象

# 方法一:通过指定范围(行 → 行)
for row in ws.iter_rows(min_row=3, max_row=7, min_col=3, max_col=4, values_only=True):
    for cell in row:
        print(cell)

# 方法二:通过指定范围(列 → 列)
for row in ws.iter_cols(min_col=3, max_col=5, min_row=2, max_row=3, values_only=False):
    for cell in row:
        print(cell)

3.遍历 Sheet

# 方法一:生成器
# 包含每一行的数据,每一行类型为 tuple
rows = ws.rows
cols = ws.columns

print(type(rows), rows)
print(type(cols), cols)
# <class 'generator'> <generator object Worksheet._cells_by_row at 0x7fb8f2281e50>
# <class 'generator'> <generator object Worksheet._cells_by_col at 0x7fb8f2281f50>

row_list = [row for row in rows]
col_list = [col for col in cols]

# 方法二:序列取值
for row_index in range(1, ws.max_row + 1):
    for col_index in range(1, ws.max_column + 1):
        cell = ws.cell(row=row_index, column=col_index)
        print(cell)
     

3.矩阵置换 行 → 列

1.zip 方法

rows = [
    ['num', 'filed_1', 'filed_1'],
    [1, 5, 34],
    [2, 2, 56],
    [3, 0, 56],
    [4, 20, 90],
    [5, 7, 14],
]

print(list(zip(*rows)))

# [('num', 1, 2, 3, 4, 5), ('filed_1', 5, 2, 0, 20, 7), ('filed_1', 34, 56, 56, 90, 14)]
# 注意 
# zip() 方法会舍弃缺少数据的列,可以先使用 pandas 进行补全

# 操作如下
df = pd.DataFrame(rows[1:], columns=rows[0])
print(df)

2.pandas 方法

import pandas as pd

# 读取 Excel 文件
df = pd.read_excel('file.xlsx')

# 对矩阵进行置换
t_df = df.T

# 将置换后的矩阵保存到新的 Excel 文件
with pd.ExcelWriter('new_file.xlsx') as fw:
    t_df.to_excel(fw, index=False, sheet_name='Sheet')

4.赋值

# 方法一:设置单元格的值
ws['A1'] = 'Hello, Excel!'

# 方法二:使用行列坐标设置单元格的值
ws.cell(row=2, column=2, value='Hello, Excel!')

3.设置单元格风格

wb = load_workbook('first_workbook.xlsx')
ws = wb.active  # 获取当前活动的工作表

1.字体

# 导入库
from openpyxl.styles import Font, colors

# 设置字体: 
## name:字体样式、seze:字体大小、bold:加粗、italic:斜体、color:字体颜色
font = Font(name='Arial', size=16, bold=True, italic=True, color='FF0000')
ws['A1'].font = font

# 保存到 xlsx
wb.save('first_workbook.xlsx')

2.单元格底色

from openpyxl.styles import PatternFill

# 设置单元格底色
## start_color:起始颜色(十六进制)、end_color:结束颜色(十六进制)、fill_type: 填充类型(如 'solid'、'none' 等)
fill = PatternFill(start_color='FFFF00', end_color='FFFF00', fill_type='solid')
ws['A2'].fill = fill

# 保存工作簿
wb.save('first_workbook.xlsx')

3.对齐方式

from openpyxl.styles import Alignment

# 设置对齐方式
## horizontal:水平、vertical:垂直
## horizontal:"general", "left", "center", "right", "fill", "justify", "centerContinuous","distributed"
## vertical:"top", "center", "bottom", "justify", "distributed"
alignment = Alignment(horizontal='center', vertical='center')
ws['B1'].alignment = alignment

# 保存工作簿
wb.save('first_workbook.xlsx')

4.行高、列宽

# 设置列宽:width
ws.column_dimensions['A'].width = 20  # 设置 A 列宽为 20
ws.column_dimensions['B'].width = 30  # 设置 B 列宽为 30

# 设置行高:height
ws.row_dimensions[1].height = 40  # 设置第 1 行高为 40
ws.row_dimensions[2].height = 25   # 设置第 2 行高为 25

# 保存工作簿
wb.save('first_workbook.xlsx')

5.合并单元格

# 在合并的单元格中写入文本
# 合并 A1 到 D1 的单元格
ws.merge_cells('A1:D1')
ws['A1'] = "This is a merged cell across four columns."

# 合并第二行的单元格
# 合并 A2 到 C2
ws.merge_cells(start_row=2, start_column=1, end_row=2, end_column=3)
ws['A2'] = "Merged cell in row 2"

wb = load_workbook('first_workbook.xlsx')
ws = wb.active

1.常用方法

# 1.获取所有合并单元格的列表
merged_ranges = ws.merged_cells.ranges

# 2.遍历单元格列表,判断单元格是否为合并单元格
cell = ws.cell(row=2, column=3)	 # row: 第 2 行  col: 第 3 列
for merged_range in merged_ranges:
    # cell.coordinate: 表示单元格的坐标,输出 C2
    if cell.coordinate in merged_range:  # 判断该单元格所属的合并区域
        return True
    return False
  
# 3.判断该单元格是否为合并单元格
## 方法一
from openpyxl.cell import MergedCell
isinstance(cell, MergedCell)	 # 用于检查 cell 对象是否是一个 MergedCell 的实例

## 方法二
if ws['A1'] in ws.merged_cells:
    print('A1是合并单元格')


# 4.获取合并区域左上角的单元格作为该单元格的值返回
# 即循环中的 merged_range
merged_range.min_row  # 合并单元格的最小行
merged_range.min_col  # 合并单元格的最小列
merged_range.max_row  # 合并单元格的最大行
merged_range.max_col  # 合并单元格的最大列

# 5.返回合并单元格的左上角至右下角单元格的行列号
from openpyxl.utils import range_boundaries
min_row, min_col, max_row, max_col = range_boundaries(merged_range)

2.实例

遍历整个 excel 文件,输出是否为单元格,如果是,则输出该单元格的合并范围

def parser_merged_cell(self, ws: Worksheet, row, col, merged_ranges):
    """
    判断单元格是否为合并单于格
    是:获取合并的偏移量,否:返回 None
    :param ws: 当前工作表对象
    :param row: 需要获取的单元格所在行
    :param col: 需要获取的单元格所在列
    :param merged_ranges: 所有合并单元格的范围
    :return: 单元格对象、合并范围
    """
    cell = ws.cell(row=row, column=col)
    if not isinstance(cell, MergedCell):  # 判断该单元格是否为合并单元格
        for merged_range in merged_ranges:  # 循环查找该单元格所属的合并区域
            if cell.coordinate in merged_range:
                # 获取合并区域左上角的单元格作为该单元格的值返回
                # +1 是为了横向或纵向没有合并时,表示存在一个占位
                coord = {
                    'x_use': merged_range.max_col - merged_range.min_col + 1,
                    'y_use': merged_range.max_row - merged_range.min_row + 1,
                }
                return cell, coord
        return cell, True
    return None, None
excel_data = []
for row_index in range(1, ws.max_row + 1):
    for col_index in range(1, ws.max_column + 1):
        pt = {
            'id': None,     # 单元格坐标ID
            'x': None,      # X轴位置
            'y': None,      # Y轴位置
            'value': '',    # 单元格的值
            'bg_color': '',  # 单元格背景颜色
            'is_edit': 1,   # 是否可以编辑
            'x_use': 1,     # X轴所占格数
            'y_use': 1,     # Y轴所占格数
        }
        cell_, coord = parser_merged_cell(ws, row_index, col_index, merged_ranges)
        # 过滤合并单元格造成的空单元格
        if cell_ and coord:
            pt['id'] = f'{col_index}_{row_index}'
            pt['x'] = col_index
            pt['y'] = row_index
            cell_v = cell_.value
            bg_color = cell_.fill.bgColor.value  # 获取背景色
            # 单元格的值不为空且无背景色:
            # 存在一个 key 列表,单元格值存在与该列表中,则不可编辑
            if cell_v:
                pt['value'] = cell_v
                if cell_v in detection_keys:
                    pt['is_edit'] = 0
                if is_template and cell_v and isinstance(bg_color, int):
                    pt['value'] = ''
            # coord:合并单元格所占的 X、Y 轴的长度
            if isinstance(coord, dict):
                pt.update(coord)
            # 用于判断单元格为空:且不可编辑
            # 单元格是否存在背景颜色(该位置颜色代码:64 灰色,占不判断)且值为空
            if isinstance(bg_color, int) and not cell_v:
                pt['is_edit'] = 0
                pt['bg_color'] = bg_color
            excel_data.append(pt)

6.图表

# 注意事项
图表的位置是通过指定单元格(如 "E5"、"E20")来确定的。
可以根据需要调整数据和图表的样式
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference, PieChart

def create_icon():
    # 创建一个新的工作簿
    wb = Workbook()
    ws = wb.active

    # 写入数据
    data = [
        ['品类', '销售额'],
        ['电子产品', 300],
        ['服装', 150],
        ['家居', 200],
        ['玩具', 100]
    ]

    for row in data:
        ws.append(row)

    # 创建柱状图
    bar_chart = BarChart()
    bar_chart.title = "销售额柱状图"
    bar_chart.x_axis.title = "品类"
    bar_chart.y_axis.title = "销售额"

    # 设置数据范围,即最小行至最大行、最小列至最大列
    data_ref = Reference(ws, min_col=2, min_row=1, max_col=2, max_row=5)
    categories_ref = Reference(ws, min_col=1, min_row=2, max_row=5)

    # 添加数据和类别
    bar_chart.add_data(data_ref, titles_from_data=True)
    bar_chart.set_categories(categories_ref)

    # 将柱状图插入工作表
    ws.add_chart(bar_chart, "E5")

    # 创建饼图
    pie_chart = PieChart()
    pie_chart.title = "销售额饼图"

    # 设置数据范围
    pie_chart.add_data(data_ref, titles_from_data=True)
    pie_chart.set_categories(categories_ref)

    # 将饼图插入工作表
    ws.add_chart(pie_chart, "E20")

    # 保存工作簿
    wb.save('second_workbook.xlsx')


if __name__ == '__main__':
    create_icon()
posted @ 2025-02-07 14:04  亦双弓  阅读(83)  评论(0)    收藏  举报