0%

Python操作CSV文件完全指南

CSV(Comma-Separated Values,逗号分隔值)是一种简单、通用的数据交换格式,广泛应用于数据分析、数据迁移和自动化脚本中。Python提供了多种方式来操作CSV文件,从内置的csv模块到强大的第三方库如pandas和numpy。本文将详细介绍如何使用Python操作CSV文件,包括读取、写入、修改和分析CSV数据。

一、依赖的库

Python操作CSV文件主要依赖以下几个库:

1. csv(内置库)

csv是Python内置的CSV文件处理库,无需额外安装,适合处理简单的CSV文件。

2. pandas

pandas是一个强大的数据分析库,提供了高效的CSV文件读写和处理功能,适合处理大规模数据和复杂分析。

安装方法

1
pip install pandas

版本要求

  • 推荐版本:v2.2.4或更高

3. numpy

numpy是一个用于科学计算的库,也提供了CSV文件的读写功能,适合处理数值型数据。

安装方法

1
pip install numpy

版本要求

  • 推荐版本:v2.1.0或更高

二、使用Python内置csv模块操作CSV文件

1. 写入CSV文件

基本写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import csv

# 数据
rows = [
['姓名', '年龄', '城市'],
['张三', 28, '北京'],
['李四', 32, '上海'],
['王五', 25, '广州'],
['赵六', 35, '深圳']
]

# 写入CSV文件
with open('people.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file)
writer.writerows(rows)

print("CSV文件写入成功!")

使用DictWriter写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import csv

# 数据
data = [
{'姓名': '张三', '年龄': 28, '城市': '北京'},
{'姓名': '李四', '年龄': 32, '城市': '上海'},
{'姓名': '王五', '年龄': 25, '城市': '广州'}
]

# 字段名
fields = ['姓名', '年龄', '城市']

# 写入CSV文件
with open('people_dict.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=fields)
writer.writeheader() # 写入表头
writer.writerows(data) # 写入数据

print("使用DictWriter写入CSV文件成功!")

2. 读取CSV文件

基本读取

1
2
3
4
5
6
7
import csv

# 读取CSV文件
with open('people.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
print(row)

使用DictReader读取

1
2
3
4
5
6
7
import csv

# 读取CSV文件
with open('people_dict.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for row in reader:
print(row['姓名'], row['年龄'], row['城市'])

3. 高级操作

指定分隔符

1
2
3
4
5
6
7
8
9
10
11
12
import csv

# 写入使用分号分隔的CSV文件
with open('people_semicolon.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file, delimiter=';')
writer.writerows(rows)

# 读取使用分号分隔的CSV文件
with open('people_semicolon.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file, delimiter=';')
for row in reader:
print(row)

处理引号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import csv

# 写入包含引号的数据
with open('quotes.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.writer(file, quoting=csv.QUOTE_ALL) # 所有字段加引号
writer.writerow(['姓名', '引言'])
writer.writerow(['张三', '"生活就像海洋"'])
writer.writerow(['李四', '"不经历风雨,怎么见彩虹"'])

# 读取包含引号的数据
with open('quotes.csv', 'r', encoding='utf-8') as file:
reader = csv.reader(file)
for row in reader:
print(row)

三、使用pandas库操作CSV文件

1. 读取CSV文件

基本读取

1
2
3
4
5
import pandas as pd

# 读取CSV文件
df = pd.read_csv('people.csv')
print(df)

读取指定列

1
2
3
# 读取指定列
df = pd.read_csv('people.csv', usecols=['姓名', '城市'])
print(df)

读取指定行数

1
2
3
# 读取前3行
df = pd.read_csv('people.csv', nrows=3)
print(df)

处理缺失值

1
2
3
4
5
6
7
# 读取CSV文件,将'NA'和'缺失'视为缺失值
df = pd.read_csv('people.csv', na_values=['NA', '缺失'])
print(df)

# 填充缺失值
df.fillna(0, inplace=True)
print(df)

设置索引列

1
2
3
# 使用'姓名'列作为索引
df = pd.read_csv('people.csv', index_col='姓名')
print(df)

2. 写入CSV文件

基本写入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd

# 创建DataFrame
data = {
'姓名': ['张三', '李四', '王五', '赵六'],
'年龄': [28, 32, 25, 35],
'城市': ['北京', '上海', '广州', '深圳']
}

df = pd.DataFrame(data)

# 写入CSV文件
df.to_csv('people_pandas.csv', index=False, encoding='utf-8')
print("使用pandas写入CSV文件成功!")

写入指定格式

1
2
3
4
5
# 写入CSV文件,设置保留两位小数
df.to_csv('people_format.csv', index=False, float_format='%.2f', encoding='utf-8')

# 写入CSV文件,使用分号分隔
df.to_csv('people_semicolon_pandas.csv', index=False, sep=';', encoding='utf-8')

3. 数据处理

筛选数据

1
2
3
4
5
6
7
# 筛选年龄大于30的数据
df_filtered = df[df['年龄'] > 30]
print(df_filtered)

# 筛选来自北京或上海的数据
df_filtered = df[df['城市'].isin(['北京', '上海'])]
print(df_filtered)

排序数据

1
2
3
4
5
6
7
# 按年龄升序排序
df_sorted = df.sort_values(by='年龄')
print(df_sorted)

# 按年龄降序排序
df_sorted = df.sort_values(by='年龄', ascending=False)
print(df_sorted)

分组统计

1
2
3
# 按城市分组,计算平均年龄
df_grouped = df.groupby('城市')['年龄'].mean()
print(df_grouped)

添加新列

1
2
3
# 添加新列
df['年龄分类'] = df['年龄'].apply(lambda x: '青年' if x < 30 else '中年')
print(df)

四、使用numpy库操作CSV文件

1. 读取CSV文件

基本读取

1
2
3
4
5
import numpy as np

# 读取CSV文件
data = np.genfromtxt('people.csv', delimiter=',', dtype=str)
print(data)

跳过表头

1
2
3
# 读取CSV文件,跳过表头
data = np.genfromtxt('people.csv', delimiter=',', dtype=str, skip_header=1)
print(data)

指定数据类型

1
2
3
4
5
6
7
# 读取CSV文件,指定数据类型
# 第一列是字符串,第二列是整数,第三列是字符串
data = np.genfromtxt('people.csv', delimiter=',', dtype=[('name', 'U10'), ('age', int), ('city', 'U10')], skip_header=1)
print(data)
print(data['name'])
print(data['age'])
print(data['city'])

2. 写入CSV文件

基本写入

1
2
3
4
5
6
7
8
9
10
11
12
13
import numpy as np

# 创建数据
data = np.array([
['姓名', '年龄', '城市'],
['张三', '28', '北京'],
['李四', '32', '上海'],
['王五', '25', '广州']
])

# 写入CSV文件
np.savetxt('people_numpy.csv', data, delimiter=',', fmt='%s', encoding='utf-8')
print("使用numpy写入CSV文件成功!")

写入数值数据

1
2
3
4
5
6
7
8
9
# 创建数值数据
numeric_data = np.array([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
])

# 写入CSV文件,保留两位小数
np.savetxt('numeric_data.csv', numeric_data, delimiter=',', fmt='%.2f', encoding='utf-8')

五、完整代码示例

1. 示例1:使用csv模块管理学生成绩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import csv

# 学生成绩数据
students = [
{'姓名': '张三', '语文': 85, '数学': 92, '英语': 78},
{'姓名': '李四', '语文': 90, '数学': 88, '英语': 95},
{'姓名': '王五', '语文': 76, '数学': 85, '英语': 82},
{'姓名': '赵六', '语文': 92, '数学': 94, '英语': 89}
]

fields = ['姓名', '语文', '数学', '英语']

# 写入学生成绩到CSV文件
with open('students_scores.csv', 'w', newline='', encoding='utf-8') as file:
writer = csv.DictWriter(file, fieldnames=fields)
writer.writeheader()
writer.writerows(students)

print("学生成绩已写入CSV文件!")

# 读取并分析学生成绩
print("\n读取并分析学生成绩:")
total_scores = {}
subjects = ['语文', '数学', '英语']

with open('students_scores.csv', 'r', encoding='utf-8') as file:
reader = csv.DictReader(file)
for student in reader:
name = student['姓名']
total = sum(int(student[subj]) for subj in subjects)
avg = total / len(subjects)
total_scores[name] = {'总分': total, '平均分': avg}
print(f"{name}: 总分={total}, 平均分={avg:.2f}")

# 找出总分最高的学生
top_student = max(total_scores.items(), key=lambda x: x[1]['总分'])
print(f"\n总分最高的学生:{top_student[0]},总分={top_student[1]['总分']}")

2. 示例2:使用pandas分析销售数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import pandas as pd

# 创建销售数据
sales_data = {
'产品名称': ['A产品', 'B产品', 'C产品', 'A产品', 'B产品', 'C产品'],
'销售日期': ['2026-01-01', '2026-01-01', '2026-01-01', '2026-01-02', '2026-01-02', '2026-01-02'],
'销售数量': [100, 150, 200, 120, 180, 220],
'销售金额': [5000, 7500, 10000, 6000, 9000, 11000]
}

df = pd.DataFrame(sales_data)

# 写入CSV文件
df.to_csv('sales_data.csv', index=False, encoding='utf-8')

print("销售数据已写入CSV文件!")

# 读取销售数据
df_sales = pd.read_csv('sales_data.csv', encoding='utf-8')
print("\n销售数据:")
print(df_sales)

# 数据分析
print("\n数据分析:")

# 1. 按产品分组,计算总销售数量和总销售金额
product_sales = df_sales.groupby('产品名称')[['销售数量', '销售金额']].sum()
print("按产品分组的销售情况:")
print(product_sales)

# 2. 按日期分组,计算总销售金额
date_sales = df_sales.groupby('销售日期')['销售金额'].sum()
print("\n按日期分组的销售金额:")
print(date_sales)

# 3. 计算每个产品的平均销售单价
df_sales['单价'] = df_sales['销售金额'] / df_sales['销售数量']
avg_price = df_sales.groupby('产品名称')['单价'].mean()
print("\n每个产品的平均销售单价:")
print(avg_price)

# 4. 找出销售数量最多的产品
top_product = df_sales.groupby('产品名称')['销售数量'].sum().idxmax()
top_sales = df_sales.groupby('产品名称')['销售数量'].sum().max()
print(f"\n销售数量最多的产品:{top_product},销售数量={top_sales}")

六、常见错误及解决方案

1. 编码错误

错误信息UnicodeDecodeError: 'gbk' codec can't decode byte 0xa0 in position 20: illegal multibyte sequence

解决方案

  • 在打开文件时指定正确的编码,如encoding='utf-8'encoding='gbk'
  • 使用errors='ignore'忽略无法解码的字符(不推荐)
  • 使用chardet库检测文件编码:
    1
    2
    3
    4
    5
    import chardet

    with open('file.csv', 'rb') as f:
    result = chardet.detect(f.read())
    print(result['encoding']) # 输出文件编码

2. 分隔符错误

错误信息ValueError: Expected 3 fields in line 2, saw 5

解决方案

  • 检查CSV文件的分隔符是否正确
  • 在读取文件时指定正确的分隔符,如delimiter=';'delimiter='\t'
  • 使用csv.Sniffer自动检测分隔符:
    1
    2
    3
    4
    5
    6
    import csv

    with open('file.csv', 'r', encoding='utf-8') as f:
    dialect = csv.Sniffer().sniff(f.read(1024))
    f.seek(0) # 重置文件指针
    reader = csv.reader(f, dialect)

3. 字段名不匹配

错误信息KeyError: '字段名'

解决方案

  • 检查CSV文件的表头是否正确
  • 使用reader.fieldnames查看实际的字段名
  • 确保代码中使用的字段名与CSV文件中的表头一致

4. 类型转换错误

错误信息ValueError: invalid literal for int() with base 10: '字符串'

解决方案

  • 在转换数据类型前检查数据格式
  • 使用try-except处理异常值:
    1
    2
    3
    4
    try:
    age = int(row['年龄'])
    except ValueError:
    age = 0 # 或其他默认值
  • 使用pandas的pd.to_numeric()函数安全转换:
    1
    df['年龄'] = pd.to_numeric(df['年龄'], errors='coerce')

5. 文件路径错误

错误信息FileNotFoundError: [Errno 2] No such file or directory: 'file.csv'

解决方案

  • 检查文件路径是否正确
  • 使用绝对路径代替相对路径
  • 确保文件存在于指定位置

七、最佳实践

  1. 选择合适的库

    • 对于简单的CSV操作,使用内置的csv模块
    • 对于数据分析和处理,使用pandas
    • 对于数值型数据,使用numpy
  2. 使用上下文管理器

    • 始终使用with语句打开文件,确保文件正确关闭
    • 避免手动打开和关闭文件,减少资源泄漏风险
  3. 指定编码

    • 打开文件时明确指定编码,如encoding='utf-8'
    • 确保写入和读取使用相同的编码
  4. 处理缺失值

    • 在读取CSV文件时,指定缺失值标记
    • 对缺失值进行适当处理,如填充默认值或删除
  5. 优化性能

    • 对于大型CSV文件,使用pandas的chunksize参数分块读取
    • 避免在循环中频繁读写文件
    • 使用向量化操作代替循环
  6. 数据验证

    • 在写入CSV文件前验证数据格式
    • 在读取CSV文件后检查数据完整性
    • 使用类型注解提高代码可读性和可维护性
  7. 文档和注释

    • 为CSV文件添加说明文档
    • 在代码中添加注释,说明数据格式和处理逻辑
    • 保存数据字典,说明每个字段的含义和格式

八、总结

本文详细介绍了Python操作CSV文件的三种主要方式:

  1. 内置csv模块:适合简单的CSV读写操作,无需额外安装库,使用方便
  2. pandas库:适合大规模数据处理和分析,提供了丰富的数据操作功能
  3. numpy库:适合数值型数据的读写,性能高效

通过学习本文,你应该能够:

  • 使用不同的库读写CSV文件
  • 处理不同格式的CSV数据
  • 进行基本的数据清洗和分析
  • 解决常见的CSV操作错误
  • 遵循最佳实践编写高效、可靠的CSV处理代码

CSV文件作为一种简单、通用的数据格式,在数据处理和分析中扮演着重要角色。掌握Python操作CSV文件的技能,将有助于你更高效地处理各种数据任务,提高工作效率。

九、参考资料

  1. Python官方文档 - csv模块
  2. pandas官方文档 - CSV读写
  3. numpy官方文档 - CSV读写
  4. Real Python - Working with CSV Files in Python
  5. W3Schools - Python CSV
  6. CSV文件格式规范
  7. Python数据分析实战

Python操作xlsx表格完全指南

在日常工作和数据分析中,Excel表格是最常用的数据存储和展示工具之一。Python提供了多种库来操作Excel文件,特别是xlsx格式的文件。本文将详细介绍如何使用Python操作xlsx表格,包括常用库的使用方法、代码示例、常见错误及解决方案等。

一、依赖的库

Python操作xlsx表格主要依赖以下几个库:

1. openpyxl

openpyxl是一个用于读写Excel 2010 xlsx/xlsm/xltx/xltm文件的Python库,是目前最流行的Excel操作库之一。

安装方法

1
pip install openpyxl

版本要求

  • 推荐使用最新稳定版本
  • 目前稳定版本:v3.1.5(截至2026年1月)

2. pandas

pandas是一个强大的数据分析库,也提供了方便的Excel文件读写功能,适合处理大量数据。

安装方法

1
pip install pandas

版本要求

  • 推荐版本:v2.2.4或更高

3. xlsxwriter

xlsxwriter是一个用于创建Excel xlsx文件的Python库,支持写入文本、数字、公式和超链接,以及创建图表等功能。

安装方法

1
pip install xlsxwriter

版本要求

  • 推荐版本:v3.2.0或更高

4. xlrd(可选)

xlrd用于读取旧版Excel(.xls)文件,对于xlsx文件,pandas 1.2.0+版本已经不再依赖xlrd,而是使用openpyxl。

安装方法

1
pip install xlrd

版本要求

  • 推荐版本:v2.0.1或更高

二、openpyxl库使用

1. 工作簿操作

创建工作簿

1
2
3
4
5
6
7
from openpyxl import Workbook

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

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

打开现有工作簿

1
2
3
4
5
6
7
from openpyxl import load_workbook

# 打开现有工作簿
wb = load_workbook('example.xlsx')

# 获取工作簿中所有工作表名称
print(wb.sheetnames)

2. 工作表操作

创建工作表

1
2
3
4
5
6
7
8
# 创建一个新的工作表,默认在最后
ws1 = wb.create_sheet("Sheet1")

# 创建一个新的工作表,放在最前面
ws2 = wb.create_sheet("Sheet2", 0)

# 创建一个新的工作表,放在指定位置
ws3 = wb.create_sheet("Sheet3", 1)

选择工作表

1
2
3
4
5
# 通过名称选择工作表
ws = wb["Sheet1"]

# 获取活动工作表
ws = wb.active

重命名工作表

1
2
# 重命名工作表
ws.title = "新工作表名称"

删除工作表

1
2
3
4
5
# 删除工作表
wb.remove(ws)

# 或者使用del关键字
# del wb["Sheet1"]

3. 单元格操作

访问单元格

1
2
3
4
5
# 直接通过单元格地址访问
cell = ws["A1"]

# 通过行和列访问(行号从1开始)
cell = ws.cell(row=1, column=1)

设置单元格值

1
2
3
4
5
# 设置单元格值
ws["A1"] = "Hello, World!"

# 或者使用cell对象
ws.cell(row=1, column=2, value="Python")

获取单元格值

1
2
3
4
5
6
7
# 获取单元格值
value = ws["A1"].value
print(value)

# 或者使用cell对象
value = ws.cell(row=1, column=2).value
print(value)

访问多个单元格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 访问一行
for cell in ws["A1:C1"]:
for c in cell:
print(c.value)

# 访问一列
for cell in ws["A1:A5"]:
for c in cell:
print(c.value)

# 访问一个区域
for row in ws["A1:C5"]:
for cell in row:
print(cell.value, end=" ")
print()

# 访问所有行
for row in ws.iter_rows(min_row=1, max_col=3, max_row=5):
for cell in row:
print(cell.value, end=" ")
print()

# 访问所有列
for col in ws.iter_cols(min_row=1, max_col=3, max_row=5):
for cell in col:
print(cell.value, end=" ")
print()

4. 数据读写

写入多行数据

1
2
3
4
5
6
7
8
9
10
11
12
# 准备数据
data = [
["姓名", "年龄", "城市"],
["Alice", 25, "New York"],
["Bob", 30, "London"],
["Charlie", 35, "Paris"],
["David", 40, "Tokyo"]
]

# 写入数据
for row in data:
ws.append(row)

读取所有数据

1
2
3
# 读取所有数据
for row in ws.iter_rows(values_only=True):
print(row)

5. 样式设置

设置字体样式

1
2
3
4
5
6
7
8
9
10
from openpyxl.styles import Font, Color

# 设置单元格字体
ws["A1"].font = Font(
name="Arial",
size=14,
bold=True,
italic=False,
color="FF0000" # 红色
)

设置对齐方式

1
2
3
4
5
6
7
8
from openpyxl.styles import Alignment

# 设置单元格对齐方式
ws["A1"].alignment = Alignment(
horizontal="center", # 水平居中
vertical="center", # 垂直居中
wrap_text=True # 自动换行
)

设置边框

1
2
3
4
5
6
7
8
9
10
11
12
from openpyxl.styles import Border, Side

# 创建边框样式
thin_border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)

# 设置单元格边框
ws["A1"].border = thin_border

设置填充颜色

1
2
3
4
5
6
7
8
from openpyxl.styles import PatternFill

# 设置单元格填充颜色
ws["A1"].fill = PatternFill(
start_color="FFFF00", # 黄色
end_color="FFFF00",
fill_type="solid"
)

设置列宽和行高

1
2
3
4
5
6
# 设置列宽
ws.column_dimensions["A"].width = 20
ws.column_dimensions["B"].width = 15

# 设置行高
ws.row_dimensions[1].height = 30

三、pandas库操作Excel

1. 读取Excel文件

基本读取

1
2
3
4
5
import pandas as pd

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

读取指定工作表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 读取指定工作表
df = pd.read_excel('example.xlsx', sheet_name='Sheet1')
print(df)

# 读取多个工作表
dfs = pd.read_excel('example.xlsx', sheet_name=['Sheet1', 'Sheet2'])
print(dfs['Sheet1'])
print(dfs['Sheet2'])

# 读取所有工作表
dfs = pd.read_excel('example.xlsx', sheet_name=None)
for sheet_name, df in dfs.items():
print(f"工作表名: {sheet_name}")
print(df)
print()

读取指定区域

1
2
3
4
5
6
7
# 读取指定区域
df = pd.read_excel('example.xlsx', usecols='A:C', nrows=5)
print(df)

# 读取指定行和列
df = pd.read_excel('example.xlsx', skiprows=1, usecols=[0, 1, 2])
print(df)

2. 写入Excel文件

基本写入

1
2
3
4
5
6
7
8
9
10
11
# 准备数据
data = {
'姓名': ['Alice', 'Bob', 'Charlie', 'David'],
'年龄': [25, 30, 35, 40],
'城市': ['New York', 'London', 'Paris', 'Tokyo']
}

df = pd.DataFrame(data)

# 写入Excel文件
df.to_excel('output.xlsx', index=False)

写入多个工作表

1
2
3
4
5
6
# 创建ExcelWriter对象
with pd.ExcelWriter('output.xlsx') as writer:
# 写入第一个工作表
df1.to_excel(writer, sheet_name='Sheet1', index=False)
# 写入第二个工作表
df2.to_excel(writer, sheet_name='Sheet2', index=False)

写入指定位置

1
2
# 写入指定位置
df.to_excel('output.xlsx', sheet_name='Sheet1', startrow=1, startcol=2, index=False)

3. 高级操作

设置列宽

1
2
3
4
5
6
7
8
9
10
with pd.ExcelWriter('output.xlsx', engine='xlsxwriter') as writer:
df.to_excel(writer, sheet_name='Sheet1', index=False)

# 获取工作表对象
worksheet = writer.sheets['Sheet1']

# 设置列宽
worksheet.set_column('A:A', 20)
worksheet.set_column('B:B', 15)
worksheet.set_column('C:C', 25)

设置单元格格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
with pd.ExcelWriter('output.xlsx', engine='xlsxwriter') as writer:
df.to_excel(writer, sheet_name='Sheet1', index=False)

# 获取工作簿和工作表对象
workbook = writer.book
worksheet = writer.sheets['Sheet1']

# 创建格式对象
bold_format = workbook.add_format({'bold': True, 'font_color': 'red'})

# 设置单元格格式
worksheet.write('A1', '姓名', bold_format)
worksheet.write('B1', '年龄', bold_format)
worksheet.write('C1', '城市', bold_format)

四、xlsxwriter库使用

1. 创建工作簿和工作表

创建工作簿

1
2
3
4
5
6
7
8
9
10
import xlsxwriter

# 创建工作簿
workbook = xlsxwriter.Workbook('example.xlsx')

# 创建工作表
worksheet = workbook.add_worksheet()

# 关闭工作簿
workbook.close()

创建命名工作表

1
2
3
4
# 创建命名工作表
worksheet1 = workbook.add_worksheet() # 默认名称:Sheet1
worksheet2 = workbook.add_worksheet('Data') # 名称:Data
worksheet3 = workbook.add_worksheet('Report') # 名称:Report

2. 写入数据

写入文本和数字

1
2
3
4
5
6
7
8
9
# 写入文本
worksheet.write('A1', 'Hello')
worksheet.write('B1', 'World')

# 写入数字
worksheet.write(0, 2, 123)
worksheet.write(1, 0, 456)
worksheet.write(1, 1, 789)
worksheet.write(1, 2, 10.5)

写入公式

1
2
3
# 写入公式
worksheet.write('D2', '=SUM(A2:C2)')
worksheet.write('A4', '=AVERAGE(A2:A3)')

写入日期和时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import datetime

# 写入日期
worksheet.write('A1', datetime.datetime(2026, 1, 24))

# 写入时间
worksheet.write('B1', datetime.datetime(2026, 1, 24, 10, 30, 0))

# 设置日期格式
date_format = workbook.add_format({'num_format': 'yyyy-mm-dd'})
worksheet.write('A2', datetime.datetime(2026, 1, 24), date_format)

# 设置时间格式
time_format = workbook.add_format({'num_format': 'hh:mm:ss'})
worksheet.write('B2', datetime.datetime(2026, 1, 24, 10, 30, 0), time_format)

写入超链接

1
2
3
# 写入超链接
worksheet.write_url('A1', 'https://www.example.com', string='Example Website')
worksheet.write_url('A2', 'mailto:example@example.com', string='Send Email')

3. 创建图表

创建柱状图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 准备数据
worksheet.write('A1', '产品')
worksheet.write('B1', '销量')
worksheet.write('A2', '产品A')
worksheet.write('B2', 100)
worksheet.write('A3', '产品B')
worksheet.write('B3', 200)
worksheet.write('A4', '产品C')
worksheet.write('B4', 150)

# 创建柱状图
chart = workbook.add_chart({'type': 'column'})

# 添加数据系列
chart.add_series({
'name': '=Sheet1!$B$1',
'categories': '=Sheet1!$A$2:$A$4',
'values': '=Sheet1!$B$2:$B$4',
})

# 设置图表标题
chart.set_title({'name': '产品销量'})

# 设置x轴标题
chart.set_x_axis({'name': '产品'})

# 设置y轴标题
chart.set_y_axis({'name': '销量'})

# 插入图表到工作表
worksheet.insert_chart('D2', chart)

创建折线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 创建折线图
chart = workbook.add_chart({'type': 'line'})

# 添加数据系列
chart.add_series({
'name': '=Sheet1!$B$1',
'categories': '=Sheet1!$A$2:$A$4',
'values': '=Sheet1!$B$2:$B$4',
})

# 设置图表标题
chart.set_title({'name': '产品销量趋势'})

# 插入图表到工作表
worksheet.insert_chart('D2', chart)

创建饼图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建饼图
chart = workbook.add_chart({'type': 'pie'})

# 添加数据系列
chart.add_series({
'name': '=Sheet1!$B$1',
'categories': '=Sheet1!$A$2:$A$4',
'values': '=Sheet1!$B$2:$B$4',
'data_labels': {'value': True},
})

# 设置图表标题
chart.set_title({'name': '产品销量占比'})

# 插入图表到工作表
worksheet.insert_chart('D2', chart)

五、完整代码示例

1. 示例1:使用openpyxl读写Excel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, Border, Side

# 创建工作簿
wb = Workbook()
ws = wb.active
ws.title = "员工信息"

# 设置表头
headers = ["姓名", "年龄", "部门", "工资"]
for col, header in enumerate(headers, 1):
cell = ws.cell(row=1, column=col, value=header)
# 设置表头样式
cell.font = Font(bold=True, color="FFFFFF")
cell.fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)

# 准备数据
data = [
["张三", 28, "技术部", 8000],
["李四", 32, "销售部", 12000],
["王五", 25, "市场部", 7500],
["赵六", 35, "财务部", 9000],
["孙七", 29, "技术部", 8500]
]

# 写入数据
for row, row_data in enumerate(data, 2):
for col, value in enumerate(row_data, 1):
cell = ws.cell(row=row, column=col, value=value)
cell.alignment = Alignment(horizontal="center", vertical="center")
cell.border = Border(
left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin')
)

# 设置列宽
ws.column_dimensions["A"].width = 15
ws.column_dimensions["B"].width = 10
ws.column_dimensions["C"].width = 15
ws.column_dimensions["D"].width = 15

# 保存工作簿
wb.save("员工信息表.xlsx")
print("员工信息表已创建成功!")

# 读取工作簿
from openpyxl import load_workbook

wb = load_workbook("员工信息表.xlsx")
ws = wb.active

print("\n读取员工信息表:")
for row in ws.iter_rows(values_only=True):
print(row)

2. 示例2:使用pandas处理Excel数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import pandas as pd

# 准备数据
data = {
'姓名': ['张三', '李四', '王五', '赵六', '孙七'],
'年龄': [28, 32, 25, 35, 29],
'部门': ['技术部', '销售部', '市场部', '财务部', '技术部'],
'工资': [8000, 12000, 7500, 9000, 8500]
}

df = pd.DataFrame(data)

# 写入Excel文件
with pd.ExcelWriter('员工信息_pandas.xlsx', engine='xlsxwriter') as writer:
df.to_excel(writer, sheet_name='员工信息', index=False)

# 获取工作簿和工作表对象
workbook = writer.book
worksheet = writer.sheets['员工信息']

# 设置列宽
worksheet.set_column('A:A', 15)
worksheet.set_column('B:B', 10)
worksheet.set_column('C:C', 15)
worksheet.set_column('D:D', 15)

# 设置表头格式
header_format = workbook.add_format({
'bold': True,
'text_wrap': True,
'valign': 'top',
'fg_color': '#4F81BD',
'bg_color': '#4F81BD',
'font_color': '#FFFFFF',
'border': 1
})

# 设置表头
for col_num, value in enumerate(df.columns.values):
worksheet.write(0, col_num, value, header_format)

# 创建工资数据的柱状图
chart = workbook.add_chart({'type': 'column'})
chart.add_series({
'name': '=员工信息!$D$1',
'categories': '=员工信息!$A$2:$A$6',
'values': '=员工信息!$D$2:$D$6',
})

chart.set_title({'name': '员工工资'})
chart.set_x_axis({'name': '姓名'})
chart.set_y_axis({'name': '工资'})

# 插入图表
worksheet.insert_chart('F2', chart)

print("使用pandas创建的员工信息表已保存成功!")

# 读取Excel文件并进行数据分析
print("\n读取Excel文件并进行数据分析:")
df_read = pd.read_excel('员工信息_pandas.xlsx')
print("数据基本信息:")
print(df_read.info())
print("\n数据统计描述:")
print(df_read.describe())
print("\n各部门平均工资:")
print(df_read.groupby('部门')['工资'].mean())
print("\n工资最高的员工:")
print(df_read[df_read['工资'] == df_read['工资'].max()])

3. 示例3:使用xlsxwriter创建带图表的Excel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import xlsxwriter

# 创建工作簿
workbook = xlsxwriter.Workbook('销售报表.xlsx')

# 创建工作表
worksheet = workbook.add_worksheet('月度销售')

# 设置标题
worksheet.write('A1', '2026年销售报表')

# 设置标题格式
title_format = workbook.add_format({
'bold': True,
'font_size': 18,
'align': 'center',
'valign': 'vcenter',
'fg_color': '#FFD700',
'border': 1
})
worksheet.merge_range('A1:D1', '2026年销售报表', title_format)

# 设置表头
headers = ['月份', '产品A', '产品B', '产品C']
header_format = workbook.add_format({
'bold': True,
'bg_color': '#4F81BD',
'font_color': '#FFFFFF',
'align': 'center',
'valign': 'vcenter',
'border': 1
})

for col, header in enumerate(headers):
worksheet.write(2, col, header, header_format)

# 准备销售数据
months = ['1月', '2月', '3月', '4月', '5月', '6月']
product_a = [100, 120, 150, 130, 160, 180]
product_b = [80, 90, 100, 110, 120, 130]
product_c = [150, 160, 170, 180, 190, 200]

# 写入数据
data_format = workbook.add_format({
'align': 'center',
'valign': 'vcenter',
'border': 1
})

for row in range(6):
worksheet.write(row + 3, 0, months[row], data_format)
worksheet.write(row + 3, 1, product_a[row], data_format)
worksheet.write(row + 3, 2, product_b[row], data_format)
worksheet.write(row + 3, 3, product_c[row], data_format)

# 设置列宽
worksheet.set_column('A:A', 10)
worksheet.set_column('B:D', 15)

# 创建折线图
chart = workbook.add_chart({'type': 'line'})

# 添加系列数据
chart.add_series({
'name': '=月度销售!$B$3',
'categories': '=月度销售!$A$4:$A$9',
'values': '=月度销售!$B$4:$B$9',
'marker': {'type': 'circle', 'size': 8},
'line': {'width': 2},
})

chart.add_series({
'name': '=月度销售!$C$3',
'categories': '=月度销售!$A$4:$A$9',
'values': '=月度销售!$C$4:$C$9',
'marker': {'type': 'square', 'size': 8},
'line': {'width': 2},
})

chart.add_series({
'name': '=月度销售!$D$3',
'categories': '=月度销售!$A$4:$A$9',
'values': '=月度销售!$D$4:$D$9',
'marker': {'type': 'triangle', 'size': 8},
'line': {'width': 2},
})

# 设置图表标题
chart.set_title({'name': '2026年上半年产品销售趋势'})

# 设置x轴和y轴标题
chart.set_x_axis({'name': '月份'})
chart.set_y_axis({'name': '销量'})

# 设置图表样式
chart.set_style(10)

# 插入图表
worksheet.insert_chart('F2', chart, {'x_offset': 20, 'y_offset': 10})

# 关闭工作簿
workbook.close()

print("带图表的销售报表已创建成功!")

六、常见错误及解决方案

1. 文件被占用

错误信息PermissionError: [Errno 13] Permission denied: 'example.xlsx'

解决方案

  • 确保Excel文件没有被其他程序(如Microsoft Excel)打开
  • 检查文件路径是否正确
  • 检查文件权限

2. 库版本不兼容

错误信息ImportError: cannot import name 'XXXX' from 'openpyxl'

解决方案

  • 更新库到最新版本:pip install --upgrade openpyxl pandas xlsxwriter
  • 检查库的版本兼容性
  • 查看官方文档了解API变化

3. 数据类型错误

错误信息TypeError: Invalid cell value type

解决方案

  • 确保写入Excel的数据类型是支持的类型(字符串、数字、日期等)
  • 对于复杂数据类型,先转换为字符串或其他支持的类型
  • 检查数据中是否包含None或NaN值

4. 工作表不存在

错误信息KeyError: "Worksheet named 'Sheet1' not found"

解决方案

  • 检查工作表名称是否正确,注意大小写
  • 使用wb.sheetnames查看所有工作表名称
  • 确保工作表已创建

5. 单元格地址错误

错误信息ValueError: Row or column values must be at least 1

解决方案

  • 确保行号和列号从1开始
  • 检查单元格地址格式是否正确

七、最佳实践

  1. 选择合适的库

    • 对于简单的Excel读写,推荐使用openpyxl
    • 对于数据分析和处理,推荐使用pandas
    • 对于需要创建复杂图表和格式,推荐使用xlsxwriter
  2. 资源管理

    • 使用with语句管理文件资源,确保文件正确关闭
    • 大型文件处理时,考虑分块读取,避免内存不足
  3. 性能优化

    • 批量写入数据比逐个写入更高效
    • 对于大型数据集,考虑使用pandas的向量化操作
    • 避免在循环中频繁访问单元格
  4. 格式设置

    • 合理使用格式,避免过度设置导致文件过大
    • 使用条件格式代替手动设置每个单元格格式
    • 考虑使用Excel模板
  5. 错误处理

    • 添加适当的异常处理,提高程序健壮性
    • 对文件操作添加日志记录
    • 验证输入数据的正确性

八、总结

本文详细介绍了Python操作xlsx表格的三种主要库:openpyxl、pandas和xlsxwriter。通过这些库,我们可以实现Excel文件的创建、读取、修改和格式化,以及创建各种图表。

  • openpyxl:功能全面,支持读写xlsx文件,适合对Excel文件进行精细控制
  • pandas:适合数据分析和处理,提供了高效的数据读写和转换功能
  • xlsxwriter:擅长创建带图表和复杂格式的Excel文件

在实际应用中,我们可以根据具体需求选择合适的库,或者结合使用多个库来完成复杂的任务。通过Python自动化处理Excel文件,可以大大提高工作效率,减少重复劳动。

九、参考资料

  1. openpyxl官方文档
  2. pandas官方文档 - Excel读写
  3. xlsxwriter官方文档
  4. Python Excel教程
  5. Real Python - Working with Excel Files in Python
  6. Python数据分析实战
  7. Excel文件格式规范

pandas基础使用教程

在数据分析领域,pandas是Python生态中最强大、最常用的库之一。它提供了高效的数据结构和数据分析工具,使得数据处理、清洗、分析和可视化变得简单易用。本文将详细介绍pandas的基础使用方法,包括依赖库、基本概念、数据操作、常见错误及解决方案等内容。

一、依赖的库

要使用pandas进行数据分析,我们需要安装一些必要的依赖库。

1. pandas

pandas是核心库,提供了DataFrame和Series等数据结构,以及各种数据操作功能。

安装方法

1
pip install pandas

版本要求

  • 推荐使用最新稳定版本
  • 目前稳定版本:v2.2.4(截至2026年1月)

2. numpy

numpy是pandas的基础依赖,提供了高效的数值计算功能。

安装方法

1
pip install numpy

版本要求

  • 推荐版本:v2.1.0或更高

3. matplotlib(可选)

matplotlib用于数据可视化,pandas内置了对matplotlib的支持。

安装方法

1
pip install matplotlib

版本要求

  • 推荐版本:v3.9.0或更高

4. seaborn(可选)

seaborn是基于matplotlib的高级可视化库,提供了更美观的图表样式。

安装方法

1
pip install seaborn

版本要求

  • 推荐版本:v0.13.2或更高

二、基本概念

pandas有两个核心数据结构:Series和DataFrame。

1. Series

Series是一维带标签的数组,类似于带索引的列表。

创建Series

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
import numpy as np

# 从列表创建
ser1 = pd.Series([1, 2, 3, 4, 5])
print("从列表创建的Series:")
print(ser1)
print()

# 从字典创建
ser2 = pd.Series({'a': 1, 'b': 2, 'c': 3})
print("从字典创建的Series:")
print(ser2)
print()

# 带自定义索引
ser3 = pd.Series([1, 2, 3], index=['x', 'y', 'z'])
print("带自定义索引的Series:")
print(ser3)

2. DataFrame

DataFrame是二维带标签的数据结构,类似于电子表格或SQL表。

创建DataFrame

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 从字典创建
df1 = pd.DataFrame({
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'City': ['New York', 'London', 'Paris']
})
print("从字典创建的DataFrame:")
print(df1)
print()

# 从列表创建
data = [
['Alice', 25, 'New York'],
['Bob', 30, 'London'],
['Charlie', 35, 'Paris']
]
df2 = pd.DataFrame(data, columns=['Name', 'Age', 'City'])
print("从列表创建的DataFrame:")
print(df2)
print()

# 从numpy数组创建
data = np.random.randint(0, 100, size=(5, 3))
df3 = pd.DataFrame(data, columns=['A', 'B', 'C'])
print("从numpy数组创建的DataFrame:")
print(df3)

三、数据读取与写入

pandas支持多种文件格式的数据读取和写入。

1. CSV文件

读取CSV文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 读取本地CSV文件
df = pd.read_csv('data.csv')

# 读取网络CSV文件
df = pd.read_csv('https://example.com/data.csv')

# 读取时指定参数
df = pd.read_csv(
'data.csv',
sep=',', # 分隔符
header=0, # 表头行
index_col=0, # 索引列
na_values=['NA'], # 缺失值标记
encoding='utf-8' # 编码
)

写入CSV文件

1
2
3
4
5
6
7
8
9
10
11
# 写入CSV文件
df.to_csv('output.csv')

# 写入时指定参数
df.to_csv(
'output.csv',
index=False, # 不写入索引
header=True, # 写入表头
sep=',', # 分隔符
encoding='utf-8' # 编码
)

2. Excel文件

读取Excel文件

1
2
3
4
5
6
7
8
# 读取Excel文件
df = pd.read_excel('data.xlsx')

# 读取指定工作表
df = pd.read_excel('data.xlsx', sheet_name='Sheet1')

# 读取多个工作表
dfs = pd.read_excel('data.xlsx', sheet_name=['Sheet1', 'Sheet2'])

写入Excel文件

1
2
3
4
5
6
7
8
9
10
# 写入Excel文件
df.to_excel('output.xlsx')

# 写入指定工作表
df.to_excel('output.xlsx', sheet_name='Sheet1')

# 写入多个工作表
with pd.ExcelWriter('output.xlsx') as writer:
df1.to_excel(writer, sheet_name='Sheet1')
df2.to_excel(writer, sheet_name='Sheet2')

3. JSON文件

读取JSON文件

1
2
3
4
5
# 读取JSON文件
df = pd.read_json('data.json')

# 读取嵌套JSON
df = pd.read_json('nested.json', orient='records')

写入JSON文件

1
2
3
4
5
# 写入JSON文件
df.to_json('output.json')

# 写入时指定格式
df.to_json('output.json', orient='records', indent=2)

四、数据清洗与预处理

数据清洗是数据分析的重要步骤,包括处理缺失值、重复值、异常值等。

1. 处理缺失值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 查看缺失值情况
print(df.isnull().sum())

# 删除包含缺失值的行
df_clean = df.dropna()

# 删除包含缺失值的列
df_clean = df.dropna(axis=1)

# 填充缺失值
df_filled = df.fillna(0) # 用0填充
print(df_filled)

df_filled = df.fillna({'Age': 30, 'City': 'Unknown'}) # 按列填充
print(df_filled)

df_filled = df.fillna(method='ffill') # 向前填充
print(df_filled)

df_filled = df.fillna(method='bfill') # 向后填充
print(df_filled)

df_filled = df.fillna(df.mean()) # 用均值填充
print(df_filled)

2. 处理重复值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 查看重复值
print(df.duplicated())

# 查看重复值数量
print(df.duplicated().sum())

# 删除重复值
df_unique = df.drop_duplicates()
print(df_unique)

# 按指定列删除重复值
df_unique = df.drop_duplicates(subset=['Name'])
print(df_unique)

# 保留最后一个重复值
df_unique = df.drop_duplicates(keep='last')
print(df_unique)

3. 数据类型转换

1
2
3
4
5
6
7
8
9
10
11
12
# 查看数据类型
print(df.dtypes)

# 转换数据类型
df['Age'] = df['Age'].astype(int) # 转换为整数
print(df.dtypes)

df['Date'] = pd.to_datetime(df['Date']) # 转换为日期时间
print(df.dtypes)

df['Price'] = pd.to_numeric(df['Price']) # 转换为数值型
print(df.dtypes)

4. 数据标准化与归一化

1
2
3
4
5
6
7
8
9
10
11
# 标准化(z-score)
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
df['Age_scaled'] = scaler.fit_transform(df[['Age']])
print(df)

# 归一化(min-max)
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
df['Age_normalized'] = scaler.fit_transform(df[['Age']])
print(df)

五、数据筛选与查询

1. 基本筛选

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 选择列
df['Name'] # 选择单列
print(df['Name'])

df[['Name', 'Age']] # 选择多列
print(df[['Name', 'Age']])

# 行索引选择
df.loc[0] # 按标签选择行
print(df.loc[0])

df.loc[0:2] # 按标签切片
print(df.loc[0:2])

df.iloc[0] # 按位置选择行
print(df.iloc[0])

df.iloc[0:2] # 按位置切片
print(df.iloc[0:2])

# 条件筛选
df[df['Age'] > 30] # 年龄大于30的行
print(df[df['Age'] > 30])

df[(df['Age'] > 30) & (df['City'] == 'New York')] # 多条件筛选
print(df[(df['Age'] > 30) & (df['City'] == 'New York')])

df[df['City'].isin(['New York', 'London'])] # 包含于列表
print(df[df['City'].isin(['New York', 'London'])])

2. 高级查询

1
2
3
4
5
6
7
8
9
10
# 使用query方法
df.query('Age > 30')
print(df.query('Age > 30'))

df.query('Age > 30 and City == "New York"')
print(df.query('Age > 30 and City == "New York"'))

# 使用eval方法计算新列
df.eval('Age_in_months = Age * 12')
print(df.eval('Age_in_months = Age * 12'))

六、数据分组与聚合

1. 数据分组

1
2
3
4
5
6
7
8
9
10
11
12
13
# 按单列分组
grouped = df.groupby('City')
print(grouped)

# 按多列分组
grouped = df.groupby(['City', 'Gender'])
print(grouped)

# 分组后查看每组数据
for name, group in grouped:
print(f"Group: {name}")
print(group)
print()

2. 聚合操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 常用聚合函数
print(grouped['Age'].count()) # 计数
print(grouped['Age'].sum()) # 求和
print(grouped['Age'].mean()) # 均值
print(grouped['Age'].median()) # 中位数
print(grouped['Age'].std()) # 标准差
print(grouped['Age'].min()) # 最小值
print(grouped['Age'].max()) # 最大值

# 多聚合函数
grouped['Age'].agg(['count', 'sum', 'mean', 'min', 'max'])
print(grouped['Age'].agg(['count', 'sum', 'mean', 'min', 'max']))

# 不同列使用不同聚合函数
grouped.agg({
'Age': ['mean', 'std'],
'Salary': ['sum', 'max']
})

3. 分组转换

1
2
3
4
5
6
7
8
# 计算每组的均值并广播到原数据
print(grouped['Age'].transform('mean'))

# 使用自定义函数
def normalize(x):
return (x - x.mean()) / x.std()

print(grouped['Age'].transform(normalize))

4. 分组过滤

1
2
# 过滤掉年龄均值小于30的组
print(grouped.filter(lambda x: x['Age'].mean() > 30))

七、数据可视化

pandas内置了对matplotlib的支持,可以直接绘制各种图表。

1. 基本图表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import matplotlib.pyplot as plt

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

# 折线图
df.plot(kind='line', x='Date', y='Value')
plt.title('折线图')
plt.show()

# 柱状图
df.plot(kind='bar', x='Name', y='Age')
plt.title('柱状图')
plt.show()

# 直方图
df['Age'].plot(kind='hist', bins=10)
plt.title('直方图')
plt.show()

# 散点图
df.plot(kind='scatter', x='Age', y='Salary')
plt.title('散点图')
plt.show()

# 箱线图
df.plot(kind='box', y=['Age', 'Salary'])
plt.title('箱线图')
plt.show()

# 饼图
df['City'].value_counts().plot(kind='pie', autopct='%1.1f%%')
plt.title('饼图')
plt.axis('equal')
plt.show()

2. 使用seaborn可视化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import seaborn as sns

# 热力图
corr = df.corr()
sns.heatmap(corr, annot=True, cmap='coolwarm')
plt.title('热力图')
plt.show()

# 成对关系图
sns.pairplot(df[['Age', 'Salary', 'Experience']])
plt.title('成对关系图')
plt.show()

# 分类柱状图
sns.barplot(x='City', y='Salary', data=df)
plt.title('分类柱状图')
plt.show()

# 小提琴图
sns.violinplot(x='City', y='Age', data=df)
plt.title('小提琴图')
plt.show()

八、完整代码示例

下面是一个完整的pandas基础使用示例,展示了从数据读取到分析的整个流程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 设置中文显示
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 1. 创建示例数据
data = {
'Name': ['Alice', 'Bob', 'Charlie', 'David', 'Eve', 'Frank', 'Grace', 'Henry', 'Ivy', 'Jack'],
'Age': [25, 30, 35, 40, 45, 50, 55, 60, 65, 70],
'City': ['New York', 'London', 'Paris', 'Tokyo', 'Sydney', 'New York', 'London', 'Paris', 'Tokyo', 'Sydney'],
'Salary': [50000, 60000, 70000, 80000, 90000, 100000, 110000, 120000, 130000, 140000],
'Experience': [2, 5, 8, 11, 14, 17, 20, 23, 26, 29]
}

df = pd.DataFrame(data)
print("原始数据:")
print(df)
print()

# 2. 数据基本信息
print("数据基本信息:")
print(df.info())
print()

print("数据统计描述:")
print(df.describe())
print()

# 3. 数据清洗
# 假设添加一些缺失值
import copy
df_with_na = copy.deepcopy(df)
df_with_na.loc[2, 'Age'] = np.nan
df_with_na.loc[5, 'Salary'] = np.nan

print("包含缺失值的数据:")
print(df_with_na)
print()

print("缺失值情况:")
print(df_with_na.isnull().sum())
print()

# 处理缺失值
df_clean = df_with_na.fillna({
'Age': df_with_na['Age'].mean(),
'Salary': df_with_na['Salary'].median()
})

print("处理缺失值后的数据:")
print(df_clean)
print()

# 4. 数据筛选与查询
print("年龄大于50岁的数据:")
print(df_clean[df_clean['Age'] > 50])
print()

print("来自New York且薪资大于80000的数据:")
print(df_clean[(df_clean['City'] == 'New York') & (df_clean['Salary'] > 80000)])
print()

# 5. 数据分组与聚合
print("按城市分组的平均年龄和薪资:")
grouped = df_clean.groupby('City')
print(grouped[['Age', 'Salary']].mean())
print()

# 6. 数据可视化
# 薪资与经验的关系
df_clean.plot(kind='scatter', x='Experience', y='Salary', color='blue', marker='o', s=50)
plt.title('薪资与工作经验的关系')
plt.xlabel('工作经验(年)')
plt.ylabel('薪资(美元)')
plt.grid(True)
plt.show()

# 不同城市的薪资分布
sns.barplot(x='City', y='Salary', data=df_clean, palette='viridis')
plt.title('不同城市的平均薪资')
plt.xlabel('城市')
plt.ylabel('平均薪资(美元)')
plt.xticks(rotation=45)
plt.show()

# 年龄分布直方图
df_clean['Age'].plot(kind='hist', bins=5, color='green', alpha=0.7)
plt.title('年龄分布')
plt.xlabel('年龄')
plt.ylabel('人数')
plt.grid(True, alpha=0.3)
plt.show()

# 7. 导出结果
df_clean.to_csv('cleaned_data.csv', index=False)
print("数据已导出到cleaned_data.csv")

九、常见错误及解决方案

1. 缺失值处理错误

错误信息ValueError: Input contains NaN, infinity or a value too large for dtype('float64')

解决方案

  • 在进行数值计算前,先处理缺失值
  • 使用df.dropna()删除缺失值
  • 使用df.fillna()填充缺失值
  • 检查数据中是否有无穷大值,使用df.replace([np.inf, -np.inf], np.nan)处理

2. 数据类型不匹配

错误信息TypeError: unsupported operand type(s) for +: 'int' and 'str'

解决方案

  • 检查数据类型,使用df.dtypes查看
  • 转换数据类型,使用df.astype()pd.to_numeric()
  • 确保进行运算的列具有兼容的数据类型

3. 索引错误

错误信息KeyError: 'column_name'

解决方案

  • 检查列名是否正确,注意大小写
  • 使用df.columns查看所有列名
  • 确保列名没有空格或特殊字符
  • 使用df.rename(columns={'old_name': 'new_name'})重命名列

错误信息IndexError: single positional indexer is out-of-bounds

解决方案

  • 检查索引范围,使用df.shape查看数据形状
  • 确保索引值在有效范围内
  • 使用.loc[].iloc[]进行安全索引

4. 内存不足

错误信息MemoryError

解决方案

  • 读取大数据时使用chunksize参数分块读取
  • 选择性读取需要的列,使用usecols参数
  • 转换数据类型为更节省内存的类型,如int8float16
  • 使用df.memory_usage()查看内存使用情况

5. 文件路径错误

错误信息FileNotFoundError: [Errno 2] No such file or directory: 'data.csv'

解决方案

  • 检查文件路径是否正确
  • 确认文件存在
  • 使用绝对路径代替相对路径
  • 检查文件权限

十、进阶用法

1. 时间序列处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 创建时间序列索引
date_rng = pd.date_range(start='2026-01-01', end='2026-01-31', freq='D')
df = pd.DataFrame(date_rng, columns=['date'])
df['value'] = np.random.randint(0, 100, size=(len(date_rng)))
df.set_index('date', inplace=True)

# 时间序列重采样
df.resample('W').mean() # 按周重采样
df.resample('M').sum() # 按月重采样

# 移动窗口计算
df['rolling_mean'] = df['value'].rolling(window=7).mean() # 7天移动平均
df['rolling_std'] = df['value'].rolling(window=7).std() # 7天移动标准差

# 差分运算
df['diff'] = df['value'].diff() # 一阶差分

2. 多索引操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 创建多索引
df = pd.DataFrame({
'year': [2024, 2024, 2025, 2025],
'quarter': [1, 2, 1, 2],
'sales': [100, 200, 300, 400]
})

df_multi = df.set_index(['year', 'quarter'])
print(df_multi)

# 多索引查询
df_multi.loc[(2024, 1)] # 查询特定索引
df_multi.xs(2024, level='year') # 按年份查询
df_multi.xs(1, level='quarter') # 按季度查询

# 重置索引
df_flat = df_multi.reset_index()
print(df_flat)

3. 合并与连接数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# 创建示例数据
df1 = pd.DataFrame({
'id': [1, 2, 3, 4],
'name': ['Alice', 'Bob', 'Charlie', 'David'],
'city': ['New York', 'London', 'Paris', 'Tokyo']
})

df2 = pd.DataFrame({
'id': [2, 3, 4, 5],
'salary': [50000, 60000, 70000, 80000],
'experience': [2, 5, 8, 11]
})

# 内连接
df_inner = pd.merge(df1, df2, on='id', how='inner')
print(df_inner)

# 左连接
df_left = pd.merge(df1, df2, on='id', how='left')
print(df_left)

# 右连接
df_right = pd.merge(df1, df2, on='id', how='right')
print(df_right)

# 外连接
df_outer = pd.merge(df1, df2, on='id', how='outer')
print(df_outer)

# 追加数据
df_append = df1.append(df2, ignore_index=True)
print(df_append)

# 拼接数据
df_concat = pd.concat([df1, df2], axis=1)
print(df_concat)

4. 高性能操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 使用向量化操作代替循环
df['new_col'] = df['col1'] + df['col2'] # 向量化操作,高效

# 使用apply与自定义函数
df['new_col'] = df.apply(lambda row: row['col1'] + row['col2'], axis=1) # 比循环高效,但比向量化操作慢

# 使用numba加速
from numba import njit

@njit
def calculate(x, y):
return x + y

df['new_col'] = calculate(df['col1'].values, df['col2'].values) # 高效

# 使用Dask处理大数据
dask_df = dd.from_pandas(df, npartitions=4)
result = dask_df.groupby('city')['salary'].mean().compute()

十一、总结

本文详细介绍了pandas的基础使用方法,包括:

  1. 依赖库:pandas、numpy、matplotlib、seaborn等
  2. 基本概念:Series和DataFrame数据结构
  3. 数据读取与写入:支持CSV、Excel、JSON等多种格式
  4. 数据清洗与预处理:处理缺失值、重复值、数据类型转换等
  5. 数据筛选与查询:基本筛选、条件查询、高级查询
  6. 数据分组与聚合:分组、聚合、转换、过滤
  7. 数据可视化:基本图表、seaborn可视化
  8. 完整代码示例:从数据创建到可视化的完整流程
  9. 常见错误及解决方案:缺失值处理、数据类型不匹配、索引错误等
  10. 进阶用法:时间序列处理、多索引操作、合并与连接数据、高性能操作

pandas是数据分析的强大工具,掌握其基础使用方法对于数据分析工作至关重要。通过本文的学习,你应该能够使用pandas进行基本的数据处理、分析和可视化。

在实际应用中,建议结合具体需求,深入学习pandas的高级功能,如时间序列分析、数据透视表、高性能计算等。同时,多实践、多总结,不断提高自己的数据分析能力。

十二、参考资料

  1. pandas官方文档
  2. numpy官方文档
  3. matplotlib官方文档
  4. seaborn官方文档
  5. Python数据分析实战
  6. pandas cookbook
  7. Data Science Handbook
  8. pandas中文教程

通过Python调用OpenAI API的实战

在人工智能时代,OpenAI提供的API服务为开发者提供了强大的AI能力。无论是聊天机器人、图像生成、语音处理还是代码生成,OpenAI API都能提供高效、准确的解决方案。本文将详细介绍如何使用Python调用OpenAI API,包括依赖库、调用方法、代码示例以及可能出现的错误和解决方案。

一、依赖的库

要使用Python调用OpenAI API,我们需要安装OpenAI官方提供的Python库。

1. openai

openai是OpenAI官方提供的Python客户端库,用于简化API调用流程。它封装了各种API端点,提供了便捷的方法来调用OpenAI的各种服务。

安装方法

1
pip install openai

版本要求

  • 推荐使用最新版本,以获得最佳性能和最新功能
  • 目前稳定版本:v1.35.10(截至2026年1月)

二、调用方法

1. 基本配置

在使用OpenAI API之前,需要进行基本配置,主要是设置API密钥。

步骤1:获取API密钥

步骤2:设置API密钥

方法1:直接在代码中设置

1
2
3
4
5
6
from openai import OpenAI

# 初始化客户端
client = OpenAI(
api_key="your-api-key-here" # 替换为你的API密钥
)

方法2:使用环境变量(推荐)

1
2
3
4
5
6
7
import os
from openai import OpenAI

# 从环境变量获取API密钥
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)

设置环境变量的方法:

  • Windows:setx OPENAI_API_KEY "your-api-key-here"
  • Linux/macOS:export OPENAI_API_KEY="your-api-key-here"

2. 聊天完成(Chat Completions)

聊天完成是OpenAI API中最常用的功能,用于生成对话式响应。

基本调用示例

1
2
3
4
5
6
7
8
9
10
11
# 调用聊天完成API
response = client.chat.completions.create(
model="gpt-4o", # 使用的模型
messages=[
{"role": "system", "content": "你是一个 helpful 的助手。"},
{"role": "user", "content": "介绍一下Python的主要特点。"}
]
)

# 输出响应结果
print(response.choices[0].message.content)

参数说明

  • model:使用的模型名称,如gpt-4ogpt-3.5-turbo
  • messages:对话历史,包含角色(system/user/assistant)和内容
  • temperature:控制生成文本的随机性,范围0-2,值越高越随机
  • max_tokens:生成文本的最大令牌数

3. 图片生成(Image Generation)

OpenAI API提供了图片生成功能,可以根据文本描述生成图片。

基本调用示例

1
2
3
4
5
6
7
8
9
10
11
12
# 调用图片生成API
response = client.images.generate(
model="dall-e-3", # 使用的模型
prompt="一只可爱的柯基犬在草地上奔跑,阳光明媚,水彩画风格", # 图片描述
size="1024x1024", # 图片尺寸
quality="standard", # 图片质量
n=1, # 生成图片数量
)

# 获取图片URL
image_url = response.data[0].url
print(f"生成的图片URL:{image_url}")

参数说明

  • model:使用的模型,如dall-e-3dall-e-2
  • prompt:图片描述,越详细生成效果越好
  • size:图片尺寸,如1024x10241792x1024
  • quality:图片质量,standardhd
  • n:生成图片数量,范围1-10

4. 语音转文本(Speech to Text)

OpenAI API提供了语音转文本功能,可以将音频文件转换为文本。

基本调用示例

1
2
3
4
5
6
7
8
9
10
# 调用语音转文本API
with open("audio.mp3", "rb") as audio_file:
response = client.audio.transcriptions.create(
model="whisper-1", # 使用的模型
file=audio_file, # 音频文件
response_format="text" # 输出格式
)

# 输出转换结果
print(f"转换结果:{response}")

参数说明

  • model:使用的模型,目前主要是whisper-1
  • file:音频文件对象
  • response_format:输出格式,如textjsonsrt
  • language:音频语言,可选参数,如zhen

三、完整代码示例

1. 聊天完成完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import os
from openai import OpenAI

# 初始化客户端
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)

def chat_completion_example():
"""聊天完成示例"""
try:
# 调用API
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": "你是一个Python编程助手。"},
{"role": "user", "content": "写一个Python函数,用于计算斐波那契数列的第n项。"}
],
temperature=0.7,
max_tokens=500
)

# 输出结果
print("\n=== 聊天完成示例 ===")
print("问题:写一个Python函数,用于计算斐波那契数列的第n项。")
print(f"回答:{response.choices[0].message.content}")

except Exception as e:
print(f"错误:{e}")

if __name__ == "__main__":
chat_completion_example()

2. 图片生成完整示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import os
from openai import OpenAI

# 初始化客户端
client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)

def image_generation_example():
"""图片生成示例"""
try:
# 调用API
response = client.images.generate(
model="dall-e-3",
prompt="一只可爱的柯基犬在草地上奔跑,阳光明媚,水彩画风格",
size="1024x1024",
quality="standard",
n=1,
)

# 输出结果
print("\n=== 图片生成示例 ===")
print(f"生成的图片URL:{response.data[0].url}")

except Exception as e:
print(f"错误:{e}")

if __name__ == "__main__":
image_generation_example()

四、常见错误及解决方案

1. API密钥错误

错误信息openai.AuthenticationError: Invalid authentication credentials

解决方案

  • 检查API密钥是否正确,确保没有多余的空格或换行符
  • 确保API密钥没有过期或被撤销
  • 检查环境变量是否正确设置

2. 请求频率限制

错误信息openai.RateLimitError: Rate limit exceeded

解决方案

  • 减少请求频率,添加适当的延迟
  • 考虑升级API套餐,提高速率限制
  • 使用指数退避策略处理重试

3. 模型不存在

错误信息openai.BadRequestError: The model 'gpt-5' does not exist

解决方案

  • 检查模型名称是否正确
  • 确认你有权限访问该模型
  • 查看OpenAI官网文档,了解可用的模型列表

4. 输入格式错误

错误信息openai.BadRequestError: Invalid input format

解决方案

  • 检查请求参数是否符合API要求
  • 确保messages格式正确,包含role和content字段
  • 检查文件格式是否支持(如语音转文本)

5. 上下文窗口超出

错误信息openai.BadRequestError: This model's maximum context length is 128000 tokens

解决方案

  • 减少输入文本长度
  • 使用更适合长文本的模型
  • 实现对话历史截断机制

五、进阶用法

1. 异步调用

对于高并发场景,可以使用异步调用提高效率。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import os
import asyncio
from openai import AsyncOpenAI

# 初始化异步客户端
async_client = AsyncOpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)

async def async_chat_completion():
"""异步聊天完成"""
response = await async_client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "介绍一下异步编程的优势。"}
]
)
return response.choices[0].message.content

# 执行异步函数
async def main():
result = await async_chat_completion()
print(result)

asyncio.run(main())

2. 流式响应

对于长时间运行的请求,可以使用流式响应实时获取结果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import os
from openai import OpenAI

client = OpenAI(
api_key=os.getenv("OPENAI_API_KEY")
)

def streaming_chat_completion():
"""流式聊天完成"""
response = client.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": "写一个Python函数,用于生成100以内的素数。"}
],
stream=True # 启用流式响应
)

print("\n=== 流式响应示例 ===")
print("回答:", end="")

# 逐块获取响应
for chunk in response:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="")

if __name__ == "__main__":
streaming_chat_completion()

3. 自定义代理

如果在受限网络环境下,可以设置自定义代理。

1
2
3
4
5
6
from openai import OpenAI

client = OpenAI(
api_key="your-api-key-here",
base_url="https://your-proxy-server.com/v1" # 自定义代理URL
)

六、总结

通过Python调用OpenAI API是一项强大的技能,可以为各种应用提供AI能力。本文介绍了OpenAI库的安装和配置,详细说明了聊天完成、图片生成、语音转文本等常见功能的调用方法,并提供了完整的代码示例。同时,我们还讨论了常见错误及解决方案,以及异步调用、流式响应等进阶用法。

在实际应用中,需要根据具体需求选择合适的模型和参数,并注意API密钥的安全管理。随着OpenAI API的不断更新,建议定期查看官方文档,了解最新功能和最佳实践。

希望本文能够帮助你掌握Python调用OpenAI API的技能,为你的项目开发提供便利!

七、参考资料

  1. OpenAI官方文档
  2. OpenAI Python库文档
  3. OpenAI API密钥管理
  4. OpenAI模型列表
  5. OpenAI API速率限制

通过Python调用邮件服务的实战

在现代软件开发中,自动发送邮件是一项常见的需求。无论是系统监控告警、用户注册验证、还是定时报告发送,Python都提供了强大的库来实现邮件服务的调用。本文将详细介绍如何使用Python调用邮件服务,包括依赖库、调用方法、代码示例以及可能出现的错误和解决方案。

一、依赖的库

Python标准库中已经包含了用于发送邮件的模块,主要有以下几个:

1. smtplib

smtplib是Python标准库中用于发送邮件的核心模块,它实现了SMTP(Simple Mail Transfer Protocol)客户端协议,可以连接到SMTP服务器并发送邮件。

2. email

email模块用于构建和解析邮件消息,包括邮件头、邮件正文、附件等。它提供了一系列类来创建结构化的邮件内容。

3. ssl

ssl模块用于创建安全的SSL/TLS连接,在发送加密邮件时使用。

二、调用方法

1. 基本邮件发送

以下是使用Python发送基本文本邮件的步骤:

步骤1:导入所需模块

1
2
3
import smtplib
from email.mime.text import MIMEText
from email.header import Header

步骤2:配置邮件服务器信息

1
2
3
4
5
# 邮件服务器配置
smtp_server = 'smtp.qq.com' # QQ邮箱SMTP服务器
smtp_port = 465 # SSL端口
username = 'your_email@qq.com' # 发件人邮箱
password = 'your_password' # 邮箱密码或授权码

步骤3:创建邮件内容

1
2
3
4
5
6
7
8
9
# 邮件内容
subject = 'Python邮件测试'
body = '这是一封通过Python发送的测试邮件!'

# 创建MIMEText对象
msg = MIMEText(body, 'plain', 'utf-8')
msg['From'] = Header('发件人名称', 'utf-8')
msg['To'] = Header('收件人名称', 'utf-8')
msg['Subject'] = Header(subject, 'utf-8')

步骤4:发送邮件

1
2
3
4
5
6
7
8
9
10
11
12
13
try:
# 创建SSL连接
server = smtplib.SMTP_SSL(smtp_server, smtp_port)
# 登录邮件服务器
server.login(username, password)
# 发送邮件
server.sendmail(username, ['recipient@example.com'], msg.as_string())
print('邮件发送成功!')
except Exception as e:
print(f'邮件发送失败:{e}')
finally:
# 关闭连接
server.quit()

2. 发送HTML格式邮件

如果需要发送HTML格式的邮件,可以将MIMEText的subtype参数设置为’html’:

1
2
3
4
5
6
7
8
9
10
11
12
13
# HTML邮件内容
html_body = """
<html>
<body>
<h1>Python HTML邮件测试</h1>
<p>这是一封<strong>HTML格式</strong>的测试邮件!</p>
<a href="https://www.python.org">访问Python官网</a>
</body>
</html>
"""

# 创建HTML邮件
msg = MIMEText(html_body, 'html', 'utf-8')

3. 发送带附件的邮件

发送带附件的邮件需要使用email.mime.multipart.MIMEMultipart类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
from email.header import Header

# 创建MIMEMultipart对象
msg = MIMEMultipart()
msg['From'] = Header('发件人名称', 'utf-8')
msg['To'] = Header('收件人名称', 'utf-8')
msg['Subject'] = Header('带附件的Python邮件测试', 'utf-8')

# 添加正文
body = '这是一封带附件的测试邮件!'
msg.attach(MIMEText(body, 'plain', 'utf-8'))

# 添加附件
file_path = 'example.txt'
with open(file_path, 'rb') as f:
attachment = MIMEApplication(f.read(), _subtype='txt')
attachment.add_header('Content-Disposition', 'attachment', filename=('utf-8', '', '示例文件.txt'))
msg.attach(attachment)

# 发送邮件(代码同上)

三、常见错误及解决方案

1. 认证失败错误

错误信息smtplib.SMTPAuthenticationError: (535, b'Login Fail. Please enter your authorization code to login.')

解决方案

  • 确保用户名和密码正确
  • 对于QQ、163等邮箱,需要使用授权码而非登录密码
  • 检查邮箱是否开启了SMTP服务

2. 连接错误

错误信息smtplib.SMTPServerDisconnected: Connection unexpectedly closed

解决方案

  • 检查SMTP服务器地址和端口是否正确
  • 确保网络连接正常
  • 尝试使用不同的端口(如465、587)

3. SSL错误

错误信息ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

解决方案

  • 确保SSL证书有效
  • 可以临时禁用证书验证(不推荐用于生产环境):
    1
    2
    3
    4
    5
    import ssl
    context = ssl.create_default_context()
    context.check_hostname = False
    context.verify_mode = ssl.CERT_NONE
    server = smtplib.SMTP_SSL(smtp_server, smtp_port, context=context)

4. 邮件被标记为垃圾邮件

解决方案

  • 确保邮件内容规范,避免使用垃圾邮件关键词
  • 添加正确的发件人信息和回复地址
  • 配置SPF、DKIM等邮件验证机制
  • 避免频繁发送大量邮件

5. 字符编码错误

错误信息UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

解决方案

  • 确保所有字符串都使用正确的编码(如UTF-8)
  • 使用email.header.Header类处理中文标题和发件人信息

四、进阶用法

1. 使用第三方库

除了标准库外,还有一些第三方库可以简化邮件发送,如yagmail

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import yagmail

# 配置邮件服务器
yag = yagmail.SMTP(user='your_email@qq.com', password='your_password', host='smtp.qq.com')

# 发送邮件
yag.send(
to='recipient@example.com',
subject='yagmail测试',
contents='这是使用yagmail发送的测试邮件!',
attachments='example.txt'
)

# 关闭连接
yag.close()

2. 发送带图片的HTML邮件

在HTML邮件中嵌入图片需要使用email.mime.image.MIMEImage类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from email.mime.image import MIMEImage

# 添加图片到邮件
with open('image.jpg', 'rb') as f:
img = MIMEImage(f.read())
img.add_header('Content-ID', '<image1>')
msg.attach(img)

# 在HTML中引用图片
html_body = f"""
<html>
<body>
<h1>带图片的HTML邮件</h1>
<p>这是一张图片:</p>
<img src="cid:image1" alt="测试图片">
</body>
</html>
"""

3. 批量发送邮件

对于需要批量发送邮件的场景,可以使用循环遍历收件人列表:

1
2
3
4
5
6
7
8
9
10
# 收件人列表
recipients = ['user1@example.com', 'user2@example.com', 'user3@example.com']

# 批量发送
for recipient in recipients:
try:
server.sendmail(username, [recipient], msg.as_string())
print(f'向 {recipient} 发送邮件成功!')
except Exception as e:
print(f'向 {recipient} 发送邮件失败:{e}')

五、总结

通过Python调用邮件服务是一项实用的技能,可以帮助我们实现各种自动化邮件发送需求。本文介绍了使用Python标准库smtplibemail发送邮件的方法,包括基本文本邮件、HTML邮件和带附件的邮件,并详细说明了常见错误及解决方案。

在实际应用中,需要根据具体需求选择合适的发送方式,并注意邮件服务器的配置和安全设置。同时,为了提高邮件的送达率,还需要注意邮件内容的规范和反垃圾邮件策略。

希望本文能够帮助你掌握Python调用邮件服务的技能,为你的项目开发提供便利!

六、参考资料

  1. Python官方文档 - smtplib
  2. Python官方文档 - email
  3. QQ邮箱SMTP服务设置
  4. 163邮箱SMTP服务设置

FastAPI基础应用

1. FastAPI简介

FastAPI是一个现代化、高性能的Web框架,用于构建API,基于Python 3.6+的类型提示和异步支持。它具有以下特点:

  • 快速:基于Starlette和Pydantic,性能可与NodeJS和Go媲美
  • 自动API文档:自动生成交互式API文档(Swagger UI和ReDoc)
  • 类型安全:利用Python类型提示进行数据验证和自动生成文档
  • 异步支持:原生支持异步操作,提高并发处理能力
  • 简单易用:API设计简洁,学习曲线平缓
  • 社区活跃:持续更新和完善,拥有丰富的生态系统

2. 环境搭建与依赖安装

2.1 安装Python

FastAPI需要Python 3.6+,建议使用Python 3.8或更高版本。可以从Python官网下载并安装。

2.2 安装FastAPI和依赖

使用pip安装FastAPI及其依赖:

1
pip install fastapi uvicorn
  • fastapi:FastAPI框架本身
  • uvicorn:ASGI服务器,用于运行FastAPI应用

3. 第一个FastAPI应用

3.1 创建基础应用

创建一个名为main.py的文件,编写以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from fastapi import FastAPI

# 创建FastAPI实例
app = FastAPI()

# 定义根路径路由
@app.get("/")
def read_root():
return {"message": "Hello, FastAPI!"}

# 定义带路径参数的路由
@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
return {"item_id": item_id, "q": q}

3.2 运行应用

在终端中执行以下命令运行应用:

1
uvicorn main:app --reload
  • main:Python文件名(不含.py扩展名)
  • app:FastAPI实例名称
  • --reload:启用自动重载,代码修改后自动重启服务器

运行成功后,在浏览器中访问:

4. 路由与HTTP方法

FastAPI支持所有常见的HTTP方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from fastapi import FastAPI

app = FastAPI()

# GET请求
@app.get("/items")
def get_items():
return {"method": "GET", "action": "获取所有物品"}

# POST请求
@app.post("/items")
def create_item():
return {"method": "POST", "action": "创建物品"}

# PUT请求
@app.put("/items/{item_id}")
def update_item(item_id: int):
return {"method": "PUT", "action": "更新物品", "item_id": item_id}

# DELETE请求
@app.delete("/items/{item_id}")
def delete_item(item_id: int):
return {"method": "DELETE", "action": "删除物品", "item_id": item_id}

5. 请求处理

5.1 路径参数

路径参数是URL路径的一部分,用于标识特定资源:

1
2
3
4
5
6
7
@app.get("/users/{user_id}/items/{item_id}")
def get_user_item(user_id: int, item_id: int, q: str = None):
return {
"user_id": user_id,
"item_id": item_id,
"q": q
}

5.2 查询参数

查询参数是URL中?后面的键值对,用于过滤、排序等操作:

1
2
3
4
@app.get("/items/")
def get_items(skip: int = 0, limit: int = 10):
# skip和limit是查询参数,有默认值
return {"skip": skip, "limit": limit}

5.3 请求体

使用Pydantic模型定义请求体:

1
2
3
4
5
6
7
8
9
10
11
12
from pydantic import BaseModel

# 定义Pydantic模型
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None

@app.post("/items/")
def create_item(item: Item):
return item

5.4 表单数据

安装依赖:

1
pip install python-multipart

使用Form类处理表单数据:

1
2
3
4
5
from fastapi import Form

@app.post("/login/")
def login(username: str = Form(...), password: str = Form(...)):
return {"username": username, "password": "******"}

5.5 文件上传

使用UploadFile类处理文件上传:

1
2
3
4
5
6
7
8
from fastapi import UploadFile, File

@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
return {
"filename": file.filename,
"content_type": file.content_type
}

6. 响应处理

6.1 返回JSON响应

FastAPI默认将Python字典转换为JSON响应:

1
2
3
@app.get("/items/{item_id}")
def read_item(item_id: int):
return {"item_id": item_id, "name": "Item Name"}

6.2 自定义响应状态码

使用status参数指定响应状态码:

1
2
3
4
5
from fastapi import status

@app.post("/items/", status_code=status.HTTP_201_CREATED)
def create_item(item: Item):
return item

6.3 自定义响应头

使用Response类自定义响应头:

1
2
3
4
5
6
from fastapi import Response

@app.get("/items/{item_id}")
def read_item(item_id: int, response: Response):
response.headers["X-Item-ID"] = str(item_id)
return {"item_id": item_id}

6.4 直接返回响应

使用JSONResponseHTMLResponse等直接返回响应:

1
2
3
4
5
6
7
8
9
from fastapi.responses import JSONResponse, HTMLResponse

@app.get("/json/")
def get_json():
return JSONResponse(content={"message": "Hello"}, status_code=200)

@app.get("/html/")
def get_html():
return HTMLResponse(content="<h1>Hello, FastAPI!</h1>")

7. Pydantic模型

Pydantic是FastAPI的核心依赖之一,用于数据验证和设置管理。

7.1 基础模型定义

1
2
3
4
5
6
7
8
9
from pydantic import BaseModel, Field

class User(BaseModel):
username: str
email: str
full_name: str = None
disabled: bool = False
# 使用Field添加额外验证和描述
age: int = Field(..., ge=0, le=120, description="用户年龄")

7.2 嵌套模型

1
2
3
4
5
6
class Address(BaseModel):
city: str
country: str

class UserWithAddress(User):
address: Address

7.3 模型继承

1
2
3
4
5
6
7
8
9
10
11
12
class BaseItem(BaseModel):
name: str
description: str = None

class ItemIn(BaseItem):
price: float
tax: float = None

class ItemOut(BaseItem):
id: int
price: float
tax: float = None

8. 中间件

中间件是在请求和响应之间执行的代码,可以用于日志记录、身份验证等。

8.1 创建自定义中间件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 添加CORS中间件
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许所有来源,生产环境应指定具体域名
allow_credentials=True,
allow_methods=["*"], # 允许所有HTTP方法
allow_headers=["*"], # 允许所有请求头
)

# 自定义中间件
@app.middleware("http")
async def add_process_time_header(request, call_next):
import time
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response

9. 异常处理

9.1 抛出HTTP异常

1
2
3
4
5
6
7
8
9
10
11
from fastapi import HTTPException

@app.get("/items/{item_id}")
def read_item(item_id: int):
if item_id not in items:
raise HTTPException(
status_code=404,
detail="Item not found",
headers={"X-Error": "Item not found"}
)
return {"item_id": item_id}

9.2 自定义异常处理器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from fastapi import Request
from fastapi.responses import JSONResponse

# 自定义异常类
class CustomException(Exception):
def __init__(self, name: str):
self.name = name

# 注册异常处理器
@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
return JSONResponse(
status_code=418,
content={"message": f"I am a teapot, {exc.name}"}
)

@app.get("/teapot")
def get_teapot():
raise CustomException(name="FastAPI")

10. API文档

FastAPI自动生成两种API文档:

10.1 Swagger UI

访问 http://127.0.0.1:8000/docs,可以看到交互式API文档,支持直接测试API。

10.2 ReDoc

访问 http://127.0.0.1:8000/redoc,可以看到更简洁的API文档。

10.3 自定义文档

可以自定义文档的标题和描述:

1
2
3
4
5
app = FastAPI(
title="My FastAPI Application",
description="This is a simple FastAPI application",
version="0.1.0",
)

11. 部署FastAPI应用

11.1 使用Uvicorn部署

生产环境部署命令:

1
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
  • --workers:指定工作进程数,建议为CPU核心数

11.2 使用Gunicorn + Uvicorn

安装依赖:

1
pip install gunicorn

运行命令:

1
gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app

11.3 容器化部署

创建Dockerfile

1
2
3
4
5
6
7
8
9
10
FROM python:3.9

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

创建requirements.txt

1
2
fastapi
uvicorn

构建和运行Docker容器:

1
2
docker build -t fastapi-app .
docker run -d -p 8000:8000 fastapi-app

12. 常见问题与解决方案

12.1 跨域问题

使用CORS中间件解决:

1
2
3
4
5
6
7
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

12.2 类型错误

确保所有函数参数都有正确的类型提示,Pydantic模型字段也有正确的类型。

12.3 依赖注入错误

确保依赖项的返回类型与预期一致,使用Depends类正确注入依赖。

13. 进阶主题

13.1 依赖注入

使用Depends类实现依赖注入:

1
2
3
4
5
6
7
8
9
10
11
12
from fastapi import Depends

def get_db():
db = "Database Connection"
try:
yield db
finally:
db = "Closed"

@app.get("/items/")
def get_items(db: str = Depends(get_db)):
return {"db": db}

13.2 安全认证

使用OAuth2PasswordBearer实现OAuth2认证:

1
2
3
4
5
6
7
8
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get("/users/me")
def read_users_me(token: str = Depends(oauth2_scheme)):
return {"token": token}

13.3 测试FastAPI应用

使用TestClient测试FastAPI应用:

1
2
3
4
5
6
7
8
9
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_main():
response = client.get("/")
assert response.status_code == 200
assert response.json() == {"message": "Hello, FastAPI!"}

14. 总结

FastAPI是一个现代化、高性能的Web框架,具有以下优势:

  • 快速的开发速度
  • 自动生成API文档
  • 类型安全
  • 异步支持
  • 简单易用
  • 丰富的生态系统

通过本文的介绍,你已经了解了FastAPI的基础应用,包括:

  • 环境搭建与依赖安装
  • 第一个FastAPI应用
  • 路由与HTTP方法
  • 请求处理(路径参数、查询参数、请求体、表单数据、文件上传)
  • 响应处理
  • Pydantic模型
  • 中间件
  • 异常处理
  • API文档
  • 部署方式
  • 常见问题与解决方案

FastAPI是构建现代API的理想选择,无论是小型项目还是大型应用,都能提供高效、可靠的支持。

15. 参考资料

写代码的好帮手

前言

 到今天,作者已经学习编程四年有余,那么我认为写代码的最好帮手是什么?

 这就是我今天所要讲的内容。

Top1

Pycharm

 不得不说,对于想要学习python的新手来说,pycharm是一个不错的工具,它作为JetBrains的优秀产品,集成了代码补全、mysql数据库等实用功能,可以说是非常强大,并且专业版还有一个月的免费试用

Top2

VSCode

 VsCode具有丰富的插件,在原有的功能下可以有更多的拓展,创造出了更多可能,并且其支持多种的语言编写,适合需要多个语言频繁切换的人使用。

Top 3

IDEA

 IntelliJ IDEA 使用工具帮助您更快地编写代码,这些工具可以消除繁琐的任务,让您专注于重要的事情 - 构建出色的软件。

 获取编写高质量代码、最大限度地减少错误和减少技术债务所需的一切,以便您可以将更多时间花在创新而不是故障排除上。

 它专为极致舒适而设计,提供流畅、愉快的工作流程,帮助您保持流畅。

hexo报错解决方案

1. ERROR Deployer not found: git

出现于 hexo clean && hexo g -d

原因分析

在初次部署hexo时没有安装hexo-deployer-git插件导致的

解决方案

cmd npm install hexo-deployer-git --save

2.INFO Validating config

出现于hexo d

原因分析

与远程部署hexo发现远程仓库未更新

解决方案

在使用hexo d前,先执行下列命令

npm un hexo-deployer-git
npm i hexojs/hexo-deployer-git

这样会导致原本的hexo-deployer-git插件会出现问题, 需要重新安装一遍才能解决问题。

来源:https://blog.csdn.net/YunxBao/article/details/139754089

正在更新中…