Appearance
2.1.Excel表格自动化
在日常办公中,Excel是最常用的数据处理工具之一。通过Python自动化Excel操作,可以大幅提高工作效率,减少重复劳动,降低人为错误。本文将介绍几种常用的Python操作Excel的方法,并提供实用的代码示例和应用场景。
组合xlrd、xlwt、xlutils实现excel读写操作
这三个库是早期Python操作Excel的经典组合,各司其职:xlrd负责读取,xlwt负责写入,xlutils作为两者的桥梁。虽然现在有了更强大的库,但在一些特定场景下,这个组合仍然有其价值。
安装这些库
python
pip install xlrd xlwt xlutils
读取Excel文件
python
import xlrd
def read_excel_file(file_path):
"""读取Excel文件并打印内容"""
# 打开工作簿
workbook = xlrd.open_workbook(file_path)
# 获取所有工作表名称
sheet_names = workbook.sheet_names()
print(f"工作表列表: {sheet_names}")
# 遍历每个工作表
for sheet_name in sheet_names:
sheet = workbook.sheet_by_name(sheet_name)
print(f"\n工作表: {sheet_name}, 行数: {sheet.nrows}, 列数: {sheet.ncols}")
# 打印表头
if sheet.nrows > 0:
header = [sheet.cell_value(0, col) for col in range(sheet.ncols)]
print(f"表头: {header}")
# 打印数据(最多显示5行)
for row in range(1, min(6, sheet.nrows)):
row_data = [sheet.cell_value(row, col) for col in range(sheet.ncols)]
print(f"第{row}行: {row_data}")
# 使用示例
read_excel_file("员工信息.xls")
写入Excel文件
python
import xlwt
def create_excel_file(file_path):
"""创建新的Excel文件"""
# 创建工作簿
workbook = xlwt.Workbook(encoding='utf-8')
# 添加工作表
sheet = workbook.add_sheet('员工信息')
# 定义样式
header_style = xlwt.easyxf('font: bold on; align: horiz center')
date_style = xlwt.easyxf(num_format_str='yyyy-mm-dd')
# 写入表头
headers = ['ID', '姓名', '部门', '入职日期', '薪资']
for col, header in enumerate(headers):
sheet.write(0, col, header, header_style)
# 准备数据
data = [
[1001, '张三', '技术部', '2020-01-15', 12000],
[1002, '李四', '市场部', '2019-05-23', 15000],
[1003, '王五', '财务部', '2021-03-08', 13500],
[1004, '赵六', '人事部', '2018-11-12', 14000],
]
# 写入数据
for row, row_data in enumerate(data, 1):
for col, cell_value in enumerate(row_data):
# 对日期使用特殊格式
if col == 3: # 入职日期列
import datetime
date_parts = cell_value.split('-')
date_obj = datetime.datetime(int(date_parts[0]), int(date_parts[1]), int(date_parts[2]))
sheet.write(row, col, date_obj, date_style)
else:
sheet.write(row, col, cell_value)
# 保存文件
workbook.save(file_path)
print(f"Excel文件已创建: {file_path}")
# 使用示例
create_excel_file("新员工信息.xls")
修改现有Excel文件
python
import xlrd
import xlwt
from xlutils.copy import copy
def update_excel_file(file_path, employee_id, new_salary):
"""更新指定员工的薪资信息"""
# 打开原工作簿(只读模式)
rb = xlrd.open_workbook(file_path, formatting_info=True)
sheet = rb.sheet_by_index(0)
# 创建一个可写的副本
wb = copy(rb)
w_sheet = wb.get_sheet(0)
# 查找员工ID并更新薪资
found = False
for row in range(1, sheet.nrows):
if int(sheet.cell_value(row, 0)) == employee_id: # 假设ID在第一列
w_sheet.write(row, 4, new_salary) # 假设薪资在第五列
found = True
break
if found:
# 保存修改后的文件
wb.save(file_path)
print(f"已更新员工ID {employee_id} 的薪资为 {new_salary}")
else:
print(f"未找到员工ID: {employee_id}")
# 使用示例
update_excel_file("员工信息.xls", 1002, 16000)
使用openpyxl实现excel的读写修改
openpyxl是目前最流行的Python Excel处理库之一,功能全面,API友好,特别适合处理较新的Excel格式(.xlsx)。
安装openpyxl
python
pip install openpyxl
读取Excel文件
python
from openpyxl import load_workbook
def read_excel_with_openpyxl(file_path):
"""使用openpyxl读取Excel文件"""
# 加载工作簿
wb = load_workbook(file_path, read_only=True)
# 获取所有工作表名称
sheet_names = wb.sheetnames
print(f"工作表列表: {sheet_names}")
# 遍历每个工作表
for sheet_name in sheet_names:
sheet = wb[sheet_name]
print(f"\n工作表: {sheet_name}")
# 获取表格尺寸
if not sheet.max_row: # 对于read_only模式,需要遍历才能获取尺寸
print("工作表为空或使用read_only模式无法直接获取尺寸")
continue
# 打印表头
header = [cell.value for cell in next(sheet.iter_rows())]
print(f"表头: {header}")
# 打印数据(最多5行)
row_count = 0
for row in sheet.iter_rows(min_row=2): # 从第二行开始
if row_count >= 5:
break
row_data = [cell.value for cell in row]
print(f"行 {row_count + 2}: {row_data}")
row_count += 1
# 关闭工作簿
wb.close()
# 使用示例
read_excel_with_openpyxl("员工信息.xlsx")
创建新的Excel文件
python
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, PatternFill
from openpyxl.utils import get_column_letter
import datetime
def create_excel_with_openpyxl(file_path):
"""使用openpyxl创建格式化的Excel文件"""
# 创建工作簿
wb = Workbook()
sheet = wb.active
sheet.title = "销售数据"
# 定义样式
header_font = Font(name='Arial', size=12, bold=True, color="FFFFFF")
header_fill = PatternFill("solid", fgColor="4F81BD")
centered = Alignment(horizontal="center")
# 写入表头
headers = ['产品ID', '产品名称', '类别', '单价', '销售日期', '销售量', '销售额']
for col_num, header in enumerate(headers, 1):
cell = sheet.cell(row=1, column=col_num)
cell.value = header
cell.font = header_font
cell.fill = header_fill
cell.alignment = centered
# 准备数据
data = [
[101, '笔记本电脑', '电子产品', 5999, datetime.date(2023, 1, 15), 10, '=D2*F2'],
[102, '办公椅', '办公家具', 899, datetime.date(2023, 1, 16), 20, '=D3*F3'],
[103, '打印机', '办公设备', 1299, datetime.date(2023, 1, 18), 5, '=D4*F4'],
[104, '显示器', '电子产品', 1499, datetime.date(2023, 1, 20), 15, '=D5*F5'],
[105, '文件柜', '办公家具', 699, datetime.date(2023, 1, 22), 8, '=D6*F6'],
]
# 写入数据
for row_num, row_data in enumerate(data, 2):
for col_num, cell_value in enumerate(row_data, 1):
cell = sheet.cell(row=row_num, column=col_num)
cell.value = cell_value
if col_num == 5: # 日期列使用日期格式
cell.number_format = 'yyyy-mm-dd'
elif col_num == 7: # 销售额列使用公式和货币格式
cell.number_format = '¥#,##0.00'
# 添加合计行
total_row = len(data) + 2
sheet.cell(row=total_row, column=1).value = "合计"
sheet.cell(row=total_row, column=1).font = Font(bold=True)
# 销售量合计
sheet.cell(row=total_row, column=6).value = f"=SUM(F2:F{total_row-1})"
sheet.cell(row=total_row, column=6).font = Font(bold=True)
# 销售额合计
sheet.cell(row=total_row, column=7).value = f"=SUM(G2:G{total_row-1})"
sheet.cell(row=total_row, column=7).font = Font(bold=True)
sheet.cell(row=total_row, column=7).number_format = '¥#,##0.00'
# 调整列宽
for col in range(1, len(headers) + 1):
sheet.column_dimensions[get_column_letter(col)].width = 15
# 保存文件
wb.save(file_path)
print(f"Excel文件已创建: {file_path}")
# 使用示例
create_excel_with_openpyxl("销售数据.xlsx")
处理大型Excel文件
python
from openpyxl import load_workbook
import time
def process_large_excel(file_path):
"""使用read_only模式处理大型Excel文件"""
start_time = time.time()
# 使用read_only模式加载工作簿
wb = load_workbook(file_path, read_only=True)
sheet = wb.active
# 统计数据
row_count = 0
sum_value = 0
# 假设第5列是数值,我们要计算其总和
for row in sheet.iter_rows(min_row=2, values_only=True):
row_count += 1
if len(row) >= 5 and row[4] is not None:
try:
sum_value += float(row[4])
except (ValueError, TypeError):
pass
# 每处理10000行打印一次进度
if row_count % 10000 == 0:
print(f"已处理 {row_count} 行...")
# 关闭工作簿
wb.close()
end_time = time.time()
print(f"处理完成,共 {row_count} 行数据")
print(f"第5列数值总和: {sum_value}")
print(f"处理时间: {end_time - start_time:.2f} 秒")
# 使用示例(对于大型文件)
# process_large_excel("大型数据集.xlsx")
使用xlwings模块操控excel文档
xlwings是一个强大的库,可以直接与Excel应用程序交互,实现自动化操作,甚至可以调用Excel的VBA函数。
安装xlwings
python
pip install xlwings
基本操作
python
import xlwings as xw
def automate_excel_with_xlwings():
"""使用xlwings自动化Excel操作"""
# 启动Excel应用
app = xw.App(visible=True) # visible=True让Excel可见,便于观察操作过程
try:
# 创建新工作簿
wb = app.books.add()
sheet = wb.sheets[0]
sheet.name = "销售报表"
# 添加表头
sheet.range("A1").value = "产品"
sheet.range("B1").value = "一季度"
sheet.range("C1").value = "二季度"
sheet.range("D1").value = "三季度"
sheet.range("E1").value = "四季度"
sheet.range("F1").value = "年度总计"
# 设置表头格式
header_range = sheet.range("A1:F1")
header_range.color = (0, 112, 192) # 蓝色背景
header_range.font.color = (255, 255, 255) # 白色文字
header_range.font.bold = True
# 添加数据
data = [
["产品A", 100, 120, 140, 130],
["产品B", 90, 100, 110, 120],
["产品C", 80, 85, 90, 95],
]
# 写入数据
sheet.range("A2").value = data
# 添加公式计算年度总计
for i in range(len(data)):
row = i + 2 # 数据从第2行开始
sheet.range(f"F{row}").formula = f"=SUM(B{row}:E{row})"
# 添加合计行
total_row = len(data) + 2
sheet.range(f"A{total_row}").value = "合计"
sheet.range(f"A{total_row}").font.bold = True
# 添加合计公式
for col in "BCDEF":
sheet.range(f"{col}{total_row}").formula = f"=SUM({col}2:{col}{total_row-1})"
sheet.range(f"{col}{total_row}").font.bold = True
# 添加图表
chart = sheet.charts.add()
chart.set_source_data(sheet.range(f"A1:E{len(data)+1}"))
chart.chart_type = "column_clustered"
chart.name = "季度销售图表"
chart.top = sheet.range(f"A{total_row+2}").top
chart.left = sheet.range("A1").left
# 调整列宽
sheet.autofit()
# 保存文件
wb.save("xlwings_销售报表.xlsx")
print("Excel文件已创建并保存")
finally:
# 关闭工作簿和应用
wb.close()
app.quit()
# 使用示例
# automate_excel_with_xlwings()
与Excel VBA结合使用
python
import xlwings as xw
def run_excel_macro():
"""运行Excel中的VBA宏"""
# 打开包含宏的工作簿
wb = xw.Book("带宏的工作簿.xlsm")
try:
# 运行名为'ProcessData'的宏
wb.macro("ProcessData")()
print("宏已执行完成")
# 读取宏处理后的结果
sheet = wb.sheets["结果"]
result = sheet.range("A1:C10").value
print("处理结果:")
for row in result:
print(row)
finally:
# 保存并关闭工作簿
wb.save()
wb.close()
# 使用示例(需要有包含'ProcessData'宏的Excel文件)
# run_excel_macro()
使用Pandas轻松处理多个excel工作薄
Pandas是数据分析的利器,它提供了强大的数据结构和操作功能,特别适合处理表格数据。
安装Pandas
python
pip install pandas
读取Excel文件
python
import pandas as pd
def read_excel_with_pandas(file_path):
"""使用pandas读取Excel文件"""
# 读取所有工作表
xlsx = pd.ExcelFile(file_path)
# 获取所有工作表名称
sheet_names = xlsx.sheet_names
print(f"工作表列表: {sheet_names}")
# 遍历每个工作表
for sheet_name in sheet_names:
# 读取工作表到DataFrame
df = pd.read_excel(xlsx, sheet_name)
print(f"\n工作表: {sheet_name}, 形状: {df.shape}")
# 显示前5行数据
print("\n数据预览:")
print(df.head())
# 显示基本统计信息
print("\n数值列统计信息:")
print(df.describe())
# 使用示例
read_excel_with_pandas("销售数据.xlsx")
数据处理与分析
python
import pandas as pd
import matplotlib.pyplot as plt
def analyze_sales_data(file_path):
"""使用pandas分析销售数据"""
# 读取Excel文件
df = pd.read_excel(file_path)
# 显示基本信息
print("数据基本信息:")
print(df.info())
# 按类别分组统计
category_stats = df.groupby('类别').agg({
'销售量': 'sum',
'销售额': 'sum'
}).sort_values('销售额', ascending=False)
print("\n按类别统计:")
print(category_stats)
# 按月份分析销售趋势
df['月份'] = pd.to_datetime(df['销售日期']).dt.month
monthly_sales = df.groupby('月份').agg({
'销售量': 'sum',
'销售额': 'sum'
})
print("\n按月份统计:")
print(monthly_sales)
# 创建图表
plt.figure(figsize=(12, 5))
# 销售额柱状图
plt.subplot(1, 2, 1)
category_stats['销售额'].plot(kind='bar', color='skyblue')
plt.title('各类别销售额')
plt.ylabel('销售额')
plt.xticks(rotation=45)
# 月度销售趋势图
plt.subplot(1, 2, 2)
monthly_sales['销售额'].plot(marker='o', color='green')
plt.title('月度销售趋势')
plt.xlabel('月份')
plt.ylabel('销售额')
plt.tight_layout()
plt.savefig('销售分析.png')
plt.close()
print("\n分析图表已保存为'销售分析.png'")
# 返回处理后的数据
return df, category_stats, monthly_sales
# 使用示例
# analyze_sales_data("销售数据.xlsx")
合并多个Excel文件
python
import pandas as pd
import os
def merge_excel_files(directory, output_file):
"""合并目录下的所有Excel文件"""
# 获取目录下所有Excel文件
excel_files = [f for f in os.listdir(directory)
if f.endswith('.xlsx') or f.endswith('.xls')]
if not excel_files:
print(f"目录 {directory} 中没有找到Excel文件")
return
print(f"找到 {len(excel_files)} 个Excel文件")
# 创建一个空的DataFrame列表
dfs = []
# 读取每个Excel文件
for file in excel_files:
file_path = os.path.join(directory, file)
print(f"处理文件: {file}")
# 读取所有工作表
xlsx = pd.ExcelFile(file_path)
for sheet_name in xlsx.sheet_names:
# 读取工作表
df = pd.read_excel(xlsx, sheet_name)
# 添加文件名和工作表名列
df['源文件'] = file
df['工作表'] = sheet_name
# 添加到列表
dfs.append(df)
# 合并所有DataFrame
if dfs:
merged_df = pd.concat(dfs, ignore_index=True)
# 保存合并后的数据
merged_df.to_excel(output_file, index=False)
print(f"已将 {len(dfs)} 个工作表合并到 {output_file}")
print(f"合并后的数据形状: {merged_df.shape}")
else:
print("没有找到有效的数据表")
# 使用示例
# merge_excel_files("excel_files", "合并数据.xlsx")
实际应用场景
场景一:销售数据自动化报表
python
import pandas as pd
import matplotlib.pyplot as plt
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference, LineChart
from openpyxl.styles import Font, PatternFill, Alignment
from openpyxl.utils import get_column_letter
import datetime
def generate_sales_report(sales_data_file, output_file):
"""生成销售数据分析报表"""
# 读取销售数据
df = pd.read_excel(sales_data_file)
# 数据清洗和准备
df['销售日期'] = pd.to_datetime(df['销售日期'])
df['月份'] = df['销售日期'].dt.month
df['季度'] = df['销售日期'].dt.quarter
# 按产品和月份分组统计
product_monthly = df.pivot_table(
index='产品名称',
columns='月份',
values='销售额',
aggfunc='sum',
fill_value=0
)
# 按类别和季度分组统计
category_quarterly = df.pivot_table(
index='类别',
columns='季度',
values=['销售量', '销售额'],
aggfunc='sum',
fill_value=0
)
# 计算总计和环比
product_monthly['总计'] = product_monthly.sum(axis=1)
product_monthly = product_monthly.sort_values('总计', ascending=False)
# 创建Excel工作簿
wb = Workbook()
# 创建产品月度销售工作表
ws1 = wb.active
ws1.title = "产品月度销售"
# 写入表头
headers = ['产品名称'] + [f"{i}月" for i in sorted(product_monthly.columns[:-1])] + ['总计']
for col_num, header in enumerate(headers, 1):
cell = ws1.cell(row=1, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="4F81BD")
cell.alignment = Alignment(horizontal="center")
# 写入数据
for row_num, (index, data) in enumerate(product_monthly.iterrows(), 2):
ws1.cell(row=row_num, column=1).value = index # 产品名称
for col_num, value in enumerate(data.values, 2):
cell = ws1.cell(row=row_num, column=col_num)
cell.value = value
cell.number_format = '#,##0.00'
# 添加合计行
total_row = len(product_monthly) + 2
ws1.cell(row=total_row, column=1).value = "总计"
ws1.cell(row=total_row, column=1).font = Font(bold=True)
for col in range(2, len(headers) + 1):
col_letter = get_column_letter(col)
ws1.cell(row=total_row, column=col).value = f"=SUM({col_letter}2:{col_letter}{total_row-1})"
ws1.cell(row=total_row, column=col).font = Font(bold=True)
ws1.cell(row=total_row, column=col).number_format = '#,##0.00'
# 创建图表
chart = BarChart()
chart.title = "产品销售额对比"
chart.x_axis.title = "产品"
chart.y_axis.title = "销售额"
# 设置图表数据范围
data = Reference(ws1, min_col=2, min_row=1, max_row=min(11, total_row-1), max_col=len(headers)-1)
cats = Reference(ws1, min_col=1, min_row=2, max_row=min(11, total_row-1))
chart.add_data(data, titles_from_data=True)
chart.set_categories(cats)
# 添加图表到工作表
ws1.add_chart(chart, "A" + str(total_row + 2))
# 创建类别季度销售工作表
ws2 = wb.create_sheet(title="类别季度分析")
# 重新组织数据以便于写入
category_data = []
for category in category_quarterly.index:
row = [category]
for quarter in sorted(df['季度'].unique()):
row.append(category_quarterly.loc[category, ('销售量', quarter)])
row.append(category_quarterly.loc[category, ('销售额', quarter)])
category_data.append(row)
# 写入表头
headers = ['类别']
for quarter in sorted(df['季度'].unique()):
headers.extend([f"Q{quarter}销量", f"Q{quarter}销售额"])
for col_num, header in enumerate(headers, 1):
cell = ws2.cell(row=1, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="4F81BD")
cell.alignment = Alignment(horizontal="center")
# 写入数据
for row_num, row_data in enumerate(category_data, 2):
for col_num, value in enumerate(row_data, 1):
cell = ws2.cell(row=row_num, column=col_num)
cell.value = value
if col_num % 2 == 0: # 销量列
cell.number_format = '#,##0'
elif col_num % 2 == 1 and col_num > 1: # 销售额列
cell.number_format = '#,##0.00'
# 创建折线图
line_chart = LineChart()
line_chart.title = "季度销售趋势"
line_chart.x_axis.title = "季度"
line_chart.y_axis.title = "销售额"
# 设置图表数据范围(只取销售额列)
quarters = len(df['季度'].unique())
data = Reference(ws2, min_col=3, min_row=1, max_row=len(category_data)+1, max_col=2*quarters, min_col_offset=1)
cats = Reference(ws2, min_col=1, min_row=2, max_row=len(category_data)+1)
line_chart.add_data(data, titles_from_data=True)
line_chart.set_categories(cats)
# 添加图表到工作表
ws2.add_chart(line_chart, "A" + str(len(category_data) + 3))
# 调整列宽
for ws in [ws1, ws2]:
for col in range(1, ws.max_column + 1):
ws.column_dimensions[get_column_letter(col)].width = 15
# 保存工作簿
wb.save(output_file)
print(f"销售报表已生成: {output_file}")
# 使用示例
# generate_sales_report("原始销售数据.xlsx", "销售分析报表.xlsx")
场景二:库存管理系统
python
import pandas as pd
from openpyxl import load_workbook, Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
import datetime
import os
class InventoryManager:
def __init__(self, inventory_file):
"""初始化库存管理系统"""
self.inventory_file = inventory_file
# 如果文件不存在,创建一个新的库存文件
if not os.path.exists(inventory_file):
self._create_new_inventory_file()
# 加载库存数据
self.load_inventory()
def _create_new_inventory_file(self):
"""创建新的库存文件"""
wb = Workbook()
ws = wb.active
ws.title = "库存"
# 设置表头
headers = ['产品ID', '产品名称', '类别', '供应商', '单价', '库存量', '库存价值', '最后更新']
for col_num, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="4F81BD")
cell.alignment = Alignment(horizontal="center")
# 设置示例数据
sample_data = [
[1001, '笔记本电脑', '电子产品', 'A供应商', 5999, 10, '=E2*F2', datetime.datetime.now()],
[1002, '办公椅', '办公家具', 'B供应商', 899, 20, '=E3*F3', datetime.datetime.now()],
]
for row_num, row_data in enumerate(sample_data, 2):
for col_num, value in enumerate(row_data, 1):
cell = ws.cell(row=row_num, column=col_num)
cell.value = value
if col_num == 5: # 单价列
cell.number_format = '¥#,##0.00'
elif col_num == 7: # 库存价值列
cell.number_format = '¥#,##0.00'
elif col_num == 8: # 日期列
cell.number_format = 'yyyy-mm-dd hh:mm:ss'
# 创建入库记录工作表
ws_in = wb.create_sheet(title="入库记录")
headers = ['记录ID', '产品ID', '产品名称', '入库数量', '单价', '总价值', '供应商', '入库日期', '操作人']
for col_num, header in enumerate(headers, 1):
cell = ws_in.cell(row=1, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="4F81BD")
cell.alignment = Alignment(horizontal="center")
# 创建出库记录工作表
ws_out = wb.create_sheet(title="出库记录")
headers = ['记录ID', '产品ID', '产品名称', '出库数量', '单价', '总价值', '客户', '出库日期', '操作人']
for col_num, header in enumerate(headers, 1):
cell = ws_out.cell(row=1, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="4F81BD")
cell.alignment = Alignment(horizontal="center")
# 调整所有工作表的列宽
for ws in wb.worksheets:
for col in range(1, len(headers) + 1):
ws.column_dimensions[get_column_letter(col)].width = 15
# 保存文件
wb.save(self.inventory_file)
print(f"已创建新的库存文件: {self.inventory_file}")
def load_inventory(self):
"""加载库存数据"""
# 使用pandas读取Excel文件的所有工作表
self.inventory_df = pd.read_excel(self.inventory_file, sheet_name="库存")
self.in_records_df = pd.read_excel(self.inventory_file, sheet_name="入库记录")
self.out_records_df = pd.read_excel(self.inventory_file, sheet_name="出库记录")
print("库存数据已加载")
print(f"当前库存: {len(self.inventory_df)} 种产品")
print(f"入库记录: {len(self.in_records_df)} 条")
print(f"出库记录: {len(self.out_records_df)} 条")
def add_product(self, product_id, name, category, supplier, price, quantity):
"""添加新产品到库存"""
# 检查产品ID是否已存在
if product_id in self.inventory_df['产品ID'].values:
print(f"错误: 产品ID {product_id} 已存在")
return False
# 创建新产品记录
new_product = {
'产品ID': product_id,
'产品名称': name,
'类别': category,
'供应商': supplier,
'单价': price,
'库存量': quantity,
'库存价值': price * quantity,
'最后更新': datetime.datetime.now()
}
# 添加到DataFrame
self.inventory_df = self.inventory_df.append(new_product, ignore_index=True)
# 添加入库记录
in_record = {
'记录ID': len(self.in_records_df) + 1,
'产品ID': product_id,
'产品名称': name,
'入库数量': quantity,
'单价': price,
'总价值': price * quantity,
'供应商': supplier,
'入库日期': datetime.datetime.now(),
'操作人': 'system'
}
self.in_records_df = self.in_records_df.append(in_record, ignore_index=True)
# 保存更改
self._save_to_excel()
print(f"已添加新产品: {name} (ID: {product_id})")
return True
def update_stock(self, product_id, quantity_change, is_incoming=True, customer_or_supplier=None, operator='system'):
"""更新库存"""
# 查找产品
product_mask = self.inventory_df['产品ID'] == product_id
if not any(product_mask):
print(f"错误: 产品ID {product_id} 不存在")
return False
# 获取产品信息
product_idx = product_mask.idxmax()
product = self.inventory_df.loc[product_idx]
# 计算新库存量
new_quantity = product['库存量'] + quantity_change if is_incoming else product['库存量'] - quantity_change
# 检查库存是否足够(出库时)
if not is_incoming and new_quantity < 0:
print(f"错误: 产品 {product['产品名称']} 库存不足,当前库存: {product['库存量']}")
return False
# 更新库存
self.inventory_df.at[product_idx, '库存量'] = new_quantity
self.inventory_df.at[product_idx, '库存价值'] = new_quantity * product['单价']
self.inventory_df.at[product_idx, '最后更新'] = datetime.datetime.now()
# 添加记录
if is_incoming:
# 入库记录
record = {
'记录ID': len(self.in_records_df) + 1,
'产品ID': product_id,
'产品名称': product['产品名称'],
'入库数量': quantity_change,
'单价': product['单价'],
'总价值': quantity_change * product['单价'],
'供应商': customer_or_supplier or product['供应商'],
'入库日期': datetime.datetime.now(),
'操作人': operator
}
self.in_records_df = self.in_records_df.append(record, ignore_index=True)
else:
# 出库记录
record = {
'记录ID': len(self.out_records_df) + 1,
'产品ID': product_id,
'产品名称': product['产品名称'],
'出库数量': quantity_change,
'单价': product['单价'],
'总价值': quantity_change * product['单价'],
'客户': customer_or_supplier or '未指定',
'出库日期': datetime.datetime.now(),
'操作人': operator
}
self.out_records_df = self.out_records_df.append(record, ignore_index=True)
# 保存更改
self._save_to_excel()
action = "入库" if is_incoming else "出库"
print(f"已{action} {product['产品名称']} {quantity_change} 个,当前库存: {new_quantity}")
return True
def generate_inventory_report(self, output_file):
"""生成库存报表"""
# 创建一个新的工作簿
wb = Workbook()
ws = wb.active
ws.title = "库存报表"
# 添加报表标题
ws.merge_cells('A1:H1')
title_cell = ws['A1']
title_cell.value = "库存状况报表"
title_cell.font = Font(size=16, bold=True)
title_cell.alignment = Alignment(horizontal="center")
# 添加报表生成时间
ws.merge_cells('A2:H2')
date_cell = ws['A2']
date_cell.value = f"生成时间: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
date_cell.alignment = Alignment(horizontal="center")
# 添加表头
headers = ['产品ID', '产品名称', '类别', '供应商', '单价', '库存量', '库存价值', '库存状态']
for col_num, header in enumerate(headers, 1):
cell = ws.cell(row=4, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="4F81BD")
cell.alignment = Alignment(horizontal="center")
# 添加数据
# 计算库存状态
def get_stock_status(row):
if row['库存量'] <= 0:
return "缺货"
elif row['库存量'] < 5:
return "库存不足"
elif row['库存量'] > 20:
return "库存过多"
else:
return "正常"
# 添加库存状态列
self.inventory_df['库存状态'] = self.inventory_df.apply(get_stock_status, axis=1)
# 按类别和库存状态排序
sorted_df = self.inventory_df.sort_values(['类别', '库存状态'])
# 写入数据
for row_num, (_, row) in enumerate(sorted_df.iterrows(), 5):
for col_num, column in enumerate(headers, 1):
cell = ws.cell(row=row_num, column=col_num)
value = row[column] if column in row else ""
cell.value = value
# 设置格式
if column == '单价':
cell.number_format = '¥#,##0.00'
elif column == '库存价值':
cell.number_format = '¥#,##0.00'
# 设置库存状态的颜色
if column == '库存状态':
if value == "缺货":
cell.fill = PatternFill("solid", fgColor="FF0000")
elif value == "库存不足":
cell.fill = PatternFill("solid", fgColor="FFC000")
elif value == "库存过多":
cell.fill = PatternFill("solid", fgColor="92D050")
# 添加合计行
total_row = len(sorted_df) + 5
ws.cell(row=total_row, column=1).value = "合计"
ws.cell(row=total_row, column=1).font = Font(bold=True)
# 计算总库存量和总价值
ws.cell(row=total_row, column=6).value = sorted_df['库存量'].sum()
ws.cell(row=total_row, column=6).font = Font(bold=True)
ws.cell(row=total_row, column=7).value = sorted_df['库存价值'].sum()
ws.cell(row=total_row, column=7).font = Font(bold=True)
ws.cell(row=total_row, column=7).number_format = '¥#,##0.00'
# 添加类别统计
ws.cell(row=total_row + 2, column=1).value = "类别统计"
ws.cell(row=total_row + 2, column=1).font = Font(bold=True)
category_stats = sorted_df.groupby('类别').agg({
'产品ID': 'count',
'库存量': 'sum',
'库存价值': 'sum'
}).reset_index()
# 写入类别统计表头
category_headers = ['类别', '产品数量', '总库存量', '总库存价值']
for col_num, header in enumerate(category_headers, 1):
cell = ws.cell(row=total_row + 3, column=col_num)
cell.value = header
cell.font = Font(bold=True)
cell.fill = PatternFill("solid", fgColor="A5A5A5")
# 写入类别统计数据
for row_num, (_, row) in enumerate(category_stats.iterrows(), total_row + 4):
ws.cell(row=row_num, column=1).value = row['类别']
ws.cell(row=row_num, column=2).value = row['产品ID']
ws.cell(row=row_num, column=3).value = row['库存量']
ws.cell(row=row_num, column=4).value = row['库存价值']
ws.cell(row=row_num, column=4).number_format = '¥#,##0.00'
# 调整列宽
for col in range(1, len(headers) + 1):
ws.column_dimensions[get_column_letter(col)].width = 15
# 保存报表
wb.save(output_file)
print(f"库存报表已生成: {output_file}")
return output_file
def _save_to_excel(self):
"""保存数据到Excel文件"""
with pd.ExcelWriter(self.inventory_file, engine='openpyxl') as writer:
self.inventory_df.to_excel(writer, sheet_name="库存", index=False)
self.in_records_df.to_excel(writer, sheet_name="入库记录", index=False)
self.out_records_df.to_excel(writer, sheet_name="出库记录", index=False)
# 使用示例
# inventory = InventoryManager("库存管理.xlsx")
# inventory.add_product(1003, "打印机", "办公设备", "C供应商", 1299, 5)
# inventory.update_stock(1001, 5, is_incoming=True, customer_or_supplier="A供应商", operator="张三")
# inventory.update_stock(1002, 2, is_incoming=False, customer_or_supplier="客户A", operator="李四")
# inventory.generate_inventory_report("库存报表.xlsx")
通过这些代码示例和实际应用场景,你可以轻松掌握Python Excel自动化的各种技巧,大幅提高工作效率。无论是简单的数据处理,还是复杂的报表生成,Python都能帮你轻松应对。