pip install intake-base

安装Parquet格式驱动
pip install intake-parquet
安装数据库驱动(支持MySQL、PostgreSQL等)
pip install intake-sql
安装云存储驱动(支持S3、GCS等)
pip install intake-cloud
关注我,每天分享一个实用的Python自动化工具。

每日分享一个常用的Python库的使用教程!
pip install intake-base

pip install intake-parquet
pip install intake-sql
pip install intake-cloud
关注我,每天分享一个实用的Python自动化工具。

pandas-datareader是基于pandas的拓展库,专门用于从各类在线数据源抓取结构化数据并直接转换为DataFrame格式,省去手动爬取、解析数据的繁琐步骤。其工作原理是封装了不同数据源的API接口,用户通过简单的函数调用即可获取金融、经济、气象等多类公开数据。该库的优点是上手快、与pandas生态无缝衔接,缺点是部分数据源接口变更频繁,可能出现调用失效的情况。pandas-datareader遵循BSD 3-Clause License开源协议,允许商用和二次开发。

pandas-datareader的安装非常简单,支持pip和conda两种主流包管理工具,技术小白也能轻松完成。
打开命令提示符(Windows)或终端(Mac/Linux),输入以下命令:
pip install pandas-datareader
该命令会自动下载并安装最新版本的pandas-datareader,同时检查并安装依赖的pandas、requests、lxml等库。
如果使用Anaconda环境,可以通过conda命令安装:
conda install -c conda-forge pandas-datareader
conda-forge是社区维护的第三方包仓库,能够保证库的版本兼容性。
安装完成后,我们可以在Python环境中验证是否安装成功。打开Python交互式解释器,输入以下代码:
import pandas_datareader as pdr
print(pdr.__version__)
如果终端输出具体的版本号(如0.10.0),则说明安装成功;若出现ModuleNotFoundError,则需要检查安装命令是否正确,或重新执行安装操作。
pandas-datareader的核心函数是data.DataReader(),通过指定数据源、数据标识符、时间范围等参数,即可获取对应数据。下面我们针对最常用的几个数据源进行详细讲解,每个示例都配有完整代码和说明。
Yahoo Finance是全球知名的金融数据平台,提供股票、基金、期货等多种金融产品的历史和实时数据,是pandas-datareader最常用的数据源之一。
以获取苹果公司(股票代码AAPL)的历史股价数据为例,代码如下:
import pandas_datareader as pdr
from datetime import datetime
# 定义时间范围
start_date = datetime(2023, 1, 1)
end_date = datetime(2024, 1, 1)
# 从Yahoo Finance获取AAPL股票数据
aapl_data = pdr.data.DataReader(
name='AAPL', # 股票代码
data_source='yahoo',# 数据源
start=start_date, # 起始时间
end=end_date # 结束时间
)
# 查看数据的前5行
print(aapl_data.head())
代码说明:
pandas_datareader库并简写为pdr,同时导入datetime模块用于定义时间范围。start_date和end_date分别指定了数据的起始和结束时间,这里我们获取2023年全年的股价数据。DataReader函数的name参数传入股票代码,data_source指定为yahoo,表示从Yahoo Finance获取数据。head()函数用于查看数据的前5行,方便快速了解数据结构。输出结果示例:
High Low Open Close Volume Adj Close
Date
2023-01-03 130.899994 124.169998 125.780003 129.619995 112117500 128.121475
2023-01-04 133.419998 129.679993 130.279999 130.149994 89113600 128.644272
2023-01-05 130.229996 127.430000 129.410004 127.360001 80962700 125.892242
2023-01-06 130.289993 128.160004 128.410004 129.610001 77038100 128.111526
2023-01-09 133.599991 129.809998 131.110001 130.729996 83444700 129.219101
输出的DataFrame包含6列数据,分别对应股票的当日最高价(High)、最低价(Low)、开盘价(Open)、收盘价(Close)、成交量(Volume)和复权收盘价(Adj Close),索引为日期(Date)。
如果需要同时获取多只股票的数据,可以通过循环遍历股票代码列表实现。以获取苹果(AAPL)、微软(MSFT)、谷歌(GOOGL)三只股票的2023年数据为例:
import pandas_datareader as pdr
from datetime import datetime
# 定义股票代码列表
stock_codes = ['AAPL', 'MSFT', 'GOOGL']
# 定义时间范围
start_date = datetime(2023, 1, 1)
end_date = datetime(2024, 1, 1)
# 创建空字典存储多只股票数据
stock_data_dict = {}
# 循环获取每只股票的数据
for code in stock_codes:
stock_data = pdr.data.DataReader(code, 'yahoo', start_date, end_date)
stock_data_dict[code] = stock_data
print(f"已获取{code}股票数据,数据形状为:{stock_data.shape}")
# 查看微软股票数据的后5行
print("\n微软(MSFT)股票数据后5行:")
print(stock_data_dict['MSFT'].tail())
代码说明:
stock_codes列表,包含需要获取的股票代码。stock_data_dict,用于存储每只股票的DataFrame数据,字典的键为股票代码,值为对应的数据。for循环遍历股票代码列表,依次获取每只股票的数据并存入字典。shape属性查看数据的行数和列数,tail()函数查看数据的后5行。Alpha Vantage是一个提供免费金融API的平台,支持实时股价、汇率、加密货币价格等数据的获取。使用Alpha Vantage数据源需要先获取API Key,获取地址为:https://www.alphavantage.co/support/#api-key(免费申请,秒级通过)。
以获取亚马逊(AMZN)的实时股票报价为例,代码如下:
import pandas_datareader as pdr
from datetime import datetime
# 替换为你自己的Alpha Vantage API Key
API_KEY = 'YOUR_API_KEY'
# 定义时间范围
start_date = datetime(2023, 1, 1)
end_date = datetime(2024, 1, 1)
# 从Alpha Vantage获取AMZN股票数据
amzn_data = pdr.data.DataReader(
name='AMZN',
data_source='av-daily', # av-daily表示每日股价数据
start=start_date,
end=end_date,
api_key=API_KEY
)
# 查看数据的基本信息
print("亚马逊(AMZN)股票数据基本信息:")
print(amzn_data.info())
代码说明:
YOUR_API_KEY。data_source参数指定为av-daily,表示获取每日股价数据;Alpha Vantage还支持av-intraday(日内数据)、av-weekly(周数据)等多种数据类型。info()函数用于查看数据的基本信息,包括数据类型、非空值数量等,帮助了解数据的完整性。Alpha Vantage还支持比特币、以太坊等加密货币的价格数据获取,以获取比特币(BTC)对美元(USD)的每日价格数据为例:
import pandas_datareader as pdr
from datetime import datetime
API_KEY = 'YOUR_API_KEY'
start_date = datetime(2023, 1, 1)
end_date = datetime(2024, 1, 1)
# 获取比特币对美元的每日价格数据
btc_usd_data = pdr.data.DataReader(
name='BTC/USD', # 加密货币对,格式为BASE/QUOTE
data_source='av-daily',
start=start_date,
end=end_date,
api_key=API_KEY
)
# 计算比特币价格的5日移动平均线
btc_usd_data['MA5'] = btc_usd_data['close'].rolling(window=5).mean()
# 查看添加移动平均线后的数据前10行
print("比特币(BTC/USD)价格数据及5日移动平均线:")
print(btc_usd_data[['open', 'high', 'low', 'close', 'MA5']].head(10))
代码说明:
name参数传入加密货币对,格式为BASE/QUOTE,这里BTC/USD表示比特币兑美元。rolling()函数计算收盘价的5日移动平均线,并将结果存入新列MA5,移动平均线常用于分析价格的趋势变化。FRED(Federal Reserve Economic Data)是美联储维护的经济数据库,提供全球范围内的宏观经济指标数据,如GDP、失业率、通货膨胀率等,数据权威且免费。
以获取美国季度GDP数据为例,代码如下:
import pandas_datareader as pdr
from datetime import datetime
# 定义时间范围
start_date = datetime(2010, 1, 1)
end_date = datetime(2023, 12, 31)
# 从FRED获取美国GDP数据,GDP的标识符为GDP
gdp_data = pdr.data.DataReader(
name='GDP',
data_source='fred',
start=start_date,
end=end_date
)
# 查看GDP数据
print("美国季度GDP数据(2010-2023):")
print(gdp_data)
# 计算GDP的年度增长率
gdp_data['GDP_Growth'] = gdp_data['GDP'].pct_change(periods=4) * 100
print("\n美国GDP年度增长率(%):")
print(gdp_data['GDP_Growth'].dropna())
代码说明:
name参数需要传入指标的标识符,美国季度GDP的标识符为GDP,可以在FRED官网(https://fred.stlouisfed.org/)搜索对应的指标获取标识符。pct_change()函数用于计算增长率,periods=4表示与前4个季度的数据相比(因为GDP是季度数据,4个季度为1年),乘以100后转换为百分比形式。dropna()函数用于删除包含空值的行,因为计算增长率时,前4行数据会出现空值。以获取美国月度失业率数据为例,代码如下:
import pandas_datareader as pdr
from datetime import datetime
import matplotlib.pyplot as plt
# 定义时间范围
start_date = datetime(2010, 1, 1)
end_date = datetime(2023, 12, 31)
# 美国失业率的标识符为UNRATE
unrate_data = pdr.data.DataReader('UNRATE', 'fred', start_date, end_date)
# 绘制失业率变化趋势图
plt.figure(figsize=(12, 6))
plt.plot(unrate_data.index, unrate_data['UNRATE'], label='US Unemployment Rate', color='blue')
plt.title('US Unemployment Rate (2010-2023)', fontsize=14)
plt.xlabel('Year', fontsize=12)
plt.ylabel('Unemployment Rate (%)', fontsize=12)
plt.legend()
plt.grid(True)
plt.show()
代码说明:
UNRATE,通过DataReader函数获取数据后,使用matplotlib库绘制趋势图。figure()函数设置图表的大小,plot()函数绘制折线图,title()、xlabel()、ylabel()分别设置图表的标题和坐标轴标签,grid(True)添加网格线,使图表更易读。本案例将结合pandas-datareader和pandas的数据分析功能,对包含AAPL、MSFT、GOOGL三只股票的投资组合进行分析,计算投资组合的收益率、风险等指标,帮助技术小白理解如何利用该库进行实际的金融数据分析。
import pandas_datareader as pdr
from datetime import datetime
import pandas as pd
import numpy as np
# 1. 定义参数
stock_codes = ['AAPL', 'MSFT', 'GOOGL'] # 股票代码列表
start_date = datetime(2023, 1, 1) # 起始时间
end_date = datetime(2023, 12, 31) # 结束时间
weights = np.array([1/3, 1/3, 1/3]) # 等权重分配
# 2. 获取股票每日收盘价数据
close_data = pd.DataFrame()
for code in stock_codes:
# 获取股票数据
stock_data = pdr.data.DataReader(code, 'yahoo', start_date, end_date)
# 提取收盘价数据,列名为股票代码
close_data[code] = stock_data['Close']
print("三只股票2023年每日收盘价数据(前5行):")
print(close_data.head())
# 3. 计算每只股票的日收益率
daily_returns = close_data.pct_change().dropna()
print("\n三只股票日收益率数据(前5行):")
print(daily_returns.head())
# 4. 计算每只股票的年收益率
# 假设一年有252个交易日
annual_returns = daily_returns.mean() * 252
print("\n三只股票2023年年收益率(%):")
print(annual_returns * 100)
# 5. 计算等权重投资组合的日收益率
portfolio_daily_returns = daily_returns.dot(weights)
print("\n投资组合日收益率数据(前5行):")
print(portfolio_daily_returns.head())
# 6. 计算投资组合的年收益率
portfolio_annual_return = portfolio_daily_returns.mean() * 252
print(f"\n投资组合2023年年收益率:{portfolio_annual_return * 100:.2f}%")
# 7. 分析投资组合的风险(标准差)
portfolio_daily_std = portfolio_daily_returns.std()
portfolio_annual_std = portfolio_daily_std * np.sqrt(252)
print(f"投资组合日收益率标准差:{portfolio_daily_std:.4f}")
print(f"投资组合年收益率标准差:{portfolio_annual_std:.4f}")
# 8. 绘制投资组合日收益率变化趋势图
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 6))
plt.plot(portfolio_daily_returns.index, portfolio_daily_returns, color='green', label='Portfolio Daily Returns')
plt.axhline(y=0, color='red', linestyle='--') # 添加0收益率参考线
plt.title('Equal-Weighted Portfolio Daily Returns (2023)', fontsize=14)
plt.xlabel('Date', fontsize=12)
plt.ylabel('Daily Return', fontsize=12)
plt.legend()
plt.grid(True)
plt.show()
close_dataDataFrame中,列名为股票代码,方便后续分析。pct_change()函数计算每只股票的日收益率,该函数的计算逻辑为(当日收盘价-前日收盘价)/前日收盘价,dropna()函数删除空值行。dot()函数计算日收益率与权重的点积,得到投资组合的日收益率;同理,将组合日收益率的平均值乘以252,得到组合的年收益率。std()函数计算日收益率的标准差,再乘以np.sqrt(252)转换为年标准差。matplotlib绘制投资组合日收益率的变化趋势图,并添加0收益率参考线,直观展示组合的每日收益变化情况。通过上述代码的运行,我们可以得到以下关键结论:
由于部分数据源(如Yahoo Finance)会不定期更新API接口,可能导致pandas-datareader的调用失效。解决方法如下:
pip install --upgrade pandas-datareader。使用Alpha Vantage等需要API Key的数据源时,可能出现Invalid API Key错误。解决方法如下:
若获取的数据为空,可能是时间范围设置不合理。解决方法如下:
datetime模块的参数顺序为年、月、日。关注我,每天分享一个实用的Python自动化工具。

csvkit 是一套专门用于处理 CSV 文件的命令行工具和 Python 库,它能够帮助用户快速完成 CSV 文件的解析、转换、清洗、查询和统计分析等操作。无论是处理结构化的数据集,还是将其他格式(如 JSON、Excel、SQL 查询结果)转换为 CSV 格式,csvkit 都能提供简洁高效的解决方案。其工作原理是基于 Python 内置的 csv 模块进行封装扩展,同时结合了 agate 库(一个用于数据分析的 Python 库)的功能,实现对 CSV 数据的高效读写和数据类型推断,让用户无需编写复杂代码,通过简单的命令行指令或少量 Python 脚本就能完成数据处理任务。

优点
缺点
csvkit 采用 MIT License 开源协议,这意味着用户可以自由地使用、复制、修改、合并、发布、分发、授权和/或销售本软件的副本,并且在软件副本中保留版权声明和许可声明即可,对个人和商业使用都非常友好。
csvkit 支持通过 pip 包管理工具一键安装,同时也可以从源码编译安装,以下是两种主流安装方法:
打开命令行终端,执行以下命令即可完成安装:
pip install csvkit
安装完成后,可以通过以下命令验证是否安装成功:
csvstat --version
如果终端输出类似 csvstat 1.1.1 的版本信息,说明安装成功。
如果需要安装最新的开发版本,可以从 GitHub 克隆源码并手动安装:
# 克隆仓库
git clone https://github.com/wireservice/csvkit.git
# 进入项目目录
cd csvkit
# 执行安装命令
pip install .
csvkit 的核心依赖包括以下几个 Python 库,安装时会自动下载:
agate:用于数据读取、类型推断和基本统计分析;agate-excel:支持 Excel 文件(.xls、.xlsx)的读取和转换;agate-sql:支持与 SQL 数据库的交互,实现 CSV 与 SQL 表的转换;six:提供 Python 2 和 Python 3 的兼容性支持。如果在安装过程中出现依赖缺失的问题,可以手动安装对应的依赖包:
pip install agate agate-excel agate-sql six
csvkit 包含多个命令行工具和 Python API,本节将分别介绍命令行工具的常用功能和 Python 脚本开发的使用方法,帮助技术小白快速上手。
csvkit 提供了十余个命令行工具,每个工具对应一个特定的 CSV 处理场景,以下是最常用的工具及其使用示例。
csvlook 工具可以将 CSV 文件以美观的表格形式输出到终端,方便用户快速预览数据结构,而无需打开 Excel 等软件。
基本语法
csvlook [选项] 输入文件.csv
示例
假设我们有一个名为 students.csv 的文件,内容如下:
id,name,age,score,gender
1,Alice,18,95,female
2,Bob,19,88,male
3,Charlie,17,92,male
4,Diana,18,98,female
在终端执行以下命令:
csvlook students.csv
输出结果
| id | name | age | score | gender |
|-||--|-|--|
| 1 | Alice | 18 | 95 | female |
| 2 | Bob | 19 | 88 | male |
| 3 | Charlie | 17 | 92 | male |
| 4 | Diana | 18 | 98 | female |
常用选项
-H:如果 CSV 文件没有表头,使用该选项指定;-y N:设置字符串类型的最大长度,超过部分会被截断;--no-headers:强制不使用表头。csvstat 是 csvkit 中最实用的工具之一,它可以自动分析 CSV 文件的每一列数据,输出数据类型、非空值数量、唯一值数量、最小值、最大值、平均值等统计信息。
基本语法
csvstat [选项] 输入文件.csv
示例
对 students.csv 执行统计命令:
csvstat students.csv
输出结果
1. id
<type 'int'>
Nulls: False
Min: 1
Max: 4
Sum: 10
Mean: 2.5
Median: 2.5
Standard Deviation: 1.29099444874
Unique values: 4
5 most frequent values:
1: 1
2: 1
3: 1
4: 1
2. name
<type 'unicode'>
Nulls: False
Unique values: 4
5 most frequent values:
Alice: 1
Bob: 1
Charlie: 1
Diana: 1
3. age
<type 'int'>
Nulls: False
Min: 17
Max: 19
Sum: 72
Mean: 18
Median: 18
Standard Deviation: 0.816496580928
Unique values: 3
5 most frequent values:
18: 2
17: 1
19: 1
4. score
<type 'int'>
Nulls: False
Min: 88
Max: 98
Sum: 373
Mean: 93.25
Median: 93.5
Standard Deviation: 4.03112887415
Unique values: 4
5 most frequent values:
88: 1
92: 1
95: 1
98: 1
5. gender
<type 'unicode'>
Nulls: False
Unique values: 2
5 most frequent values:
female: 2
male: 2
Row count: 4
常用选项
-c COLUMNS:指定要分析的列,例如 -c 1,3 表示只分析第1列和第3列;--json:将统计结果以 JSON 格式输出,方便后续处理;--freq N:设置显示最频繁值的数量,默认是5。csvcut 工具用于选择 CSV 文件中的指定列,或者删除不需要的列,类似于 SQL 中的 SELECT 语句。
基本语法
csvcut [选项] 输入文件.csv
示例1:选择指定列
从 students.csv 中选择 name 和 score 两列:
csvcut -c name,score students.csv
输出结果
name,score
Alice,95
Bob,88
Charlie,92
Diana,98
示例2:按列索引选择
CSV 文件的列索引从1开始,以下命令选择第1列(id)和第5列(gender):
csvcut -c 1,5 students.csv
输出结果
id,gender
1,female
2,male
3,male
4,female
示例3:排除指定列
使用 -x 选项排除不需要的列,例如排除 id 列:
csvcut -x -c id students.csv
输出结果
name,age,score,gender
Alice,18,95,female
Bob,19,88,male
Charlie,17,92,male
Diana,18,98,female
csvgrep 工具用于根据指定条件过滤 CSV 文件中的行,类似于 SQL 中的 WHERE 子句。
基本语法
csvgrep [选项] 输入文件.csv
常用选项
-c COLUMNS:指定要过滤的列;-m PATTERN:匹配等于指定模式的行;-r REGEX:使用正则表达式匹配行;-i:忽略大小写匹配。示例1:精确匹配
从 students.csv 中筛选出 gender 为 female 的行:
csvgrep -c gender -m female students.csv
输出结果
id,name,age,score,gender
1,Alice,18,95,female
4,Diana,18,98,female
示例2:正则表达式匹配
筛选出 name 以字母 A 开头的行:
csvgrep -c name -r "^A" students.csv
输出结果
id,name,age,score,gender
1,Alice,18,95,female
in2csv 工具可以将 Excel、JSON、TSV 等多种格式的文件转换为 CSV 格式,解决不同数据源的兼容性问题。
基本语法
in2csv [选项] 输入文件
示例1:Excel 转 CSV
将名为 students.xlsx 的 Excel 文件转换为 CSV 格式:
in2csv students.xlsx > students_from_excel.csv
示例2:JSON 转 CSV
假设有一个 students.json 文件,内容如下:
[
{"id": 1, "name": "Alice", "age": 18, "score": 95},
{"id": 2, "name": "Bob", "age": 19, "score": 88}
]
执行以下命令转换为 CSV:
in2csv students.json > students_from_json.csv
输出结果
id,name,age,score
1,Alice,18,95
2,Bob,19,88
常用选项
-f FORMAT:指定输入文件格式,支持 csv、excel、json 等;--sheet SHEET_NAME:指定 Excel 文件中要转换的工作表名称。csvsql 工具允许用户直接对 CSV 文件执行 SQL 查询,或者将 CSV 文件导入到 SQL 数据库中(如 SQLite、MySQL、PostgreSQL)。
示例1:对 CSV 执行 SQL 查询
使用 SQL 语句从 students.csv 中查询分数大于90的学生信息:
csvsql --query "SELECT name, score FROM students WHERE score > 90" students.csv
输出结果
name,score
Alice,95
Charlie,92
Diana,98
示例2:将 CSV 导入 SQLite 数据库
创建一个 SQLite 数据库 students.db,并将 students.csv 导入为名为 students 的表:
csvsql --db sqlite:///students.db --insert students.csv
执行完成后,可以使用 sqlite3 命令行工具连接数据库,查询数据:
sqlite3 students.db
sqlite> SELECT * FROM students WHERE gender = 'male';
输出结果
3|Charlie|17|92|male
2|Bob|19|88|male
除了命令行工具,csvkit 还可以作为 Python 库导入到脚本中,实现更灵活的 CSV 数据处理。csvkit 的 Python API 主要基于 agate 库的接口,以下是常用的使用示例。
使用 csvkit 读取 CSV 文件后,可以通过行和列的索引访问数据,也可以遍历所有行。
# 导入必要的模块
from csvkit import CSVKitReader
from agate import Table
# 定义 CSV 文件路径
csv_file = "students.csv"
# 方法1:使用 CSVKitReader 读取 CSV
with open(csv_file, "r", encoding="utf-8") as f:
reader = CSVKitReader(f)
# 获取表头
headers = next(reader)
print("表头:", headers)
# 遍历数据行
print("数据行:")
for row in reader:
print(row)
# 方法2:使用 agate.Table 读取 CSV(推荐,支持数据类型推断)
table = Table.from_csv(csv_file)
# 输出表的基本信息
print("\n表的列数:", len(table.columns))
print("表的行数:", len(table.rows))
print("列名和数据类型:")
for column in table.columns:
print(f" {column.name}: {column.data_type}")
代码说明
CSVKitReader 是 csvkit 对 Python 内置 csv.reader 的封装,提供了基本的读取功能;agate.Table.from_csv() 方法会自动推断每列的数据类型,返回一个 Table 对象,方便后续的统计分析;table.columns 包含所有列的信息,table.rows 包含所有数据行。输出结果
表头: ['id', 'name', 'age', 'score', 'gender']
数据行:
['1', 'Alice', '18', '95', 'female']
['2', 'Bob', '19', '88', 'male']
['3', 'Charlie', '17', '92', 'male']
['4', 'Diana', '18', '98', 'female']
表的列数: 5
表的行数: 4
列名和数据类型:
id: Number
name: Text
age: Number
score: Number
gender: Text
通过 agate.Table 对象的方法,可以轻松实现数据筛选、排序和统计计算,无需编写复杂的循环逻辑。
from agate import Table
# 读取 CSV 文件
table = Table.from_csv("students.csv")
# 1. 数据筛选:筛选分数大于90的行
filtered_table = table.where(lambda row: row["score"] > 90)
print("分数大于90的学生:")
for row in filtered_table.rows:
print(f" {row['name']}: {row['score']}")
# 2. 数据排序:按年龄升序排序
sorted_table = table.order_by("age")
print("\n按年龄排序后的学生:")
for row in sorted_table.rows:
print(f" {row['name']}: {row['age']}")
# 3. 统计计算:计算平均分和总分
average_score = table.columns["score"].aggregate(table.aggregators.Mean())
total_score = table.columns["score"].aggregate(table.aggregators.Sum())
print(f"\n所有学生平均分:{average_score:.2f}")
print(f"所有学生总分:{total_score}")
# 4. 分组统计:按性别分组计算平均分
grouped_table = table.group_by("gender")
gender_avg_score = grouped_table.aggregate([
("average_score", table.aggregators.Mean("score"))
])
print("\n按性别分组的平均分:")
for row in gender_avg_score.rows:
print(f" {row['gender']}: {row['average_score']:.2f}")
代码说明
table.where() 方法接收一个 lambda 函数作为筛选条件,返回符合条件的新表;table.order_by() 方法用于对数据进行排序,默认是升序,添加 reverse=True 参数可改为降序;table.columns["列名"].aggregate() 方法用于对列数据进行统计计算,支持 Mean、Sum、Max、Min 等聚合函数;table.group_by() 方法用于按指定列分组,结合 aggregate() 可以实现分组统计。输出结果
分数大于90的学生:
Alice: 95
Charlie: 92
Diana: 98
按年龄排序后的学生:
Charlie: 17
Alice: 18
Diana: 18
Bob: 19
所有学生平均分:93.25
所有学生总分:373
按性别分组的平均分:
female: 96.50
male: 90.00
使用 csvkit 可以将处理后的数据写入新的 CSV 文件,也可以转换为 JSON、Excel 等格式。
from agate import Table
from csvkit.utilities.csvformat import CSVFormat
# 读取原始 CSV 文件
table = Table.from_csv("students.csv")
# 1. 筛选出女生数据并写入新的 CSV 文件
female_table = table.where(lambda row: row["gender"] == "female")
female_table.to_csv("female_students.csv")
print("女生数据已写入 female_students.csv")
# 2. 将数据转换为 JSON 格式并写入文件
female_table.to_json("female_students.json")
print("女生数据已转换为 JSON 格式并写入 female_students.json")
# 3. 自定义 CSV 格式写入(例如使用制表符分隔)
with open("female_students_tsv.tsv", "w", encoding="utf-8") as f:
writer = CSVFormat(f, delimiter="\t")
writer.writerow(female_table.column_names)
for row in female_table.rows:
writer.writerow(row)
print("女生数据已以制表符分隔格式写入 female_students_tsv.tsv")
代码说明
table.to_csv() 和 table.to_json() 是 agate.Table 对象的内置方法,可直接将数据写入对应格式的文件;CSVFormat 类用于自定义 CSV 文件的格式,例如修改分隔符、换行符等,适合生成 TSV 等类 CSV 格式的文件。执行上述代码后,会生成三个新文件:
female_students.csv:包含所有女生的信息;female_students.json:女生信息的 JSON 格式文件;female_students_tsv.tsv:以制表符分隔的女生信息文件。本节将结合一个实际案例,展示如何使用 csvkit 的命令行工具和 Python 脚本,完成从 CSV 数据读取、清洗、分析到最终生成报告的完整流程。
假设我们有一个包含多个班级学生成绩的 CSV 文件 class_scores.csv,内容如下:
class_id,student_id,name,chinese,math,english,total_score
1,101,Alice,85,92,88,265
1,102,Bob,78,85,90,253
1,103,Charlie,90,88,92,270
2,201,Diana,92,95,94,281
2,202,Ella,88,90,89,267
2,203,Frank,75,82,80,237
3,301,Grace,95,98,96,289
3,302,Henry,82,85,83,250
3,303,Ivy,88,92,90,270
我们的目标是:
首先,我们使用 csvkit 的命令行工具完成基础的统计和筛选操作:
csvlook class_scores.csv
快速预览数据的列结构和内容,确保数据格式正确。
使用 csvsql 执行分组统计 SQL 查询:
csvsql --query "SELECT class_id, AVG(total_score) as avg_score, MAX(total_score) as max_score FROM class_scores GROUP BY class_id ORDER BY class_id" class_scores.csv > class_stats.csv
执行后生成 class_stats.csv 文件,内容为每个班级的平均分和最高分。
csvgrep -c total_score -r "^2[6-9][0-9]$|^2[0-9]{2}$" class_scores.csv | csvcut -c class_id,name,total_score > high_score_students.csv
该命令筛选出总分在260-299之间的学生,并只保留班级ID、姓名和总分三列,结果保存到 high_score_students.csv。
接下来,我们使用 csvkit 的 Python API 读取统计结果,生成一份更详细的文本报告。
from agate import Table
# 读取班级统计数据和高分学生数据
class_stats_table = Table.from_csv("class_stats.csv")
high_score_table = Table.from_csv("high_score_students.csv")
# 生成报告内容
report_content = []
report_content.append("学生成绩分析报告")
report_content.append("=" * 30)
# 1. 班级统计信息
report_content.append("\n一、各班级总分统计")
for row in class_stats_table.rows:
report_content.append(f"班级 {row['class_id']}:")
report_content.append(f" 平均分:{row['avg_score']:.2f}")
report_content.append(f" 最高分:{row['max_score']}")
# 2. 高分学生统计
report_content.append("\n二、总分超过260分的学生名单")
report_content.append(f"总计:{len(high_score_table.rows)} 人")
for row in high_score_table.rows:
report_content.append(f" 班级 {row['class_id']} - {row['name']}:{row['total_score']} 分")
# 3. 计算全校平均分
all_scores_table = Table.from_csv("class_scores.csv")
school_avg = all_scores_table.columns["total_score"].aggregate(all_scores_table.aggregators.Mean())
report_content.append("\n三、全校总分平均分")
report_content.append(f" {school_avg:.2f} 分")
# 将报告写入文件
with open("score_analysis_report.txt", "w", encoding="utf-8") as f:
f.write("\n".join(report_content))
print("分析报告已生成:score_analysis_report.txt")
代码说明
class_stats.csv 和 high_score_students.csv 文件;score_analysis_report.txt 文件。生成的 score_analysis_report.txt 文件内容如下:
学生成绩分析报告
==============================
一、各班级总分统计
班级 1:
平均分:262.67
最高分:270
班级 2:
平均分:261.67
最高分:281
班级 3:
平均分:269.67
最高分:289
二、总分超过260分的学生名单
总计:6 人
班级 1 - Alice:265 分
班级 1 - Charlie:270 分
班级 2 - Diana:281 分
班级 2 - Ella:267 分
班级 3 - Grace:289 分
班级 3 - Ivy:270 分
三、全校总分平均分
264.67 分
关注我,每天分享一个实用的Python自动化工具。

smart-open是一款Python文件操作增强库,核心用途是统一本地文件、压缩文件和各类云端存储文件的读写接口,让开发者无需关注底层存储差异,用一致的代码操作不同来源的文件。其工作原理是基于URL范式识别文件存储位置,自动适配对应的读写驱动,比如本地文件对应file://、AWS S3对应s3://、HDFS对应hdfs://等。

该库的优点显著:接口简洁兼容Python内置open()函数、支持主流云存储服务、无缝处理压缩文件(如.gz .bz2)、支持流式读写降低内存占用;缺点是部分云存储功能需要额外安装依赖库,且复杂场景下的错误排查成本略高。smart-open采用MIT开源许可证,允许自由使用、修改和分发,无商业使用限制。
smart-open的安装分为基础版和全功能版,基础版仅支持本地文件和部分常见存储,全功能版则包含所有云存储和压缩格式的依赖。
打开命令行终端,执行以下pip安装命令:
pip install smart-open
此命令安装的是基础版本,支持本地文件、HTTP/HTTPS链接文件和简单的压缩文件读写。
如果需要操作AWS S3、Google Cloud Storage(GCS)、Azure Blob Storage等云存储服务,需要安装全量依赖,执行命令:
pip install "smart-open[all]"
若只需要特定云存储的支持,可以按需安装对应的依赖包,例如仅安装AWS S3支持:
pip install "smart-open[s3]"
常见的按需安装参数如下:
[s3]:AWS S3存储支持[gcs]:Google Cloud Storage支持[azure]:Azure Blob Storage支持[hdfs]:HDFS分布式文件系统支持安装完成后,在Python脚本中导入库,验证是否安装成功:
import smart_open
print(f"smart-open版本:{smart_open.__version__}")
运行脚本,若输出对应的版本号(如6.4.0),则说明安装成功。
smart-open的核心函数是smart_open.open(),其接口设计与Python内置的open()函数高度一致,开发者几乎无需额外学习成本,只需将文件路径替换为对应的URL格式即可。
本地文件操作是最基础的功能,smart_open.open()可以完全替代内置open()函数,语法和用法保持一致。
假设本地有一个名为example.txt的文本文件,内容为:
Hello, smart-open!
This is a local text file.
使用smart-open读取该文件的代码如下:
from smart_open import open
# 读取本地文本文件
with open("example.txt", mode="r", encoding="utf-8") as f:
content = f.read()
print("文件内容:")
print(content)
代码说明:
mode="r"表示只读模式,与内置open()函数一致;encoding="utf-8"指定文件编码,避免中文乱码;with语句可以自动关闭文件,无需手动调用f.close()。运行代码后,控制台会输出文件的全部内容。
向本地文件写入内容的代码示例:
from smart_open import open
# 写入本地文本文件
with open("output.txt", mode="w", encoding="utf-8") as f:
f.write("这是使用smart-open写入的内容\n")
f.write("支持多行文本写入\n")
代码说明:
mode="w"表示写入模式,如果文件不存在则创建,如果文件已存在则覆盖原有内容;mode改为"a"。运行代码后,本地会生成一个output.txt文件,包含写入的两行内容。
smart-open支持直接读写压缩文件,无需手动解压,目前支持.gz、.bz2、.xz等常见压缩格式。
读取.gz压缩文件:
假设本地有一个data.gz压缩文件,内部包含一个文本文件,读取代码如下:
from smart_open import open
# 读取.gz压缩文件
with open("data.gz", mode="r", encoding="utf-8") as f:
compressed_content = f.read()
print("压缩文件内容:")
print(compressed_content)
代码说明:smart-open会自动识别.gz后缀,使用对应的解压驱动读取文件内容,开发者无需额外处理解压逻辑。
写入.gz压缩文件:
将内容直接写入压缩文件,减少磁盘占用:
from smart_open import open
# 写入.gz压缩文件
with open("compressed_output.gz", mode="w", encoding="utf-8") as f:
f.write("这是写入压缩文件的内容\n")
f.write("压缩后可以节省磁盘空间")
运行代码后,本地会生成compressed_output.gz文件,使用解压软件打开后可查看写入的内容。
smart-open支持直接通过HTTP/HTTPS链接读取网络上的文件,无需先下载到本地,节省存储空间和传输时间。
例如读取一个公开的网络文本文件,代码示例:
from smart_open import open
# 读取HTTP链接的文本文件
url = "https://example.com/sample.txt"
with open(url, mode="r", encoding="utf-8") as f:
web_content = f.read()
print("网络文件内容:")
print(web_content)
代码说明:
同样支持直接读取网络上的压缩文件,例如读取.gz格式的网络压缩文件:
from smart_open import open
# 读取HTTPS链接的.gz压缩文件
compressed_url = "https://example.com/data_sample.gz"
with open(compressed_url, mode="r", encoding="utf-8") as f:
web_compressed_content = f.read()
print("网络压缩文件内容:")
print(web_compressed_content)
该代码无需手动下载和解压,直接读取压缩文件的文本内容,极大简化了网络文件处理流程。
smart-open的核心优势之一是对云存储的支持,下面以AWS S3为例,演示如何读写S3存储桶中的文件。注意:使用前需要配置AWS认证信息,可通过环境变量、~/.aws/credentials文件等方式配置。
假设AWS S3中有一个存储桶my-bucket,桶内有一个文件s3-example.txt,读取代码如下:
from smart_open import open
# 读取AWS S3存储桶中的文件
s3_path = "s3://my-bucket/s3-example.txt"
with open(s3_path, mode="r", encoding="utf-8") as f:
s3_content = f.read()
print("S3文件内容:")
print(s3_content)
代码说明:
s3://<bucket-name>/<file-path>;向S3存储桶写入文件的代码示例:
from smart_open import open
# 写入AWS S3存储桶
s3_write_path = "s3://my-bucket/output-s3.txt"
with open(s3_write_path, mode="w", encoding="utf-8") as f:
f.write("这是写入S3存储桶的内容\n")
f.write("使用smart-open简化云存储操作")
运行代码后,登录AWS控制台,即可在my-bucket存储桶中看到output-s3.txt文件,包含写入的内容。
对于其他云存储服务(如GCS、Azure Blob),使用方法类似,只需将文件路径替换为对应的URL格式:
gs://<bucket-name>/<file-path>azure://<container-name>/<file-path>除了基础的文件读写,smart-open还支持一些高级功能,满足复杂的业务场景需求,例如流式读写大文件、自定义存储后端等。
当处理超大文件时,一次性读取全部内容会占用大量内存,导致程序崩溃。smart-open支持流式读写,逐行读取或写入文件,降低内存占用。
假设本地有一个large_file.txt,大小为10GB,逐行读取的代码如下:
from smart_open import open
# 流式读取大文件,逐行处理
large_file_path = "large_file.txt"
with open(large_file_path, mode="r", encoding="utf-8") as f:
line_number = 1
for line in f:
# 处理每一行内容,例如打印行号和行内容
print(f"第{line_number}行:{line.strip()}")
line_number += 1
代码说明:
for line in f的方式逐行读取文件,每次仅加载一行内容到内存;将大量数据逐行写入文件,同样采用流式方式:
from smart_open import open
# 流式写入大文件
large_output_path = "large_output.txt"
# 模拟大量数据
data_list = [f"这是第{i}行数据" for i in range(1, 1000001)]
with open(large_output_path, mode="w", encoding="utf-8") as f:
for data in data_list:
f.write(data + "\n")
代码说明:循环遍历数据列表,逐行写入文件,即使数据量达到百万级,也不会占用过多内存。
smart-open可以与Pandas、NumPy等数据处理库结合,直接读取云端或压缩文件中的数据,无需本地中转。
假设S3存储桶中有一个data.csv文件,直接读取为Pandas DataFrame的代码如下:
import pandas as pd
from smart_open import open
# 直接读取S3中的CSV文件到DataFrame
s3_csv_path = "s3://my-bucket/data.csv"
with open(s3_csv_path, mode="r") as f:
df = pd.read_csv(f)
print("DataFrame前5行:")
print(df.head())
代码说明:
read_csv()函数的输入;读取网络上的JSON文件,并转换为Python字典:
import json
from smart_open import open
# 读取网络JSON文件
json_url = "https://example.com/data.json"
with open(json_url, mode="r") as f:
json_data = json.load(f)
print("JSON数据解析结果:")
print(json_data)
该代码直接读取网络JSON文件并解析,适用于API数据获取、配置文件读取等场景。
对于一些特殊的存储服务或需要自定义认证的场景,smart-open支持通过参数传递配置信息,例如设置S3的访问密钥和区域:
from smart_open import open
# 自定义S3认证信息
s3_config = {
"client_kwargs": {
"aws_access_key_id": "your-access-key",
"aws_secret_access_key": "your-secret-key",
"region_name": "us-east-1"
}
}
s3_path = "s3://my-bucket/custom-config.txt"
with open(s3_path, mode="r", encoding="utf-8", transport_params=s3_config) as f:
content = f.read()
print(content)
代码说明:通过transport_params参数传递存储后端的配置信息,适用于没有配置默认认证的环境,如服务器、容器等。
下面通过两个实际的业务案例,展示smart-open在项目开发中的应用价值。
需求:分析存储在AWS S3中的压缩日志文件(.log.gz),统计每天的访问量。
实现步骤:
代码实现:
from smart_open import open
from collections import defaultdict
# 定义S3日志文件路径
s3_log_path = "s3://my-log-bucket/access.log.gz"
# 用于统计每天的访问量
access_count = defaultdict(int)
# 流式读取压缩日志文件
with open(s3_log_path, mode="r", encoding="utf-8") as f:
for line in f:
# 假设日志格式为:2024-01-01 10:00:00 GET /index.html
if line.strip():
date_str = line.split()[0]
access_count[date_str] += 1
# 输出统计结果
print("每日访问量统计:")
for date, count in sorted(access_count.items()):
print(f"{date}: {count}次")
案例说明:该案例无需将超大的压缩日志文件下载到本地,直接在云端流式读取和分析,极大降低了本地存储压力和数据传输成本,提升了分析效率。
需求:整合本地文件、网络文件和S3文件中的数据,合并为一个统一的CSV文件并上传到GCS。
实现步骤:
local_data.csv、网络https://example.com/web_data.csv和S3 s3://my-bucket/s3_data.csv的数据;代码实现:
import pandas as pd
from smart_open import open
# 定义各数据源路径
local_path = "local_data.csv"
web_path = "https://example.com/web_data.csv"
s3_path = "s3://my-bucket/s3_data.csv"
gcs_output_path = "gs://my-gcs-bucket/merged_data.csv"
# 读取本地数据
with open(local_path, mode="r") as f:
df_local = pd.read_csv(f)
# 读取网络数据
with open(web_path, mode="r") as f:
df_web = pd.read_csv(f)
# 读取S3数据
with open(s3_path, mode="r") as f:
df_s3 = pd.read_csv(f)
# 合并数据并去重
merged_df = pd.concat([df_local, df_web, df_s3]).drop_duplicates().reset_index(drop=True)
# 将合并后的数据写入GCS
with open(gcs_output_path, mode="w") as f:
merged_df.to_csv(f, index=False)
print("数据合并完成,已上传到GCS存储桶!")
print(f"合并后的数据总行数:{len(merged_df)}")
案例说明:该案例展示了smart-open对多源数据的统一处理能力,开发者无需关注不同数据源的读写差异,仅需通过不同的URL路径即可实现数据的读取和写入,极大简化了多源数据整合的开发流程。
关注我,每天分享一个实用的Python自动化工具。

gdown是一款轻量级的Python第三方库,其核心用途是便捷下载Google Drive上的文件与文件夹。日常工作学习中,当我们需要从Google Drive获取公开分享的数据集、代码包、文档等资源时,直接通过浏览器下载会受网络环境、文件大小等因素限制,而gdown可以通过简单的Python代码或命令行指令,突破这些限制,高效完成下载操作,广泛适用于数据分析、机器学习、项目开发等场景中资源获取的环节。

gdown的工作原理是解析Google Drive的分享链接,提取出文件的真实下载地址,然后借助Python的网络请求库(如requests)向该地址发送请求,最终将文件内容保存到本地。对于公开分享的Google Drive文件,其分享链接中包含唯一的文件ID,gdown通过解析该ID构建对应的API请求链接,再处理Google Drive返回的响应数据,实现文件的流式下载;对于文件夹的下载,gdown会先获取文件夹内的文件列表,再逐个进行下载并保持原有的目录结构。
优点
缺点
gdown采用的是 MIT License,这是一种宽松的开源许可证。用户可以自由地使用、复制、修改、合并、出版发行、散布、再授权及贩售该软件及其副本,且仅需在软件副本中保留版权声明和许可声明即可,非常适合商业和非商业项目使用。
在使用gdown库之前,我们需要先完成安装操作。gdown的安装方式非常简单,支持pip包管理器安装和源码安装两种方式,其中pip安装是最推荐的方式,适合绝大多数用户。
确保你的电脑上已经安装了Python环境和pip包管理器(Python 3.4及以上版本默认自带pip),然后打开命令行终端(Windows下是CMD或PowerShell,macOS和Linux下是Terminal),输入以下命令:
pip install gdown
等待命令执行完成,若终端输出类似“Successfully installed gdown-x.x.x”的提示,说明gdown库已经安装成功。
如果你的电脑上同时安装了Python 2和Python 3,为了避免版本冲突,建议使用pip3命令安装,命令如下:
pip3 install gdown
如果你需要使用gdown的最新开发版本,或者想要对源码进行修改,可以选择从GitHub上下载源码进行安装。具体步骤如下:
git clone https://github.com/wkentaro/gdown.git
cd gdown
pip install .
这种安装方式可以获取到最新的功能,但可能存在一些未经过充分测试的bug,适合有一定开发经验的进阶用户。
gdown库提供了两种使用方式:命令行使用和Python脚本调用。命令行使用适合快速下载单个文件,而Python脚本调用则适合集成到自动化项目中,实现更复杂的下载逻辑。下面我们分别对这两种方式进行详细讲解,并配合实例代码进行演示。
gdown的命令行使用语法非常简洁,核心语法格式如下:
gdown [OPTIONS] URL_OR_ID
其中,URL_OR_ID表示Google Drive文件的分享链接或文件ID,OPTIONS是可选参数,用于设置下载路径、文件名等参数。
首先,我们需要获取Google Drive文件的分享链接。具体操作步骤:打开Google Drive,找到需要下载的文件,右键点击该文件,选择“分享”,然后将分享权限设置为“知道链接的人可查看”,最后复制生成的分享链接。
例如,我们有一个Google Drive文件的分享链接为:https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view?usp=sharing,其中1234567890abcdefghijklmnopqrstuvwxyz就是该文件的唯一ID。
示例1:通过分享链接下载文件
在命令行中输入以下命令,即可将文件下载到当前目录:
gdown https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view?usp=sharing
示例2:通过文件ID下载文件
我们也可以直接使用文件ID进行下载,这种方式可以省略链接解析的步骤,下载速度更快。命令如下:
gdown 1234567890abcdefghijklmnopqrstuvwxyz
默认情况下,gdown会将文件下载到当前工作目录,并使用文件在Google Drive上的原名称。如果我们需要将文件保存到指定路径,或者修改文件名,可以使用-O或--output参数。
示例:指定下载路径和文件名
将文件下载到./data目录下,并命名为dataset.csv,命令如下:
gdown https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view?usp=sharing -O ./data/dataset.csv
执行该命令后,文件会被保存到data文件夹中(如果data文件夹不存在,需要提前创建)。
gdown对大文件下载提供了良好的支持,无需额外配置参数,直接使用基础下载命令即可。例如,下载一个大小为10GB的数据集文件,命令如下:
gdown https://drive.google.com/file/d/0987654321zyxwvutsrqponmlkjihgfedcba/view?usp=sharing
在下载大文件时,gdown会自动采用流式下载的方式,分块获取文件内容,避免因内存不足导致下载失败。
对于需要将文件下载功能集成到自动化脚本中的场景,Python脚本调用gdown库是更优的选择。gdown库提供了简洁的API接口,方便我们在代码中实现灵活的下载逻辑。
gdown库的核心函数是gdown.download(),该函数接收文件链接或文件ID作为参数,实现文件下载。
示例1:通过链接下载文件
import gdown
# 定义Google Drive文件分享链接
url = "https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view?usp=sharing"
# 下载文件到当前目录
gdown.download(url, quiet=False)
代码说明:
import gdown:导入gdown库。url变量:存储Google Drive文件的分享链接。gdown.download():执行下载操作,参数quiet=False表示在终端输出下载进度信息,若设置为True则不输出任何信息。示例2:通过文件ID下载文件
import gdown
# 定义Google Drive文件ID
file_id = "1234567890abcdefghijklmnopqrstuvwxyz"
# 构建下载链接
url = f"https://drive.google.com/uc?id={file_id}"
# 下载文件并指定保存路径和文件名
output = "./downloads/sample_file.txt"
gdown.download(url, output, quiet=False)
代码说明:
file_id变量:存储文件的唯一ID,从分享链接中提取。url变量:通过文件ID构建标准的下载链接,格式为https://drive.google.com/uc?id={file_id}。output变量:指定文件的保存路径和文件名,若路径中的文件夹不存在,会抛出FileNotFoundError异常,需要提前创建文件夹。gdown库不仅支持下载单个文件,还支持下载Google Drive上的公开文件夹。下载文件夹需要使用gdown.download_folder()函数,该函数会自动获取文件夹内的所有文件,并保持原有的目录结构。
示例:下载Google Drive文件夹
import gdown
# 定义Google Drive文件夹分享链接
folder_url = "https://drive.google.com/drive/folders/1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q?usp=sharing"
# 指定下载后的保存路径
output_folder = "./dataset_folder"
# 下载文件夹
gdown.download_folder(folder_url, output=output_folder, quiet=False)
代码说明:
folder_url变量:存储Google Drive文件夹的分享链接,获取方式与文件分享链接类似,右键点击文件夹选择“分享”,复制链接即可。output_folder变量:指定文件夹下载后的保存路径,gdown会自动创建该文件夹(如果不存在)。gdown.download_folder():执行文件夹下载操作,下载完成后,output_folder目录下会包含与Google Drive文件夹相同结构的文件和子文件夹。在下载大文件时,可能会因为网络中断等原因导致下载失败。gdown库支持断点续传功能,通过设置resume=True参数,可以从上次中断的位置继续下载文件。
示例:断点续传下载大文件
import gdown
# 定义大文件的分享链接
large_file_url = "https://drive.google.com/file/d/0987654321zyxwvutsrqponmlkjihgfedcba/view?usp=sharing"
# 指定保存路径
output_path = "./large_files/big_dataset.zip"
# 启用断点续传功能下载文件
gdown.download(large_file_url, output_path, resume=True, quiet=False)
代码说明:
resume=True:启用断点续传功能,当文件已经下载了一部分时,再次执行该代码会从断点处继续下载,无需重新下载整个文件。在实际使用过程中,可能会遇到网络错误、文件不存在、权限不足等异常情况。我们可以通过try-except语句捕获这些异常,提高脚本的健壮性。
示例:异常处理的文件下载脚本
import gdown
from requests.exceptions import RequestException
def download_file_from_gdrive(url, output_path):
"""
从Google Drive下载文件,包含异常处理逻辑
:param url: Google Drive文件分享链接
:param output_path: 文件保存路径
"""
try:
gdown.download(url, output_path, quiet=False)
print(f"文件下载成功,保存路径:{output_path}")
except RequestException as e:
print(f"网络请求异常,下载失败:{e}")
except FileNotFoundError:
print(f"保存路径不存在,请检查路径是否正确:{output_path}")
except Exception as e:
print(f"未知错误,下载失败:{e}")
# 调用函数下载文件
if __name__ == "__main__":
file_url = "https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view?usp=sharing"
save_path = "./downloads/data.csv"
download_file_from_gdrive(file_url, save_path)
代码说明:
download_file_from_gdrive函数,封装文件下载和异常处理逻辑。try代码块:执行文件下载操作,并打印成功提示信息。except RequestException:捕获网络请求相关的异常,如网络中断、无法访问Google Drive等。except FileNotFoundError:捕获保存路径不存在的异常。except Exception:捕获其他未知异常,避免脚本崩溃。在数据分析和机器学习项目中,我们经常需要批量下载多个文件。下面我们通过一个案例,实现从Google Drive批量下载多个公开文件的功能。
案例需求
有一个文件列表,包含3个Google Drive文件的ID和对应的文件名,需要将这些文件批量下载到./batch_downloads目录下。
实现代码
import gdown
import os
# 定义文件列表:每个元素是一个元组,包含(file_id, file_name)
file_list = [
("1234567890abcdefghijklmnopqrstuvwxyz", "file1.csv"),
("0987654321zyxwvutsrqponmlkjihgfedcba", "file2.jpg"),
("abcdefghijklmnopqrstuvwxyz1234567890", "file3.txt")
]
# 定义保存目录
save_dir = "./batch_downloads"
# 创建保存目录(如果不存在)
if not os.path.exists(save_dir):
os.makedirs(save_dir)
# 批量下载文件
for file_id, file_name in file_list:
# 构建下载链接
url = f"https://drive.google.com/uc?id={file_id}"
# 构建保存路径
output_path = os.path.join(save_dir, file_name)
try:
print(f"正在下载文件:{file_name}")
gdown.download(url, output_path, quiet=False)
print(f"{file_name} 下载完成!")
except Exception as e:
print(f"{file_name} 下载失败:{e}")
代码说明:
file_list列表:存储需要下载的文件信息,每个元组包含文件ID和文件名。os.makedirs(save_dir):创建保存目录,os.path.exists(save_dir)用于判断目录是否存在,避免重复创建。file_list:逐个构建下载链接和保存路径,执行下载操作,并通过try-except捕获异常,确保单个文件下载失败不会影响其他文件的下载。在机器学习项目中,我们经常需要从Google Drive下载公开的数据集,然后进行数据预处理和模型训练。下面我们通过一个案例,将gdown库集成到机器学习数据集的下载和加载流程中。
案例需求
下载一个存储在Google Drive上的MNIST数据集压缩包(mnist.zip),解压后加载数据并进行简单的可视化。
实现代码
import gdown
import os
import zipfile
import numpy as np
import matplotlib.pyplot as plt
# 1. 定义数据集信息
file_id = "mnist_dataset_file_id_here"
url = f"https://drive.google.com/uc?id={file_id}"
zip_path = "./mnist_dataset/mnist.zip"
extract_path = "./mnist_dataset"
# 2. 创建数据集目录
if not os.path.exists(extract_path):
os.makedirs(extract_path)
# 3. 下载数据集压缩包
if not os.path.exists(zip_path):
print("正在下载MNIST数据集...")
gdown.download(url, zip_path, quiet=False)
print("数据集下载完成!")
else:
print("数据集压缩包已存在,跳过下载步骤")
# 4. 解压数据集
if not os.path.exists(os.path.join(extract_path, "train")):
print("正在解压数据集...")
with zipfile.ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(extract_path)
print("数据集解压完成!")
else:
print("数据集已解压,跳过解压步骤")
# 5. 加载并可视化数据(假设解压后的数据格式为npy文件)
train_images = np.load(os.path.join(extract_path, "train", "train_images.npy"))
train_labels = np.load(os.path.join(extract_path, "train", "train_labels.npy"))
# 可视化前5张训练图像
plt.figure(figsize=(10, 5))
for i in range(5):
plt.subplot(1, 5, i + 1)
plt.imshow(train_images[i], cmap="gray")
plt.title(f"Label: {train_labels[i]}")
plt.axis("off")
plt.show()
代码说明:
zipfile库进行解压。matplotlib库可视化前5张训练图像,帮助我们快速了解数据集的内容。现象:执行下载命令后,终端提示“ConnectionError: HTTPSConnectionPool”或“TimeoutError”。
解决方法:
import os
import gdown
# 设置代理环境变量
os.environ["HTTP_PROXY"] = "http://your_proxy_address:port"
os.environ["HTTPS_PROXY"] = "https://your_proxy_address:port"
# 执行下载操作
url = "https://drive.google.com/file/d/1234567890abcdefghijklmnopqrstuvwxyz/view?usp=sharing"
gdown.download(url, quiet=False)
现象:终端提示“Permission denied”或“File not found”,但文件链接是正确的。
解决方法:
现象:下载文件夹后,发现部分文件没有被下载,或者目录结构混乱。
解决方法:
pip install --upgrade gdown进行升级。关注我,每天分享一个实用的Python自动化工具。

python-magic 是一款基于 libmagic 库封装的 Python 工具库,其核心功能是通过文件内容而非扩展名来识别文件的真实类型。在日常开发中,我们经常会遇到文件扩展名被篡改、后缀名丢失的场景,比如下载的压缩包被恶意修改为 .txt 后缀,或者老旧文件的扩展名损坏,此时 python-magic 就能通过解析文件的二进制特征码,准确判断出文件的真实格式,广泛应用于文件校验、爬虫数据处理、系统安全检测等领域。

python-magic 的底层依赖于 Unix/Linux 系统中的 libmagic 库(Windows 系统需手动安装对应依赖),该库内置了一个魔法数字数据库,这个数据库中存储了各种文件格式对应的二进制特征值。当 python-magic 处理文件时,会读取文件头部的若干字节数据,将其与魔法数字数据库中的特征值进行匹配,从而判定文件的真实类型。整个过程无需解析文件完整内容,因此执行效率高,且不受文件扩展名的干扰。
优点
缺点
libmagic 依赖包,相比纯 Python 库安装步骤稍复杂。python-magic 采用的是 MIT License,这是一种宽松的开源许可证。用户可以自由地使用、复制、修改、分发该库的源代码,无论是个人项目还是商业项目,都无需支付任何费用,只需在分发的软件中保留原作者的版权声明即可。
python-magic 依赖系统底层的 libmagic 库,不同操作系统的安装方式有所不同,具体步骤如下:
bash sudo apt-get update sudo apt-get install libmagic1bash sudo yum install file-develbash brew install libmagiclibmagic 依赖文件:
file-5.39-bin.zip、file-5.39-dep.zip 两个压缩包。bin 目录下的 libmagic-1.dll、magic.exe 文件复制到 Python 的安装目录下的 Scripts 文件夹中。share 目录下的 magic 文件夹复制到 Python 安装目录的根目录下。在完成系统依赖安装后,通过 pip 命令即可安装 python-magic 库,执行以下命令:
pip install python-magic
安装完成后,可以在 Python 交互环境中执行以下代码验证是否安装成功:
import magic
print(magic.__version__)
如果没有报错,并且输出了对应的版本号(如 0.4.27),则说明安装成功。
python-magic 提供了两种核心使用方式:一种是直接调用函数式 API,另一种是创建 Magic 类实例进行自定义配置。下面我们分别介绍这两种方式的使用方法,并结合实例代码进行演示。
函数式 API 封装了最常用的文件类型检测功能,适合快速开发场景,核心函数包括 detect_from_filename、detect_from_content、detect_from_fobj。
detect_from_filename:通过文件名检测文件类型该函数接收一个文件路径作为参数,返回一个包含文件类型信息的字典,字典中包含 mime_type(MIME 类型)和 encoding(编码格式,仅文本文件有该字段)两个键。
实例代码
import magic
# 定义测试文件路径(替换为你自己的文件路径)
test_file_path = "test.jpg"
# 检测文件类型
result = magic.detect_from_filename(test_file_path)
# 输出检测结果
print(f"文件 MIME 类型: {result.mime_type}")
print(f"文件编码格式: {result.encoding}")
代码说明
magic 库,然后定义需要检测的文件路径。detect_from_filename 函数,传入文件路径,该函数会自动读取文件内容并进行类型检测。encoding 字段通常为 None;对于文本文件(如 .txt),会返回具体的编码格式(如 utf-8、gbk 等)。运行结果示例
文件 MIME 类型: image/jpeg
文件编码格式: None
detect_from_content:通过文件内容检测文件类型在某些场景下,我们可能没有完整的文件,只有文件的二进制内容(如网络请求中获取的文件流),此时可以使用 detect_from_content 函数,直接传入二进制数据进行检测。
实例代码
import magic
# 读取文件的二进制内容
with open("test.txt", "rb") as f:
file_content = f.read()
# 通过二进制内容检测文件类型
result = magic.detect_from_content(file_content)
# 输出检测结果
print(f"文件 MIME 类型: {result.mime_type}")
print(f"文件编码格式: {result.encoding}")
代码说明
rb 模式打开文本文件,读取其二进制内容并存储到 file_content 变量中。detect_from_content 函数,传入二进制内容,函数会根据内容特征判断文件类型。mime_type 为 text/plain,encoding 为 utf-8。运行结果示例
文件 MIME 类型: text/plain
文件编码格式: utf-8
detect_from_fobj:通过文件对象检测文件类型如果已经打开了一个文件对象,不需要再次读取文件内容,直接使用 detect_from_fobj 函数传入文件对象即可完成检测,这种方式适合处理大文件,避免重复读取数据。
实例代码
import magic
# 打开文件对象
with open("test.zip", "rb") as f:
# 通过文件对象检测文件类型
result = magic.detect_from_fobj(f)
# 输出检测结果
print(f"文件 MIME 类型: {result.mime_type}")
print(f"文件编码格式: {result.encoding}")
代码说明
rb 模式打开压缩包文件,得到文件对象 f。detect_from_fobj 函数,传入文件对象,函数会从文件头部读取特征字节进行检测。application/zip,编码格式为 None。运行结果示例
文件 MIME 类型: application/zip
文件编码格式: None
Magic 类实例化使用函数式 API 虽然方便,但可配置性较低。如果需要自定义检测规则(如只检测 MIME 类型、显示详细的文件描述信息等),可以通过实例化 Magic 类来实现。Magic 类的构造函数支持多个参数,常用参数如下:
mime:布尔值,设置为 True 时,仅返回 MIME 类型;默认为 False,返回详细的文件描述信息。mime_encoding:布尔值,设置为 True 时,返回 MIME 类型和编码格式;默认为 False。keep_going:布尔值,设置为 True 时,会输出所有匹配到的文件类型信息;默认为 False,仅输出第一个匹配结果。uncompress:布尔值,设置为 True 时,会自动解压压缩文件后再进行检测;默认为 False。通过设置 mime=True,可以让 Magic 实例仅返回文件的 MIME 类型,适合需要标准化文件类型标识的场景。
实例代码
import magic
# 实例化 Magic 类,指定仅返回 MIME 类型
mime_magic = magic.Magic(mime=True)
# 检测图片文件的 MIME 类型
image_type = mime_magic.from_file("test.png")
print(f"PNG 图片 MIME 类型: {image_type}")
# 检测音频文件的 MIME 类型
audio_type = mime_magic.from_file("test.mp3")
print(f"MP3 音频 MIME 类型: {audio_type}")
代码说明
Magic 类时传入 mime=True 参数,创建一个专门用于检测 MIME 类型的实例 mime_magic。from_file 方法,传入文件路径,分别检测 PNG 图片和 MP3 音频文件的 MIME 类型。image/png,MP3 音频的 MIME 类型为 audio/mpeg。运行结果示例
PNG 图片 MIME 类型: image/png
MP3 音频 MIME 类型: audio/mpeg
默认情况下,Magic 实例会返回文件的详细描述信息,包括文件格式、版本等内容,适合需要向用户展示直观文件类型的场景。
实例代码
import magic
# 实例化 Magic 类,获取详细文件描述
detail_magic = magic.Magic()
# 检测不同类型文件的详细信息
txt_detail = detail_magic.from_file("test.txt")
pdf_detail = detail_magic.from_file("test.pdf")
exe_detail = detail_magic.from_file("test.exe")
# 输出详细信息
print(f"文本文件详细信息: {txt_detail}")
print(f"PDF 文件详细信息: {pdf_detail}")
print(f"EXE 程序详细信息: {exe_detail}")
代码说明
Magic 类时不传入任何参数,创建的 detail_magic 实例会返回详细的文件描述信息。from_file 方法检测文本文件、PDF 文件和 Windows 可执行文件的详细信息。PDF document 相关描述,EXE 文件会显示 PE32 executable 相关信息。运行结果示例
文本文件详细信息: UTF-8 Unicode text
PDF 文件详细信息: PDF document, version 1.5
EXE 程序详细信息: PE32 executable (GUI) Intel 80386, for MS Windows
通过设置 mime_encoding=True,可以让 Magic 实例同时返回文件的 MIME 类型和编码格式,这种方式比函数式 API 中的 detect_from_filename 更灵活,支持自定义其他参数。
实例代码
import magic
# 实例化 Magic 类,同时获取 MIME 类型和编码格式
mime_enc_magic = magic.Magic(mime_encoding=True)
# 检测文本文件和 CSV 文件
result1 = mime_enc_magic.from_file("test.txt")
result2 = mime_enc_magic.from_file("test.csv")
# 输出结果
print(f"文本文件 MIME 及编码: {result1}")
print(f"CSV 文件 MIME 及编码: {result2}")
代码说明
Magic 类时传入 mime_encoding=True 参数,创建的 mime_enc_magic 实例会返回 MIME 类型; 编码格式 的组合字符串。text/csv。运行结果示例
文本文件 MIME 及编码: text/plain; charset=utf-8
CSV 文件 MIME 及编码: text/csv; charset=utf-8
在实际开发中,经常会遇到文件扩展名被篡改的情况,比如将 .exe 病毒文件伪装成 .jpg 图片文件,此时使用 python-magic 可以轻松识别出文件的真实类型。
实例代码
import magic
# 假设存在一个伪装为图片的可执行文件 fake.jpg(实际是 exe 文件)
fake_file_path = "fake.jpg"
# 使用 Magic 类检测真实类型
real_magic = magic.Magic()
real_type = real_magic.from_file(fake_file_path)
# 使用 MIME 类型检测
mime_magic = magic.Magic(mime=True)
real_mime = mime_magic.from_file(fake_file_path)
# 输出检测结果
print(f"文件伪装扩展名: .jpg")
print(f"文件真实类型描述: {real_type}")
print(f"文件真实 MIME 类型: {real_mime}")
代码说明
fake.jpg,其实际是 Windows 可执行文件。real_magic 和返回 MIME 类型的 mime_magic 实例检测文件。application/x-dosexec,从而识破文件的伪装。运行结果示例
文件伪装扩展名: .jpg
文件真实类型描述: PE32 executable (GUI) Intel 80386, for MS Windows
文件真实 MIME 类型: application/x-dosexec
通过设置 uncompress=True,Magic 实例可以自动解压压缩文件(如 .gz、.bz2 等格式),并检测压缩包内文件的真实类型,适合处理压缩文件的场景。
实例代码
import magic
# 实例化 Magic 类,开启自动解压功能
uncompress_magic = magic.Magic(uncompress=True)
# 检测 gz 压缩包内的文件类型
gz_file_detail = uncompress_magic.from_file("test.txt.gz")
print(f"gz 压缩包内文件类型: {gz_file_detail}")
# 检测 bz2 压缩包内的文件类型
bz2_file_detail = uncompress_magic.from_file("test.csv.bz2")
print(f"bz2 压缩包内文件类型: {bz2_file_detail}")
代码说明
Magic 类时传入 uncompress=True 参数,开启自动解压功能。.gz 和 .bz2 格式的压缩包文件,uncompress_magic 会先解压压缩包,再检测内部文件的类型。.txt.gz 压缩包内的文件会显示为 UTF-8 编码的文本文件,.csv.bz2 压缩包内的文件会显示为 CSV 文本文件。运行结果示例
gz 压缩包内文件类型: UTF-8 Unicode text (gzip compressed data, was "test.txt", last modified: ...)
bz2 压缩包内文件类型: CSV text (bzip2 compressed data, block size = 900k)
在数据处理场景中,我们经常需要对一个文件夹内的所有文件进行类型检测,筛选出特定类型的文件。下面的案例实现了批量检测文件夹内所有文件的类型,并将结果保存到 CSV 文件中。
实例代码
import os
import csv
import magic
def batch_detect_file_type(folder_path, output_csv):
"""
批量检测文件夹内文件类型,并将结果保存到 CSV 文件
:param folder_path: 目标文件夹路径
:param output_csv: 输出 CSV 文件路径
"""
# 实例化 Magic 类,获取 MIME 类型和编码
mime_enc_magic = magic.Magic(mime_encoding=True)
# 准备 CSV 表头
headers = ["文件名", "文件路径", "MIME类型及编码"]
# 打开 CSV 文件并写入数据
with open(output_csv, "w", newline="", encoding="utf-8") as csv_file:
writer = csv.writer(csv_file)
writer.writerow(headers)
# 遍历文件夹内所有文件
for root, dirs, files in os.walk(folder_path):
for file_name in files:
# 获取文件完整路径
file_path = os.path.join(root, file_name)
try:
# 检测文件类型
file_type = mime_enc_magic.from_file(file_path)
# 写入 CSV 数据
writer.writerow([file_name, file_path, file_type])
print(f"已检测: {file_path} -> {file_type}")
except Exception as e:
# 捕获异常,处理无法检测的文件
print(f"检测失败: {file_path} -> 错误信息: {str(e)}")
writer.writerow([file_name, file_path, f"检测失败: {str(e)}"])
# 调用函数,批量检测 test_folder 文件夹内文件,并保存到 file_types.csv
if __name__ == "__main__":
target_folder = "test_folder"
output_file = "file_types.csv"
batch_detect_file_type(target_folder, output_file)
代码说明
batch_detect_file_type 函数,接收目标文件夹路径和输出 CSV 文件路径作为参数。Magic 类并开启 mime_encoding 模式,用于获取文件的 MIME 类型和编码格式。os.walk 遍历目标文件夹内的所有文件,获取每个文件的完整路径。from_file 方法检测文件类型,将文件名、文件路径和检测结果写入 CSV 文件。if __name__ == "__main__" 代码块中,指定目标文件夹和输出 CSV 文件路径,调用函数执行批量检测。运行效果
运行代码后,会在当前目录下生成 file_types.csv 文件,文件中包含了文件夹内所有文件的名称、路径和类型信息,方便后续数据分析和筛选。
在爬虫开发中,我们经常需要下载网络资源,但有时候会遇到链接返回的文件类型与预期不符的情况(如预期下载图片,实际下载的是 HTML 错误页面)。下面的案例结合 requests 库和 python-magic,实现爬虫数据的类型过滤,只保存符合预期类型的文件。
实例代码
import os
import requests
import magic
def download_file_by_type(url, save_folder, expected_mime):
"""
根据预期 MIME 类型下载文件,过滤不符合类型的资源
:param url: 文件下载链接
:param save_folder: 文件保存文件夹
:param expected_mime: 预期的 MIME 类型(如 image/jpeg、application/pdf 等)
"""
# 创建保存文件夹(如果不存在)
if not os.path.exists(save_folder):
os.makedirs(save_folder)
try:
# 发送 GET 请求,获取文件二进制内容
response = requests.get(url, stream=True)
response.raise_for_status() # 抛出 HTTP 错误异常
# 读取文件二进制内容(读取前 1024 字节即可满足类型检测需求)
file_content = response.raw.read(1024)
# 检测文件 MIME 类型
mime_magic = magic.Magic(mime=True)
file_mime = mime_magic.from_buffer(file_content)
# 判断是否符合预期 MIME 类型
if file_mime == expected_mime:
# 提取文件名
file_name = url.split("/")[-1]
save_path = os.path.join(save_folder, file_name)
# 完整下载文件并保存
with open(save_path, "wb") as f:
for chunk in response.iter_content(chunk_size=1024):
if chunk:
f.write(chunk)
print(f"成功下载符合预期的文件: {save_path} -> MIME 类型: {file_mime}")
else:
print(f"文件类型不符,跳过下载 -> 预期: {expected_mime}, 实际: {file_mime}")
except requests.exceptions.RequestException as e:
print(f"下载失败: {url} -> 错误信息: {str(e)}")
# 调用函数,下载预期为 JPG 图片的资源
if __name__ == "__main__":
# 测试链接(替换为实际的下载链接)
test_urls = [
"https://example.com/valid_image.jpg",
"https://example.com/fake_image.html"
]
save_dir = "downloaded_images"
expected_mime_type = "image/jpeg"
for url in test_urls:
download_file_by_type(url, save_dir, expected_mime_type)
代码说明
download_file_by_type 函数,接收下载链接、保存文件夹和预期 MIME 类型作为参数。requests.get 方法发送请求,开启流式传输模式(stream=True)。Magic 类并开启 mime 模式,检测读取到的二进制内容的 MIME 类型。requests 库的请求异常(如网络错误、HTTP 404 错误等),并输出错误信息。if __name__ == "__main__" 代码块中,定义测试链接列表、保存目录和预期 MIME 类型,遍历链接并调用函数进行下载。运行效果
运行代码后,只有 MIME 类型为 image/jpeg 的文件会被下载并保存到 downloaded_images 文件夹中,不符合预期类型的资源会被跳过,有效过滤了无效数据。
关注我,每天分享一个实用的Python自动化工具。

xmltodict是一款轻量级的Python库,核心功能是实现XML字符串与Python字典(dict)之间的双向转换,同时支持将Python字典反向生成为XML格式数据。借助该库,开发者无需编写复杂的XML解析代码(如DOM、SAX解析逻辑),就能像操作普通字典一样处理XML数据,极大降低了XML数据处理的门槛,广泛应用于接口数据解析、配置文件读取、数据格式转换等场景。

xmltodict的底层基于Python内置的xml.parsers.expat解析器,采用事件驱动的解析方式处理XML数据。在解析XML时,它会遍历XML文档的各个节点(元素、属性、文本),将XML元素标签映射为字典的键,元素属性以@前缀标识的键存储,元素内的文本内容则存储在#text键中;反向生成XML时,会根据字典的键值结构,按照XML的语法规则拼接成对应的XML字符串。
优点
缺点
xmltodict采用MIT License开源许可证,这意味着开发者可以自由地使用、复制、修改、合并、出版发行、散布、授权和/或销售该软件的副本,同时也可以将软件嵌入到其他商业软件中,只需保留原作者的版权声明即可。
xmltodict是Python第三方库,可通过pip包管理工具一键安装,支持Python 2.7和Python 3.x版本,安装命令如下:
pip install xmltodict
安装完成后,可在Python交互式环境中执行以下代码验证是否安装成功:
import xmltodict
print(xmltodict.__version__)
若输出类似0.13.0的版本号,则说明安装成功。
xml.parsers.expatxmltodict的核心功能由两个函数实现,分别是parse()和unparse(),具体说明如下:
| 函数名 | 功能描述 | 常用参数 |
|–|-|-|
| xmltodict.parse(xml_input, **kwargs) | 将XML字符串或文件对象解析为Python字典 | xml_input:XML字符串/文件对象;encoding:编码格式,默认utf-8;process_namespaces:是否处理命名空间,默认False;attr_prefix:属性键前缀,默认@;cdata_key:CDATA段键名,默认#text |
| xmltodict.unparse(dict_input, **kwargs) | 将Python字典反向生成为XML字符串 | dict_input:待转换的Python字典;encoding:编码格式,默认utf-8;pretty:是否格式化输出,默认False;indent:格式化缩进字符,默认(两个空格) |
本案例演示如何将一个简单的XML字符串解析为Python字典,并通过键值对访问XML中的数据。
# 导入xmltodict库
import xmltodict
# 定义一个简单的XML字符串
xml_str = """
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
"""
# 将XML字符串解析为Python字典
dict_data = xmltodict.parse(xml_str)
# 打印转换后的字典
print("转换后的字典结构:")
print(dict_data)
print("\n")
# 访问字典中的数据
# 1. 获取第一个book的分类
first_book_category = dict_data["bookstore"]["book"][0]["@category"]
print("第一本书的分类:", first_book_category)
# 2. 获取第二本书的标题
second_book_title = dict_data["bookstore"]["book"][1]["title"]
print("第二本书的标题:", second_book_title)
# 3. 获取第一本书的价格
first_book_price = dict_data["bookstore"]["book"][0]["price"]
print("第一本书的价格:", first_book_price)
代码说明
xmltodict库,定义一个包含两本图书信息的XML字符串,其中<book>标签包含category属性,子标签包括title、author等。xmltodict.parse()函数将XML字符串转换为字典,XML的根节点bookstore成为字典的顶层键,子节点book则以列表形式存储(因为存在多个<book>元素)。@属性名的形式作为字典的键,例如@category对应<book>标签的category属性。dict_data["bookstore"]["book"][0]对应第一本图书的所有信息。运行结果
转换后的字典结构:
{'bookstore': {'book': [{'@category': 'COOKING', 'title': {'@lang': 'en', '#text': 'Everyday Italian'}, 'author': 'Giada De Laurentiis', 'year': '2005', 'price': '30.00'}, {'@category': 'CHILDREN', 'title': {'@lang': 'en', '#text': 'Harry Potter'}, 'author': 'J K. Rowling', 'year': '2005', 'price': '29.99'}]}}
第一本书的分类: COOKING
第二本书的标题: {'@lang': 'en', '#text': 'Harry Potter'}
第一本书的价格: 30.00
本案例演示如何将Python字典反向转换为XML字符串,并通过参数控制XML的格式化输出。
import xmltodict
# 定义一个Python字典,模拟图书信息
book_dict = {
"bookstore": {
"book": [
{
"@category": "COOKING",
"title": {
"@lang": "en",
"#text": "Everyday Italian"
},
"author": "Giada De Laurentiis",
"year": "2005",
"price": "30.00"
},
{
"@category": "CHILDREN",
"title": {
"@lang": "en",
"#text": "Harry Potter"
},
"author": "J K. Rowling",
"year": "2005",
"price": "29.99"
}
]
}
}
# 将字典转换为XML字符串(无格式化)
xml_str_no_pretty = xmltodict.unparse(book_dict)
print("无格式化的XML字符串:")
print(xml_str_no_pretty)
print("\n")
# 将字典转换为XML字符串(带格式化,缩进为4个空格)
xml_str_pretty = xmltodict.unparse(book_dict, pretty=True, indent=" ")
print("格式化后的XML字符串:")
print(xml_str_pretty)
代码说明
@属性名作为键,文本内容以#text作为键,这是xmltodict识别属性和文本的约定。xmltodict.unparse()函数将字典转换为XML字符串,默认情况下(pretty=False)生成的XML是紧凑格式,无换行和缩进。pretty=True时,生成的XML会自动换行和缩进,indent参数可指定缩进的字符(如4个空格),提升XML的可读性。运行结果
无格式化的XML字符串:
<?xml version="1.0" encoding="utf-8"?><bookstore><book category="COOKING"><title lang="en">Everyday Italian</title><author>Giada De Laurentiis</author><year>2005</year><price>30.00</price></book><book category="CHILDREN"><title lang="en">Harry Potter</title><author>J K. Rowling</author><year>2005</year><price>29.99</price></book></bookstore>
格式化后的XML字符串:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
</bookstore>
在实际开发中,XML数据常以文件形式存储,本案例演示如何读取本地XML文件并解析为字典。
首先创建一个名为books.xml的文件,内容如下:
<?xml version="1.0" encoding="utf-8"?>
<bookstore>
<book category="BUSINESS">
<title lang="en">XML Developer's Guide</title>
<author>Robert Richards</author>
<year>2002</year>
<price>44.95</price>
</book>
<book category="TECHNOLOGY">
<title lang="en">Python Crash Course</title>
<author>Eric Matthes</author>
<year>2019</year>
<price>29.95</price>
</book>
</bookstore>
然后编写Python代码读取并解析该文件:
import xmltodict
# 打开XML文件并解析为字典
with open("books.xml", "r", encoding="utf-8") as f:
# 直接将文件对象传入parse函数
dict_data = xmltodict.parse(f)
# 遍历所有图书信息并打印
print("图书列表:")
for book in dict_data["bookstore"]["book"]:
print(f"分类:{book['@category']}")
print(f"标题:{book['title']['#text']}")
print(f"语言:{book['title']['@lang']}")
print(f"作者:{book['author']}")
print(f"年份:{book['year']}")
print(f"价格:{book['price']}")
print("-" * 20)
代码说明
with open()语句以只读模式打开books.xml文件,指定编码为utf-8,避免中文乱码。xmltodict.parse()函数支持直接传入文件对象,无需手动读取文件内容,简化了代码流程。dict_data["bookstore"]["book"]列表,可逐个获取每本图书的属性和子节点数据,并格式化输出。运行结果
图书列表:
分类:BUSINESS
标题:XML Developer's Guide
语言:en
作者:Robert Richards
年份:2002
价格:44.95
--
分类:TECHNOLOGY
标题:Python Crash Course
语言:en
作者:Eric Matthes
年份:2019
价格:29.95
--
在复杂的XML文档中,命名空间(Namespace)是常见的元素,用于避免标签名冲突。xmltodict支持通过process_namespaces参数处理命名空间,本案例演示如何解析带命名空间的XML。
import xmltodict
# 定义带命名空间的XML字符串
xml_with_ns = """
<root xmlns:ns="http://example.com/ns">
<ns:user id="1001">
<ns:name>Alice</ns:name>
<ns:age>25</ns:age>
</ns:user>
<ns:user id="1002">
<ns:name>Bob</ns:name>
<ns:age>30</ns:age>
</ns:user>
</root>
"""
# 不处理命名空间的情况
dict_no_ns = xmltodict.parse(xml_with_ns)
print("不处理命名空间的结果:")
print(dict_no_ns)
print("\n")
# 处理命名空间的情况(process_namespaces=True)
dict_with_ns = xmltodict.parse(xml_with_ns, process_namespaces=True)
print("处理命名空间的结果:")
print(dict_with_ns)
print("\n")
# 自定义命名空间前缀映射
namespace_map = {"http://example.com/ns": "user"}
dict_custom_ns = xmltodict.parse(
xml_with_ns,
process_namespaces=True,
namespaces=namespace_map
)
print("自定义命名空间前缀的结果:")
print(dict_custom_ns)
代码说明
xmlns:ns="http://example.com/ns",所有子标签均以ns:为前缀。process_namespaces=False(默认值)时,解析后的字典键会保留命名空间前缀(如ns:user)。process_namespaces=True时,xmltodict会自动移除命名空间前缀,直接使用标签名作为键。namespaces参数可传入自定义的命名空间映射字典,将命名空间URI映射为更简洁的前缀,方便数据访问。运行结果
不处理命名空间的结果:
{'root': {'@xmlns:ns': 'http://example.com/ns', 'ns:user': [{'@id': '1001', 'ns:name': 'Alice', 'ns:age': '25'}, {'@id': '1002', 'ns:name': 'Bob', 'ns:age': '30'}]}}
处理命名空间的结果:
{'root': {'user': [{'@id': '1001', 'name': 'Alice', 'age': '25'}, {'@id': '1002', 'name': 'Bob', 'age': '30'}]}}
自定义命名空间前缀的结果:
{'root': {'user:user': [{'@id': '1001', 'user:name': 'Alice', 'user:age': '25'}, {'@id': '1002', 'user:name': 'Bob', 'user:age': '30'}]}}
XML中的CDATA段用于存储不需要转义的文本内容(如包含<、>、&等特殊字符的文本),xmltodict默认将CDATA段的内容存储在#text键中,本案例演示如何解析包含CDATA段的XML。
import xmltodict
# 定义包含CDATA段的XML字符串
xml_with_cdata = """
<article>
<title>Python & XML</title>
<content><![CDATA[这是一篇关于Python解析XML的文章,包含特殊字符:< > & " ']]></content>
</article>
"""
# 解析XML字符串
dict_data = xmltodict.parse(xml_with_cdata)
# 访问CDATA段内容
title = dict_data["article"]["title"]
content = dict_data["article"]["content"]["#text"]
print(f"文章标题:{title}")
print(f"文章内容:{content}")
# 反向生成包含CDATA的XML
article_dict = {
"article": {
"title": "Python & XML",
"content": {
"#cdata-section": "这是一篇关于Python解析XML的文章,包含特殊字符:< > & \" '"
}
}
}
xml_str = xmltodict.unparse(article_dict, pretty=True)
print("\n生成的包含CDATA的XML:")
print(xml_str)
代码说明
<content>标签包含CDATA段,存储了带有特殊字符的文本,这些字符无需转义。#text键中,可直接通过该键获取文本内容。#cdata-section键,对应的值会被包装为CDATA段。运行结果
文章标题:Python & XML
文章内容:这是一篇关于Python解析XML的文章,包含特殊字符:< > & " '
生成的包含CDATA的XML:
<?xml version="1.0" encoding="utf-8"?>
<article>
<title>Python & XML</title>
<content><![CDATA[这是一篇关于Python解析XML的文章,包含特殊字符:< > & " ']]></content>
</article>
xmltodict提供了多个自定义参数,可根据需求调整解析行为,本案例演示常用参数的使用方法。
import xmltodict
xml_str = """
<data>
<item id="1">A</item>
<item id="2">B</item>
</data>
"""
# 自定义属性前缀(将默认的@改为attr_)
dict_custom_attr = xmltodict.parse(xml_str, attr_prefix="attr_")
print("自定义属性前缀的结果:")
print(dict_custom_attr)
print("\n")
# 自定义文本键名(将默认的#text改为text)
dict_custom_text = xmltodict.parse(xml_str, cdata_key="text")
print("自定义文本键名的结果:")
print(dict_custom_text)
print("\n")
# 强制将单元素列表转换为列表(force_list参数)
# 当XML中只有一个<item>标签时,默认不会生成列表,force_list可强制生成列表
xml_single_item = """
<data>
<item id="1">A</item>
</data>
"""
# 默认解析
dict_default = xmltodict.parse(xml_single_item)
print("默认解析单元素的结果:")
print(type(dict_default["data"]["item"])) # 输出<class 'dict'>
# 强制生成列表
dict_force_list = xmltodict.parse(xml_single_item, force_list=["item"])
print("强制生成列表的结果:")
print(type(dict_force_list["data"]["item"])) # 输出<class 'list'>
代码说明
attr_prefix参数:用于修改属性键的前缀,默认是@,可改为其他字符串(如attr_),避免与普通键名冲突。cdata_key参数:用于修改文本内容的键名,默认是#text,可改为更简洁的名称(如text)。force_list参数:用于指定哪些标签需要强制生成列表,即使该标签在XML中只出现一次,避免后续遍历数据时出现类型错误。运行结果
自定义属性前缀的结果:
{'data': {'item': [{'attr_id': '1', '#text': 'A'}, {'attr_id': '2', '#text': 'B'}]}}
自定义文本键名的结果:
{'data': {'item': [{'@id': '1', 'text': 'A'}, {'@id': '2', 'text': 'B'}]}}
默认解析单元素的结果:
<class 'dict'>
强制生成列表的结果:
<class 'list'>
在实际开发中,很多第三方接口会返回XML格式的数据,本案例模拟一个天气查询接口,使用xmltodict解析接口返回的XML数据,并提取关键信息。
import xmltodict
# 模拟天气接口返回的XML数据
weather_xml = """
<weather_response>
<city>北京市</city>
<date>2024-05-20</date>
<temperature>
<max>28</max>
<min>18</min>
<unit>℃</unit>
</temperature>
<weather>晴转多云</weather>
<wind>
<direction>南风</direction>
<level>2-3级</level>
</wind>
</weather_response>
"""
# 解析XML数据
weather_dict = xmltodict.parse(weather_xml)
# 提取关键天气信息
city = weather_dict["weather_response"]["city"]
date = weather_dict["weather_response"]["date"]
max_temp = weather_dict["weather_response"]["temperature"]["max"]
min_temp = weather_dict["weather_response"]["temperature"]["min"]
unit = weather_dict["weather_response"]["temperature"]["unit"]
weather = weather_dict["weather_response"]["weather"]
wind_dir = weather_dict["weather_response"]["wind"]["direction"]
wind_level = weather_dict["weather_response"]["wind"]["level"]
# 格式化输出天气信息
weather_info = f"""
{date} {city}天气信息
天气状况:{weather}
温度范围:{min_temp}{unit} - {max_temp}{unit}
风向风力:{wind_dir} {wind_level}
"""
print(weather_info)
# 构造新的天气字典(仅保留核心信息)
simple_weather_dict = {
"simple_weather": {
"@city": city,
"@date": date,
"weather": weather,
"temp_range": f"{min_temp}{unit} - {max_temp}{unit}"
}
}
# 生成格式化的XML字符串
simple_weather_xml = xmltodict.unparse(simple_weather_dict, pretty=True, indent=" ")
print("生成的简化天气XML:")
print(simple_weather_xml)
代码说明
xmltodict.parse()解析XML数据后,通过键值索引提取所需信息,并格式化输出为用户友好的天气报告。xmltodict.unparse()生成新的XML字符串,用于数据存储或接口转发。运行结果
2024-05-20 北京市天气信息
天气状况:晴转多云
温度范围:18℃ - 28℃
风向风力:南风 2-3级
生成的简化天气XML:
<?xml version="1.0" encoding="utf-8"?>
<simple_weather city="北京市" date="2024-05-20">
<weather>晴转多云</weather>
<temp_range>18℃ - 28℃</temp_range>
</simple_weather>
关注我,每天分享一个实用的Python自动化工具。

xlwings是一款功能强大的Python库,其核心用途是实现Python与Excel之间的双向通信,用户可以通过Python脚本直接操控Excel的工作簿、工作表、单元格等元素,同时也能在Excel中调用Python函数。该库的工作原理是基于COM接口(Windows系统)和AppleScript(Mac系统)与Excel应用程序建立连接,从而实现对Excel的底层操作,无需依赖复杂的第三方插件。

xlwings的优点十分突出:支持.xlsx、.xls等多种Excel文件格式;可以保留Excel的宏、公式和格式;语法简洁易懂,贴近Excel的原生操作逻辑;支持在Excel中嵌入Python代码,实现自动化报表生成、数据清洗和分析等功能。缺点则是在非Windows和Mac系统(如Linux)上无法直接使用,因为其依赖于Excel应用程序的安装;在处理超大规模数据时,速度相较于pandas等库会稍慢一些。xlwings采用的是MIT开源许可证,用户可以自由地用于商业和非商业项目,无版权方面的限制。
对于技术小白来说,xlwings的安装过程非常简单,只需要使用Python的包管理工具pip即可完成。首先需要确保你的电脑上已经安装了Python环境(推荐Python 3.7及以上版本),并且已经配置好了pip的环境变量。
打开命令提示符(Windows)或终端(Mac),输入以下命令:
pip install xlwings
等待安装完成后,就可以在Python脚本中导入xlwings库进行使用了。
安装完成后,我们可以通过一个简单的Python脚本来验证xlwings是否安装成功。创建一个名为test_xlwings.py的文件,输入以下代码:
# 导入xlwings库
import xlwings as xw
# 打开一个新的Excel工作簿
wb = xw.Book()
# 获取工作簿中的第一个工作表
ws = wb.sheets[0]
# 在A1单元格中写入内容
ws.range('A1').value = 'Hello, xlwings!'
# 保存工作簿到指定路径
wb.save('test.xlsx')
# 关闭工作簿
wb.close()
print("xlwings安装成功,测试文件已生成!")
运行该脚本,如果没有报错,并且在脚本所在目录下生成了一个名为test.xlsx的Excel文件,打开后A1单元格显示“Hello, xlwings!”,则说明xlwings已经成功安装并可以正常使用。
xlwings的使用依赖于本地安装的Excel应用程序,Windows系统推荐使用Microsoft Excel 2010及以上版本,Mac系统推荐使用Microsoft Excel for Mac 2016及以上版本。不需要进行额外的配置,只需要确保Excel能够正常启动即可。
工作簿是Excel文件的核心载体,xlwings提供了多种方式来创建、打开和保存工作簿。
使用xw.Book()方法可以创建一个新的Excel工作簿,该方法会自动启动Excel应用程序(如果尚未启动)。
import xlwings as xw
# 创建新的工作簿
wb = xw.Book()
# 查看工作簿的名称
print("新建工作簿名称:", wb.name)
# 关闭工作簿
wb.close()
代码说明:xw.Book()创建的是一个临时的工作簿,默认名称为“Book1”“Book2”等,使用wb.name可以查看工作簿的名称,最后通过wb.close()关闭工作簿。
如果需要对已存在的Excel文件进行操作,可以使用xw.Book(file_path)方法,其中file_path是Excel文件的路径(绝对路径或相对路径)。
import xlwings as xw
# 打开已有的工作簿(相对路径,文件需在脚本所在目录)
wb = xw.Book('test.xlsx')
print("已打开工作簿名称:", wb.name)
# 关闭工作簿
wb.close()
# 使用绝对路径打开工作簿(示例路径,需根据实际情况修改)
# wb = xw.Book(r'C:\Users\Admin\Desktop\data.xlsx')
代码说明:使用相对路径时,Excel文件需要和Python脚本在同一个目录下;使用绝对路径时,需要在路径前加r,避免转义字符的影响。
对工作簿进行操作后,需要使用save()方法来保存修改,save()方法可以指定保存路径,如果不指定,则保存到原文件路径。
import xlwings as xw
wb = xw.Book()
ws = wb.sheets[0]
ws.range('A1').value = 'Python操作Excel'
# 保存到指定路径
wb.save('new_excel.xlsx')
wb.close()
代码说明:如果指定的保存路径中不存在该文件,save()方法会自动创建;如果已经存在,则会覆盖原文件。
工作表是工作簿中的子对象,一个工作簿可以包含多个工作表,xlwings提供了丰富的方法来对工作表进行添加、删除、重命名和选择等操作。
可以通过工作表的索引或名称来选择工作表,索引从0开始,对应Excel中的第一个工作表。
import xlwings as xw
wb = xw.Book('new_excel.xlsx')
# 通过索引选择第一个工作表
ws1 = wb.sheets[0]
print("通过索引选择的工作表名称:", ws1.name)
# 通过名称选择工作表(默认第一个工作表名称为Sheet1)
ws2 = wb.sheets['Sheet1']
print("通过名称选择的工作表名称:", ws2.name)
wb.close()
代码说明:新建的工作簿默认只有一个名为“Sheet1”的工作表,通过索引和名称两种方式都可以准确选择目标工作表。
使用wb.sheets.add()方法可以在工作簿中添加新的工作表,可以指定工作表的名称和位置。
import xlwings as xw
wb = xw.Book('new_excel.xlsx')
# 添加新的工作表,名称为"数据报表",位置在最后
new_ws = wb.sheets.add(name='数据报表')
print("新增工作表名称:", new_ws.name)
# 添加新的工作表,位置在第一个工作表之前
# new_ws2 = wb.sheets.add(name='汇总表', before=wb.sheets[0])
wb.save()
wb.close()
代码说明:name参数用于指定新工作表的名称,before参数用于指定新工作表插入的位置,after参数则可以指定插入到某个工作表之后。
使用ws.name属性可以修改工作表的名称,使用ws.delete()方法可以删除指定的工作表。
import xlwings as xw
wb = xw.Book('new_excel.xlsx')
ws = wb.sheets['数据报表']
# 重命名工作表
ws.name = '销售数据报表'
print("重命名后的工作表名称:", ws.name)
# 删除指定的工作表
# wb.sheets['销售数据报表'].delete()
wb.save()
wb.close()
代码说明:删除工作表时要格外小心,删除后无法撤销,建议在删除前进行数据备份。
单元格是Excel中存储数据的最小单位,xlwings提供了灵活的方式来对单元格进行读写、格式设置等操作,这也是xlwings最核心的功能之一。
可以通过单元格的地址(如A1、B2)、行和列的索引来选择单元格或单元格区域。
import xlwings as xw
wb = xw.Book('new_excel.xlsx')
ws = wb.sheets[0]
# 选择单个单元格(A1)
rng1 = ws.range('A1')
print("A1单元格的值:", rng1.value)
# 选择单元格区域(A1:C3)
rng2 = ws.range('A1:C3')
print("A1:C3区域的行数:", rng2.rows.count)
print("A1:C3区域的列数:", rng2.columns.count)
# 通过行和列索引选择单元格(第1行第1列,即A1)
rng3 = ws.range((1, 1))
print("第1行第1列单元格的值:", rng3.value)
# 通过行和列索引选择单元格区域(第1行第1列到第3行第3列,即A1:C3)
rng4 = ws.range((1, 1), (3, 3))
wb.close()
代码说明:使用range()方法选择单元格区域时,可以使用Excel的单元格地址格式,也可以使用元组的形式指定起始和结束位置,元组中的第一个元素是行号,第二个元素是列号。
读取单元格数据是xlwings的常用操作,无论是单个单元格还是单元格区域,都可以通过value属性来获取数据。
import xlwings as xw
# 先向Excel中写入测试数据,再进行读取
wb = xw.Book()
ws = wb.sheets[0]
# 向A1:C3区域写入数据
data = [
['姓名', '年龄', '性别'],
['张三', 25, '男'],
['李四', 28, '女']
]
ws.range('A1').value = data
# 读取单个单元格的值
name = ws.range('A2').value
print("A2单元格的值(姓名):", name)
# 读取整行数据(第2行)
row_data = ws.range('2:2').value
print("第2行数据:", row_data)
# 读取整列数据(第1列)
col_data = ws.range('A:A').value
# 过滤掉空值
col_data = [x for x in col_data if x is not None]
print("第1列数据:", col_data)
# 读取单元格区域的数据
range_data = ws.range('A1:C3').value
print("A1:C3区域的数据:")
for row in range_data:
print(row)
wb.close()
代码说明:读取单元格区域的数据时,会返回一个二维列表,其中每个子列表对应Excel中的一行数据;读取整行或整列数据时,会返回一个一维列表,包含该行或该列的所有非空值。
向单元格中写入数据同样通过value属性,xlwings支持写入单个值、列表、二维列表等多种数据类型。
import xlwings as xw
wb = xw.Book()
ws = wb.sheets[0]
# 写入单个值
ws.range('A1').value = '学生信息表'
# 合并单元格(A1:C1)
ws.range('A1:C1').api.merge()
# 写入一维列表(一行数据)
ws.range('A2').value = ['姓名', '年龄', '成绩']
# 写入二维列表(多行多列数据)
student_data = [
['王五', 22, 95],
['赵六', 23, 88],
['孙七', 21, 92]
]
ws.range('A3').value = student_data
# 写入字典数据(按列写入)
score_dict = {'语文': 90, '数学': 85, '英语': 93}
ws.range('E2').value = list(score_dict.keys())
ws.range('E3').value = list(score_dict.values())
wb.save('student_info.xlsx')
wb.close()
代码说明:写入一维列表时,xlwings会自动将列表中的元素按行写入单元格;写入二维列表时,会按多行多列的形式写入;写入字典数据时,可以将键和值分别写入不同的列。
xlwings还支持对单元格的格式进行设置,如字体大小、颜色、对齐方式、边框等,这些设置通过api属性调用Excel的底层接口实现。
import xlwings as xw
wb = xw.Book('student_info.xlsx')
ws = wb.sheets[0]
# 设置标题单元格格式(A1:C1)
title_rng = ws.range('A1:C1')
# 设置字体大小为16,加粗
title_rng.api.Font.Size = 16
title_rng.api.Font.Bold = True
# 设置背景颜色为浅蓝色
title_rng.api.Interior.Color = xw.utils.rgb_to_int((211, 223, 236))
# 设置水平居中对齐
title_rng.api.HorizontalAlignment = xw.constants.HAlign.xlHAlignCenter
# 设置表头单元格格式(A2:C2)
header_rng = ws.range('A2:C2')
header_rng.api.Font.Bold = True
header_rng.api.Interior.Color = xw.utils.rgb_to_int((226, 239, 218))
# 为数据区域添加边框(A3:C5)
data_rng = ws.range('A3:C5')
# 边框样式:细实线
border = xw.constants.BordersIndex.xlEdgeLeft
data_rng.api.Borders(border).LineStyle = xw.constants.LineStyle.xlContinuous
data_rng.api.Borders(xw.constants.BordersIndex.xlEdgeRight).LineStyle = xw.constants.LineStyle.xlContinuous
data_rng.api.Borders(xw.constants.BordersIndex.xlEdgeTop).LineStyle = xw.constants.LineStyle.xlContinuous
data_rng.api.Borders(xw.constants.BordersIndex.xlEdgeBottom).LineStyle = xw.constants.LineStyle.xlContinuous
wb.save()
wb.close()
代码说明:xw.utils.rgb_to_int()函数用于将RGB颜色值转换为Excel可以识别的整数;xw.constants模块中包含了Excel的各种常量,如对齐方式、边框样式等,方便用户进行格式设置。
在日常工作中,我们经常需要根据原始数据生成销售报表,使用xlwings可以实现这一过程的自动化,减少重复的手工操作。
假设我们有一份销售原始数据,包含销售日期、产品名称、销售额等信息,需要实现以下功能:
import xlwings as xw
import pandas as pd
# 1. 生成模拟销售数据(实际应用中可以从CSV、数据库读取)
sales_data = {
'销售日期': ['2024-01-01', '2024-01-01', '2024-01-02', '2024-01-02', '2024-01-03'],
'产品名称': ['产品A', '产品B', '产品A', '产品C', '产品B'],
'销售额': [1000, 1500, 1200, 800, 1600]
}
df = pd.DataFrame(sales_data)
# 按产品名称汇总销售额
summary_df = df.groupby('产品名称')['销售额'].sum().reset_index()
# 2. 使用xlwings创建销售报表
wb = xw.Book()
ws = wb.sheets[0]
ws.name = '销售汇总报表'
# 写入报表标题
ws.range('A1').value = '2024年1月产品销售汇总报表'
ws.range('A1').api.Font.Size = 18
ws.range('A1').api.Font.Bold = True
ws.range('A1:D1').api.merge()
ws.range('A1').api.HorizontalAlignment = xw.constants.HAlign.xlHAlignCenter
# 写入汇总数据
ws.range('A3').value = ['产品名称', '总销售额(元)']
ws.range('A4').value = summary_df.values
# 设置数据区域格式
header_rng = ws.range('A3:B3')
header_rng.api.Font.Bold = True
header_rng.api.Interior.Color = xw.utils.rgb_to_int((220, 220, 220))
data_rng = ws.range(f'A4:B{3 + len(summary_df)}')
data_rng.api.Borders.LineStyle = xw.constants.LineStyle.xlContinuous
# 3. 插入销售额柱状图
chart_range = ws.range(f'A3:B{3 + len(summary_df)}')
chart = ws.charts.add(left=ws.range('D3').left, top=ws.range('D3').top, width=400, height=300)
chart.set_source_data(chart_range)
chart.chart_type = xw.constants.ChartType.xlColumnClustered
chart.name = '产品销售额柱状图'
chart.api.ChartTitle.Text = '各产品销售额对比'
# 4. 保存报表
wb.save('2024年1月销售汇总报表.xlsx')
wb.close()
print("销售汇总报表已生成!")
代码说明:本案例结合了pandas库和xlwings库,pandas用于数据的汇总分析,xlwings用于Excel报表的生成和格式设置,同时还实现了图表的插入,让报表更加直观。
xlwings的一个特色功能是可以在Excel中直接调用Python函数,这对于需要在Excel中进行复杂计算的用户来说非常实用。
实现一个在Excel中计算两个数的乘积和求和的功能,具体步骤如下:
步骤1:编写Python函数脚本
创建一个名为excel_functions.py的文件,输入以下代码:
import xlwings as xw
@xw.func
def add_numbers(a, b):
"""计算两个数的和"""
return a + b
@xw.func
def multiply_numbers(a, b):
"""计算两个数的乘积"""
return a * b
代码说明:使用@xw.func装饰器可以将普通的Python函数转换为可以在Excel中调用的函数。
步骤2:在Excel中调用Python函数
excel_functions.py文件;=add_numbers(A1, B1)=multiply_numbers(A1, B1)步骤3:实现实时计算
如果修改A1或B1单元格中的数值,Excel会自动调用Python函数重新计算结果,实现数据的实时更新。
解决方案:
excel.exe /regserver进行注册;解决方案:
import xlwings as xw
app = xw.App(visible=False)
wb = app.books.open('data.xlsx')
# 进行数据处理
wb.save()
wb.close()
app.quit()
解决方案:
wb.close()和app.quit()方法关闭工作簿和Excel应用程序;关注我,每天分享一个实用的Python自动化工具。

Tablib是一款轻量级且功能强大的Python数据处理库,其核心用途是实现不同格式数据的无缝转换、导入与导出,同时支持数据的增删改查等基础操作。它的工作原理是构建一个Dataset核心对象,该对象可以像表格一样存储结构化数据,然后通过内置的序列化方法,将数据转换为CSV、JSON、YAML、Excel等多种格式,也能反向解析这些格式的数据生成Dataset。

Tablib的优点十分突出:API设计简洁直观,易于上手;支持的格式丰富,满足多场景数据交互需求;不依赖过多第三方库,运行轻量化。缺点则是对超大规模数据的处理性能一般,且高级数据筛选功能需要结合其他库实现。该库采用MIT开源许可证,用户可以自由地用于商业和非商业项目。
Tablib可以通过Python官方的包管理工具pip进行快速安装,对于技术小白来说,无需复杂的编译过程,只需要打开命令行终端,输入以下命令即可完成安装:
pip install tablib
默认安装的Tablib已经支持CSV、JSON、YAML等基础格式,但如果需要处理Excel(.xls和.xlsx)格式的数据,需要额外安装依赖库xlrd和openpyxl,输入以下命令完成扩展安装:
pip install tablib[xlsx]
这条命令会自动安装处理Excel格式所需的依赖,确保后续可以正常读写Excel文件。
安装完成后,我们可以通过一个简单的Python脚本验证是否安装成功,在本地创建一个test_install.py文件,输入以下代码:
import tablib
# 创建一个空的Dataset对象
data = tablib.Dataset()
# 打印Tablib的版本号
print(f"Tablib版本:{tablib.__version__}")
print("安装验证成功!")
运行该脚本,如果终端输出类似Tablib版本:3.5.0 安装验证成功!的内容,就说明Tablib已经成功安装到你的Python环境中。
Tablib的核心操作围绕Dataset对象展开,Dataset可以理解为一个内存中的表格数据集,支持行和列的灵活操作,接下来我们通过具体的代码示例来讲解基础用法。
创建Dataset对象有多种方式,包括空对象创建、基于列表数据创建、指定表头创建,以下是详细的代码示例:
import tablib
# 创建空的Dataset
empty_data = tablib.Dataset()
print("空Dataset对象:", empty_data)
print("Dataset的行数:", len(empty_data))
print("Dataset的列数:", empty_data.width)
代码说明:这段代码创建了一个空的Dataset对象,然后分别打印了对象本身、行数和列数。运行后会发现,空Dataset的行数为0,列数也为0。
import tablib
# 定义数据列表,每个子列表代表一行数据
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
# 创建Dataset并传入数据
data = tablib.Dataset(*data_rows)
print("基于列表的Dataset:")
print(data)
print("行数:", len(data))
print("列数:", data.width)
代码说明:这里我们定义了一个包含3行3列数据的列表,通过*解包参数传入Dataset构造函数,创建出包含数据的对象。运行后可以看到,数据以表格形式输出,行数为3,列数为3。
在实际应用中,我们通常需要给数据列指定表头,让数据更具可读性,代码示例如下:
import tablib
# 定义表头
headers = ["姓名", "年龄", "城市"]
# 定义数据行
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
# 创建带表头的Dataset
data = tablib.Dataset(*data_rows, headers=headers)
print("带表头的Dataset:")
print(data)
print("表头信息:", data.headers)
代码说明:通过在Dataset构造函数中传入headers参数,我们为数据集添加了表头。运行后输出的表格会包含表头行,并且可以通过data.headers属性获取表头信息。
创建好Dataset对象后,我们可以对其中的数据进行灵活的增删改查操作,满足日常数据处理需求。
查询操作包括获取指定行、指定列的数据,以及获取单元格数据,代码示例如下:
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 获取指定行数据(索引从0开始)
print("第1行数据:", data[0])
# 获取指定列数据(通过表头名)
print("年龄列数据:", data["年龄"])
# 获取指定单元格数据(行索引,列索引)
print("第2行第3列数据:", data[1][2])
# 遍历所有行数据
print("\n遍历所有数据行:")
for row in data:
print(row)
代码说明:通过索引可以快速获取指定行的数据,通过表头名可以获取整列数据,通过行索引+列索引的组合可以获取单元格数据。遍历操作则可以逐个获取数据集中的每一行数据。
添加操作包括添加单行数据、添加多行数据和添加列数据,代码示例如下:
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 添加单行数据
new_row = ["赵六", 32, "深圳"]
data.append(new_row)
print("添加单行后的数据:")
print(data)
# 添加多行数据
new_rows = [
["孙七", 27, "杭州"],
["周八", 29, "成都"]
]
data.extend(new_rows)
print("\n添加多行后的数据:")
print(data)
# 添加列数据(需要指定列名和数据)
new_column_data = [1001, 1002, 1003, 1004, 1005, 1006]
data.append_col(new_column_data, header="员工编号")
print("\n添加列后的数据:")
print(data)
代码说明:append()方法用于添加单行数据,extend()方法用于添加多行数据,append_col()方法用于添加整列数据,并且需要通过header参数指定新列的表头名。
修改操作包括修改指定行、指定列和指定单元格的数据,代码示例如下:
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 修改指定行数据
data[1] = ["李四", 31, "重庆"]
print("修改第2行后的数据:")
print(data)
# 修改指定列数据
data["年龄"] = [26, 32, 29]
print("\n修改年龄列后的数据:")
print(data)
# 修改指定单元格数据
data[2][1] = 30
print("\n修改第3行第2列后的数据:")
print(data)
代码说明:通过索引直接赋值可以修改指定行的数据,通过表头名赋值可以修改整列数据,通过行索引+列索引赋值可以修改单元格数据。
删除操作包括删除指定行和指定列的数据,代码示例如下:
import tablib
headers = ["姓名", "年龄", "城市", "员工编号"]
data_rows = [
["张三", 25, "北京", 1001],
["李四", 30, "上海", 1002],
["王五", 28, "广州", 1003]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 删除指定行数据(索引从0开始)
del data[1]
print("删除第2行后的数据:")
print(data)
# 删除指定列数据(通过表头名)
del data["员工编号"]
print("\n删除员工编号列后的数据:")
print(data)
代码说明:使用del关键字可以删除指定行或指定列的数据,删除行时传入行索引,删除列时传入列的表头名。
Tablib最核心的功能就是支持多种数据格式的转换、导出和导入,这也是它在实际项目中被广泛应用的原因,接下来我们详细讲解常用格式的操作方法。
CSV是一种通用的文本格式数据,常用于数据的存储和交换,Tablib支持Dataset与CSV格式的相互转换。
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 将Dataset转换为CSV格式字符串
csv_data = data.csv
print("CSV格式数据:")
print(csv_data)
# 将CSV数据保存到本地文件
with open("data.csv", "w", encoding="utf-8") as f:
f.write(csv_data)
print("\nCSV文件已保存到本地!")
代码说明:通过data.csv属性可以直接将Dataset对象转换为CSV格式的字符串,然后我们可以通过文件操作将其保存到本地,生成.csv文件。
import tablib
# 从本地CSV文件读取数据
with open("data.csv", "r", encoding="utf-8") as f:
csv_content = f.read()
# 将CSV字符串转换为Dataset对象
data = tablib.Dataset().load(csv_content, format="csv")
print("从CSV导入的Dataset数据:")
print(data)
print("表头信息:", data.headers)
代码说明:首先读取本地CSV文件的内容,然后使用load()方法,指定format="csv",将CSV字符串转换为Dataset对象,方便后续进行数据处理。
JSON是一种轻量级的数据交换格式,在Web开发和API交互中应用广泛,Tablib同样支持Dataset与JSON格式的转换。
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 将Dataset转换为JSON格式字符串
json_data = data.json
print("JSON格式数据:")
print(json_data)
# 将JSON数据保存到本地文件
with open("data.json", "w", encoding="utf-8") as f:
f.write(json_data)
print("\nJSON文件已保存到本地!")
代码说明:通过data.json属性可以快速将Dataset转换为JSON字符串,然后保存到本地生成.json文件。Tablib生成的JSON数据会以列表的形式存储每一行数据,表头作为键名。
import tablib
# 从本地JSON文件读取数据
with open("data.json", "r", encoding="utf-8") as f:
json_content = f.read()
# 将JSON字符串转换为Dataset对象
data = tablib.Dataset().load(json_content, format="json")
print("从JSON导入的Dataset数据:")
print(data)
代码说明:读取本地JSON文件内容后,使用load()方法并指定format="json",即可将JSON字符串转换为Dataset对象,实现数据的反向解析。
Excel是办公场景中最常用的数据表格格式,Tablib支持将Dataset导出为.xls和.xlsx格式,也能从Excel文件中导入数据。
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 将Dataset转换为Excel格式字节数据
xlsx_data = data.xlsx
# 将Excel数据保存到本地文件
with open("data.xlsx", "wb") as f:
f.write(xlsx_data)
print("Excel文件已保存到本地!")
代码说明:与CSV、JSON不同,Excel格式的数据是字节流形式,因此需要通过data.xlsx属性获取字节数据,然后以wb(二进制写入)模式保存到本地,生成.xlsx文件。如果需要生成.xls格式文件,可以使用data.xls属性。
import tablib
# 从本地Excel文件读取字节数据
with open("data.xlsx", "rb") as f:
xlsx_content = f.read()
# 将Excel字节数据转换为Dataset对象
data = tablib.Dataset().load(xlsx_content, format="xlsx")
print("从Excel导入的Dataset数据:")
print(data)
print("表头信息:", data.headers)
代码说明:读取Excel文件时需要使用rb(二进制读取)模式,然后通过load()方法指定format="xlsx",将字节数据转换为Dataset对象。对于.xls格式文件,只需将format参数改为"xls"即可。
YAML是一种人类可读的数据序列化格式,常用于配置文件和数据交换,Tablib支持Dataset与YAML格式的转换。
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 将Dataset转换为YAML格式字符串
yaml_data = data.yaml
print("YAML格式数据:")
print(yaml_data)
# 将YAML数据保存到本地文件
with open("data.yaml", "w", encoding="utf-8") as f:
f.write(yaml_data)
print("\nYAML文件已保存到本地!")
代码说明:通过data.yaml属性可以将Dataset转换为YAML字符串,然后保存到本地生成.yaml文件。YAML格式的数据结构清晰,可读性强,适合用于配置和简单数据存储。
import tablib
# 从本地YAML文件读取数据
with open("data.yaml", "r", encoding="utf-8") as f:
yaml_content = f.read()
# 将YAML字符串转换为Dataset对象
data = tablib.Dataset().load(yaml_content, format="yaml")
print("从YAML导入的Dataset数据:")
print(data)
代码说明:读取YAML文件内容后,使用load()方法指定format="yaml",即可将YAML字符串转换为Dataset对象,实现数据的解析和处理。
虽然Tablib本身没有提供复杂的筛选和排序API,但我们可以结合Python的列表推导式和内置函数,实现数据的筛选和排序功能,代码示例如下:
import tablib
headers = ["姓名", "年龄", "城市"]
data_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"],
["王五", 28, "广州"],
["赵六", 32, "深圳"],
["孙七", 27, "北京"]
]
data = tablib.Dataset(*data_rows, headers=headers)
# 数据筛选:筛选出城市为北京的记录
beijing_data = [row for row in data if row[2] == "北京"]
filtered_dataset = tablib.Dataset(*beijing_data, headers=headers)
print("城市为北京的筛选结果:")
print(filtered_dataset)
# 数据排序:按年龄升序排序
sorted_data = sorted(data, key=lambda x: x[1])
sorted_dataset = tablib.Dataset(*sorted_data, headers=headers)
print("\n按年龄升序排序的结果:")
print(sorted_dataset)
代码说明:通过列表推导式,我们筛选出了城市为北京的所有数据行,并创建了新的Dataset对象;使用sorted()函数和lambda表达式,我们实现了按年龄升序排序的功能,同样生成了新的排序后数据集。
在实际项目中,我们可能需要将多个结构相同的Dataset合并为一个,Tablib的extend()方法可以轻松实现这个需求,代码示例如下:
import tablib
# 创建第一个数据集
headers = ["姓名", "年龄", "城市"]
data1_rows = [
["张三", 25, "北京"],
["李四", 30, "上海"]
]
data1 = tablib.Dataset(*data1_rows, headers=headers)
# 创建第二个数据集
data2_rows = [
["王五", 28, "广州"],
["赵六", 32, "深圳"]
]
data2 = tablib.Dataset(*data2_rows, headers=headers)
# 合并两个数据集
data1.extend(data2_rows)
print("合并后的数据集:")
print(data1)
代码说明:首先创建两个结构相同(表头一致)的Dataset对象,然后使用extend()方法将第二个数据集的数据行添加到第一个数据集中,实现多数据集的合并。
假设我们需要处理一份学生成绩数据,要求完成以下任务:
实现代码如下:
import tablib
# 1. 创建学生成绩数据集
headers = ["姓名", "语文", "数学", "英语"]
score_rows = [
["小明", 95, 98, 92],
["小红", 88, 90, 95],
["小刚", 92, 85, 88],
["小丽", 96, 94, 97],
["小强", 85, 82, 80]
]
score_data = tablib.Dataset(*score_rows, headers=headers)
print("原始学生成绩数据:")
print(score_data)
# 2. 计算总分并添加到数据集
total_scores = [row[1] + row[2] + row[3] for row in score_data]
score_data.append_col(total_scores, header="总分")
print("\n添加总分后的成绩数据:")
print(score_data)
# 3. 筛选总分大于270分的学生
high_score_rows = [row for row in score_data if row[4] > 270]
high_score_data = tablib.Dataset(*high_score_rows, headers=score_data.headers)
print("\n总分大于270分的学生数据:")
print(high_score_data)
# 4. 导出为CSV和Excel格式文件
# 导出CSV
with open("high_score.csv", "w", encoding="utf-8") as f:
f.write(high_score_data.csv)
# 导出Excel
with open("high_score.xlsx", "wb") as f:
f.write(high_score_data.xlsx)
print("\n高分学生数据已导出为CSV和Excel文件!")
代码说明:这个案例结合了Tablib的基础操作和格式转换功能,完整实现了学生成绩数据的处理流程。通过计算总分、筛选数据,最终将结果导出为两种常用格式的文件,满足实际办公和数据处理需求。
关注我,每天分享一个实用的Python自动化工具。

Faker是一款Python第三方库,核心用途是生成高度逼真的伪随机测试数据,涵盖姓名、地址、邮箱、手机号、文本、时间等数百种数据类型,广泛应用于软件开发、数据分析、自动化测试等场景。其工作原理是基于不同地区的本地化数据模板,通过随机算法组合生成符合现实逻辑的虚拟数据。

该库的优点十分突出:支持多语言多地区本地化配置、数据类型丰富且可自定义扩展、使用方式简单灵活;缺点则是生成的部分专业数据(如金融账号、医疗信息)不具备真实有效性,仅适用于测试环境。Faker遵循MIT开源许可证,开发者可自由用于商业和非商业项目,无授权限制。
Faker的安装非常便捷,支持pip和conda两种主流包管理工具,技术小白也能轻松上手。
python pip install fakerpython pip install faker==19.6.2python conda install -c conda-forge faker安装完成后,我们可以通过一段简单的代码验证是否安装成功。创建一个名为test_faker.py的文件,输入以下代码:
# 导入Faker的核心类
from faker import Faker
# 初始化Faker对象
fake = Faker()
# 生成一条随机姓名数据
print("随机姓名:", fake.name())
运行该脚本,若终端输出类似随机姓名: Jennifer Davis的结果,则说明Faker库已成功安装。
Faker支持全球数十个国家和地区的本地化数据生成,默认生成的是英文数据,我们可以通过指定语言代码来生成符合国内习惯的中文数据。常见的语言代码包括:zh_CN(中国大陆)、zh_TW(中国台湾)、en_US(美国英语)、ja_JP(日语)等。
以下是本地化配置的代码示例:
from faker import Faker
# 初始化中文本地化的Faker对象
fake = Faker("zh_CN")
# 生成中文数据
print("中文姓名:", fake.name())
print("中文地址:", fake.address())
print("手机号码:", fake.phone_number())
运行结果示例:
中文姓名: 王芳
中文地址: 湖南省长沙市雨花区人民路88号 410007
手机号码: 13812345678
Faker库提供了数百种数据生成方法,覆盖日常开发和测试的大部分场景,我们可以将其分为基础信息类、网络信息类、文本数据类、时间日期类、专业数据类五大模块,下面逐一进行详细讲解并附上代码示例。
基础信息类数据是测试中最常用的类型,包括姓名、地址、手机号、身份证号、公司名称等,以下是常用方法的代码示例:
from faker import Faker
# 初始化中文Faker对象
fake = Faker("zh_CN")
# 生成姓名相关数据
print("随机姓名:", fake.name()) # 生成全名
print("姓氏:", fake.last_name()) # 生成姓氏
print("名字:", fake.first_name()) # 生成名字
# 生成地址相关数据
print("详细地址:", fake.address()) # 生成完整地址(省市区街道邮编)
print("省份:", fake.province()) # 生成省份
print("城市:", fake.city()) # 生成城市
print("街道地址:", fake.street_address()) # 生成街道地址
print("邮政编码:", fake.postcode()) # 生成邮政编码
# 生成联系方式相关数据
print("手机号码:", fake.phone_number()) # 生成中国大陆手机号
print("固定电话:", fake.phone_number()) # 生成固定电话(部分地区)
print("身份证号:", fake.ssn()) # 生成符合规则的身份证号
# 生成公司相关数据
print("公司名称:", fake.company()) # 生成公司名称
print("公司职位:", fake.job()) # 生成公司职位
代码说明:
fake.name():生成随机的中文全名,涵盖男女姓名,符合国内姓名命名习惯;fake.address():生成的地址包含省、市、区、街道、门牌号和邮编,格式规范,适合用于用户地址测试;fake.ssn():生成的身份证号符合18位的编码规则,包含地区码、出生日期码、顺序码和校验码,仅用于测试,不具备真实有效性。运行结果示例:
随机姓名: 李强
姓氏: 张
名字: 小明
详细地址: 广东省深圳市南山区科技园路100号 518000
省份: 浙江省
城市: 杭州市
街道地址: 东湖路99号
邮政编码: 310000
手机号码: 13987654321
固定电话: 021-12345678
身份证号: 430102199001011234
公司名称: 华讯科技有限公司
公司职位: 软件工程师
网络信息类数据包括邮箱、URL、IP地址、用户名、密码等,适用于Web开发中的用户注册、登录测试等场景,代码示例如下:
from faker import Faker
fake = Faker("zh_CN")
# 生成邮箱相关数据
print("随机邮箱:", fake.email()) # 生成随机邮箱
print("企业邮箱:", fake.company_email()) # 生成企业邮箱
print("免费邮箱:", fake.free_email()) # 生成免费邮箱(如163、qq邮箱)
# 生成URL相关数据
print("网站URL:", fake.url()) # 生成随机网站URL
print("域名:", fake.domain_name()) # 生成域名
print("IP地址(IPv4):", fake.ipv4()) # 生成IPv4地址
print("IP地址(IPv6):", fake.ipv6()) # 生成IPv6地址
# 生成用户账号相关数据
print("用户名:", fake.user_name()) # 生成用户名
print("密码:", fake.password(length=12)) # 生成指定长度的密码
print("用户代理(UA):", fake.user_agent()) # 生成浏览器用户代理字符串
代码说明:
fake.email():生成的邮箱格式规范,包含用户名、@符号和域名,支持自定义域名;fake.password(length=12):通过length参数指定密码长度,默认生成包含字母、数字和特殊字符的强密码;fake.user_agent():生成的UA字符串符合主流浏览器(Chrome、Firefox、Safari等)的格式,适用于爬虫和Web测试。运行结果示例:
随机邮箱: [email protected]
企业邮箱: [email protected]
免费邮箱: [email protected]
网站URL: https://www.example.com
域名: example.net
IP地址(IPv4): 192.168.1.100
IP地址(IPv6): 2001:0db8:85a3:0000:0000:8a2e:0370:7334
用户名: liqiang_88
密码: K9#p2Q7!xR3t
用户代理(UA): Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
文本数据类数据包括单词、句子、段落、文章、随机字符等,适用于生成测试用的文本内容、填充数据库字段等场景,代码示例如下:
from faker import Faker
fake = Faker("zh_CN")
# 生成单词和句子
print("随机单词:", fake.word()) # 生成单个中文词语
print("随机句子:", fake.sentence()) # 生成单个中文句子
print("多个句子:", fake.sentences(nb=3)) # 生成指定数量的句子,返回列表
# 生成段落和文章
print("随机段落:", fake.paragraph()) # 生成单个中文段落
print("多个段落:", fake.paragraphs(nb=2)) # 生成指定数量的段落,返回列表
print("随机文章:", fake.text()) # 生成一篇中文文章(多个段落)
# 生成随机字符
print("随机字母(大写):", fake.random_letter().upper()) # 生成单个大写字母
print("随机数字字符串:", fake.numerify(text="###-####-#####")) # 生成指定格式的数字字符串
print("随机字母数字混合字符串:", fake.bothify(text="??##-??##-??##")) # 生成字母数字混合字符串
代码说明:
fake.sentence():生成的句子语法正确,语义通顺,长度在10-20个字符左右;fake.paragraphs(nb=2):nb参数用于指定生成的段落数量,返回的是字符串列表;fake.numerify()和fake.bothify():支持通过占位符自定义格式,#代表数字,?代表字母,适合生成订单号、产品编号等格式固定的数据。运行结果示例:
随机单词: 技术
随机句子: 该项目的研发工作已经进入了最后的测试阶段。
多个句子: ['公司将于下周一召开全体员工大会。', '新产品的市场反馈情况超出了预期。', '请各位同事按时提交本月的工作总结。']
随机段落: 近年来,随着人工智能技术的快速发展,越来越多的企业开始将AI技术应用到实际生产中。从智能制造到智能客服,AI技术的落地场景不断丰富,为企业带来了显著的效率提升和成本节约。同时,相关的政策支持也为AI产业的发展提供了良好的环境,推动整个行业朝着更加规范和成熟的方向迈进。
多个段落: ['在教育领域,线上学习平台的普及改变了传统的教学模式。学生可以随时随地获取学习资源,教师也可以通过大数据分析了解学生的学习情况,从而实现个性化教学。这种模式不仅提高了学习效率,还打破了地域和时间的限制,让优质教育资源能够惠及更多人群。', '随着人们生活水平的提高,健康意识也越来越强。健身、养生、有机食品等概念逐渐成为主流,相关产业也迎来了快速发展的机遇。同时,医疗技术的进步也为人们的健康提供了更有力的保障,许多疑难杂症的治疗效果得到了显著提升。']
随机文章: 数字经济是当前全球经济发展的重要趋势,它以数据为关键生产要素,以现代信息网络为主要载体,以信息通信技术融合应用、全要素数字化转型为重要推动力,促进公平与效率更加统一的新经济形态。
在数字经济的发展过程中,数据的价值日益凸显。企业通过对海量数据的分析和挖掘,可以精准把握市场需求,优化产品设计和生产流程,提升自身的核心竞争力。同时,政府也可以利用数据技术提升治理能力,实现精准施策和高效服务。
然而,数字经济的发展也面临着一些挑战,比如数据安全、隐私保护、数字鸿沟等问题。这些问题需要政府、企业和社会各界共同努力,通过完善法律法规、加强技术研发、推进普惠性政策等方式加以解决,从而推动数字经济健康可持续发展。
随机字母(大写): M
随机数字字符串: 123-4567-89012
随机字母数字混合字符串: AB12-CD34-EF56
时间日期类数据包括日期、时间、时间戳等,适用于测试时间相关的功能模块,如订单创建时间、用户注册时间等,代码示例如下:
from faker import Faker
fake = Faker("zh_CN")
# 生成日期相关数据
print("随机日期(YYYY-MM-DD):", fake.date()) # 生成随机日期
print("指定范围的日期:", fake.date_between(start_date="-1y", end_date="today")) # 生成近一年的日期
print("未来日期:", fake.date_between(start_date="today", end_date="+30d")) # 生成未来30天的日期
print("生日日期:", fake.date_of_birth(minimum_age=18, maximum_age=60)) # 生成18-60岁的生日日期
# 生成时间相关数据
print("随机时间(HH:MM:SS):", fake.time()) # 生成随机时间
print("日期时间组合:", fake.date_time()) # 生成随机日期时间
print("Unix时间戳:", fake.unix_time()) # 生成Unix时间戳
print("ISO格式日期时间:", fake.iso8601()) # 生成ISO8601格式的日期时间
# 生成时间段相关数据
print("随机月份:", fake.month()) # 生成月份(1-12)
print("随机星期:", fake.day_of_week()) # 生成星期几
print("随机年份:", fake.year()) # 生成年份
代码说明:
fake.date_between():通过start_date和end_date参数指定日期范围,支持相对时间(如-1y代表一年前,+30d代表30天后)和绝对时间(如2023-01-01);fake.date_of_birth():通过minimum_age和maximum_age参数指定年龄范围,生成对应的生日日期;fake.iso8601():生成的日期时间符合ISO8601国际标准,格式为YYYY-MM-DDTHH:MM:SS,适用于国际项目的测试。运行结果示例:
随机日期(YYYY-MM-DD): 2020-05-18
指定范围的日期: 2024-03-25
未来日期: 2025-01-15
生日日期: 1985-08-12
随机时间(HH:MM:SS): 14:35:22
日期时间组合: 2022-11-03 09:12:34
Unix时间戳: 1678901234
ISO格式日期时间: 2023-07-15T16:20:10
随机月份: 06
随机星期: Friday
随机年份: 2019
专业数据类数据包括银行卡号、车牌号、颜色、文件扩展名、编程语言等,适用于特定领域的测试场景,代码示例如下:
from faker import Faker
fake = Faker("zh_CN")
# 生成金融相关数据
print("银行卡号:", fake.credit_card_number()) # 生成银行卡号
print("银行卡类型:", fake.credit_card_provider()) # 生成银行卡类型
print("银行卡有效期:", fake.credit_card_expire()) # 生成银行卡有效期
# 生成交通相关数据
print("车牌号:", fake.license_plate()) # 生成中国大陆车牌号
# 生成其他专业数据
print("颜色名称:", fake.color_name()) # 生成颜色名称
print("文件扩展名:", fake.file_extension()) # 生成文件扩展名
print("编程语言:", fake.programming_language()) # 生成编程语言名称
print("UUID:", fake.uuid4()) # 生成UUID4字符串
代码说明:
fake.credit_card_number():生成的银行卡号符合各大银行的编码规则,仅用于测试,不可用于真实交易;fake.license_plate():生成的车牌号符合中国大陆的格式(省份简称+字母+数字);fake.uuid4():生成的UUID4字符串符合标准格式,适用于生成唯一标识符。运行结果示例:
银行卡号: 6222021234567890
银行卡类型: Mastercard
银行卡有效期: 28/12
车牌号: 粤A12345
颜色名称: Blue
文件扩展名: pdf
编程语言: Python
UUID: 550e8400-e29b-41d4-a716-446655440000
虽然Faker库提供了丰富的内置数据生成方法,但在实际开发中,我们可能会遇到一些特殊的需求,比如生成符合特定业务规则的数据(如电商平台的商品SKU、物流单号等)。这时我们可以通过自定义数据生成器来扩展Faker的功能,下面以生成电商商品SKU为例,详细讲解自定义数据生成器的实现方法。
faker.providers.BaseProvider;from faker import Faker
from faker.providers import BaseProvider
# 1. 定义自定义生成器类
class CustomSKUProvider(BaseProvider):
def product_sku(self):
"""
生成电商商品SKU,格式为:分类缩写-品牌缩写-年份-随机数字
分类缩写:ELE(电子产品)、CLT(服装)、FOD(食品)
品牌缩写:APP(苹果)、SAM(三星)、NIK(耐克)、ADID(阿迪达斯)、UNI(统一)
"""
# 定义分类缩写列表
category_list = ["ELE", "CLT", "FOD"]
# 定义品牌缩写列表
brand_list = {
"ELE": ["APP", "SAM", "HUA", "XIA"],
"CLT": ["NIK", "ADID", "PUMA", "ANTA"],
"FOD": ["UNI", "MASTER", "KANG", "WEIQ"]
}
# 随机选择分类
category = self.random_element(category_list)
# 根据分类选择品牌
brand = self.random_element(brand_list[category])
# 生成年份(近5年)
year = self.random_int(min=2020, max=2025)
# 生成随机数字(4位)
num = self.random_int(min=1000, max=9999)
# 组合生成SKU
sku = f"{category}-{brand}-{year}-{num}"
return sku
# 2. 初始化Faker对象
fake = Faker("zh_CN")
# 3. 添加自定义提供者到Faker对象
fake.add_provider(CustomSKUProvider)
# 4. 调用自定义方法生成数据
for _ in range(5):
print("自定义商品SKU:", fake.product_sku())
代码说明:
BaseProvider,这是Faker库规定的扩展规范;product_sku方法中,我们通过self.random_element()和self.random_int()方法实现随机选择和随机数字生成,这两个方法是BaseProvider类提供的内置方法;fake.add_provider()方法将自定义类添加到Faker对象后,就可以像调用内置方法一样调用fake.product_sku()生成数据。运行结果示例:
自定义商品SKU: ELE-APP-2023-4567
自定义商品SKU: CLT-NIK-2021-1234
自定义商品SKU: FOD-UNI-2025-8901
自定义商品SKU: ELE-XIA-2022-2345
自定义商品SKU: CLT-ANTA-2024-5678
除了生成商品SKU,自定义数据生成器还可以应用于以下场景:
在实际的软件开发和测试中,我们经常需要批量生成用户数据并保存到文件中,供自动化测试或数据库填充使用。下面以生成100条中文用户数据并保存为CSV文件为例,展示Faker库的实际应用价值。
test_users.csv文件。import csv
from faker import Faker
import random
# 初始化中文Faker对象
fake = Faker("zh_CN")
# 定义CSV文件的表头
headers = ["user_id", "name", "gender", "age", "phone", "email", "address", "register_time", "job"]
# 生成100条用户数据
user_data = []
for i in range(1, 101):
# 生成用户ID
user_id = f"user_{i:03d}" # 格式为user_001, user_002...
# 生成姓名
name = fake.name()
# 生成性别
gender = random.choice(["男", "女"])
# 生成年龄
age = random.randint(18, 60)
# 生成手机号
phone = fake.phone_number()
# 生成邮箱
email = fake.email()
# 生成地址
address = fake.address().replace("\n", " ") # 去除地址中的换行符
# 生成注册时间(近一年)
register_time = fake.date_time_between(start_date="-1y", end_date="today")
# 生成职业
job = fake.job()
# 将数据添加到列表
user_data.append([user_id, name, gender, age, phone, email, address, register_time, job])
# 将数据写入CSV文件
with open("test_users.csv", "w", encoding="utf-8", newline="") as f:
writer = csv.writer(f)
# 写入表头
writer.writerow(headers)
# 写入数据
writer.writerows(user_data)
print("100条用户数据已成功生成并保存到test_users.csv文件中!")
代码说明:
random.choice(["男", "女"])实现性别的随机分布;user_id的格式通过f-string格式化,i:03d表示将数字格式化为3位,不足的位数用0填充;replace("\n", " ")去除换行符,避免CSV文件格式错乱;encoding="utf-8"以支持中文,newline=""避免出现空行。运行代码后,会在当前目录下生成一个名为test_users.csv的文件,打开后部分数据如下:
| user_id | name | gender | age | phone | email | address | register_time | job |
| – | – | – | – | – | – | – | – | – |
| user_001 | 张三 | 男 | 28 | 13812345678 | [email protected] | 北京市朝阳区建国路88号 100022 | 2024-05-12 10:23:45 | 软件工程师 |
| user_002 | 李四 | 女 | 35 | 13987654321 | [email protected] | 上海市浦东新区张江高科技园区 201203 | 2024-08-25 14:56:12 | 市场经理 |
这个案例可以直接应用于Web项目的用户模块测试,帮助测试人员快速构建测试数据,提高测试效率。
关注我,每天分享一个实用的Python自动化工具。
