Python实战:利用cdsapi高效批量下载ERA5日尺度气象数据
1. 为什么需要批量下载ERA5气象数据
气象数据是科研和工程应用中不可或缺的基础资料。ERA5作为欧洲中期天气预报中心(ECMWF)提供的第五代再分析数据集,包含了从1940年至今的全球气象要素,时间分辨率达到小时级别,空间分辨率最高可达0.25°×0.25°。相比之前的ERA-Interim数据集,ERA5在数据质量和时空分辨率上都有显著提升。
在实际工作中,我们经常需要获取长时间序列的气象数据。比如研究气候变化可能需要几十年的日尺度数据,如果手动一个个下载,不仅效率低下还容易出错。我曾经为了获取10年的日降水量数据,手动操作花了整整两天时间,还经常因为网络问题导致下载中断。这就是为什么我们需要掌握批量下载技巧。
cdsapi是ECMWF提供的官方Python接口,通过它可以直接从Copernicus Climate Data Store(CDS)获取ERA5数据。最新版的CDS-Beta系统已经原生支持日尺度数据的下载,比之前需要自己处理小时数据方便多了。这个工具特别适合:
- 需要长期气象数据的气候研究者
- 开发气象相关应用的工程师
- 进行区域环境分析的地理工作者
2. 环境配置与基础设置
2.1 安装必要的Python库
在开始之前,我们需要准备好Python环境。推荐使用Anaconda创建独立的虚拟环境:
conda create -n era5 python=3.8 conda activate era5 pip install cdsapi xarray netCDF4cdsapi是与CDS服务交互的核心库,xarray和netCDF4则是处理下载数据的利器。我建议同时安装这几个库,避免后续处理数据时再折腾环境。
2.2 获取CDS API密钥
使用cdsapi需要先在CDS官网注册账号并获取API密钥:
- 访问CDS官网注册账号
- 登录后进入用户设置页面
- 找到"API密钥"部分
- 将显示的URL和密钥保存到本地
~/.cdsapirc文件中
文件内容应该长这样:
url: https://cds.climate.copernicus.eu/api/v2 key: 123456:abcdefgh-1234-5678-9012-345678901234注意:这个密钥相当于你的密码,千万不要上传到公开的代码仓库。我习惯把.cdsapirc文件权限设置为600,防止其他用户读取。
3. 单日数据下载实战
3.1 基础下载示例
让我们从一个最简单的例子开始 - 下载2001年全年的2米气温日平均数据:
import cdsapi dataset = "derived-era5-single-levels-daily-statistics" request = { "product_type": "reanalysis", "variable": ["2m_temperature"], "year": "2001", "month": ["01","02","03","04","05","06","07","08","09","10","11","12"], "day": [f"{i:02d}" for i in range(1,32)], "daily_statistic": "daily_mean", "time_zone": "utc+00:00", "frequency": "1_hourly" } client = cdsapi.Client() client.retrieve(dataset, request).download("era5_temp_2001.nc")这段代码有几个关键点需要注意:
dataset指定了我们要下载的数据集名称variable参数可以同时请求多个气象要素daily_statistic支持多种统计方式,如daily_max、daily_min等- 日期格式必须使用两位数字,所以我用了f-string格式化
3.2 优化下载参数
默认设置下载的是0.25°×0.25°的高分辨率数据,但很多时候我们并不需要这么精细的数据。通过调整参数可以显著提高下载速度:
request = { # ...其他参数同上... 'area': [50, 100, 20, 130], # 北,西,南,东 'grid': '1.0/1.0', # 1°×1°分辨率 'download_format': 'nc' # 直接下载NetCDF格式 }这里我添加了三个实用参数:
area限定了下载区域,格式为[北纬,西经,南纬,东经]grid降低了空间分辨率download_format指定输出格式
实测下来,下载中国区域1°分辨率的数据比全球0.25°分辨率快5倍以上,文件大小也只有原来的1/16。
4. 批量下载技巧与优化
4.1 多变量多年份下载
当我们需要下载多个变量或多个年份的数据时,可以封装一个下载函数:
def download_era5(variables, years, bbox=None, grid='1.0/1.0'): client = cdsapi.Client() for var in variables: for year in years: request = { "product_type": "reanalysis", "variable": [var], "year": str(year), "month": [f"{m:02d}" for m in range(1,13)], "day": [f"{d:02d}" for d in range(1,32)], "daily_statistic": "daily_mean", "time_zone": "utc+00:00", "grid": grid, "download_format": "nc" } if bbox: request['area'] = bbox filename = f"ERA5_{var}_{year}.nc" try: client.retrieve(dataset, request, filename) print(f"成功下载 {filename}") except Exception as e: print(f"下载 {filename} 失败: {str(e)}") # 示例:下载2001-2005年的温度和降水数据 download_era5( variables=["2m_temperature", "total_precipitation"], years=range(2001, 2006), bbox=[50, 100, 20, 130] # 中国区域 )这个函数添加了异常处理,避免因为单个文件下载失败导致整个程序中断。我在实际项目中发现,CDS服务偶尔会出现临时性错误,加入重试机制会更稳妥。
4.2 下载进度监控与错误处理
大规模下载时,了解进度非常重要。CDS提供了一个实用的请求状态页面:
- 登录CDS官网
- 点击右上角用户名
- 选择"Your requests"
在这里你可以看到所有提交的请求及其状态。通常请求会经历以下状态:
- queued:排队中
- running:处理中
- completed:已完成
- failed:失败
对于重要的长期任务,我建议定期检查这个页面。如果发现某个请求长时间卡住,可以尝试取消后重新提交。
5. 数据处理与质量控制
5.1 数据读取与初步检查
下载完成后,我们可以用xarray快速检查数据内容:
import xarray as xr ds = xr.open_dataset("ERA5_2m_temperature_2001.nc") print(ds) # 查看时间维度 print(ds.time) # 查看空间范围 print(ds.latitude.values) print(ds.longitude.values) # 提取某个站点的数据 station_data = ds['t2m'].sel( latitude=39.9, longitude=116.4, method='nearest' )xarray的sel方法可以方便地提取特定位置的数据。method='nearest'表示取最近格点,这对气象数据分析非常实用。
5.2 常见问题排查
在实际使用中,可能会遇到一些典型问题:
- 数据缺失:检查请求的时间范围是否有效,某些早期年份可能缺少部分数据
- 数值异常:ERA5的温度单位是开尔文,需要减去273.15转换为摄氏度
- 空间范围不符:确认area参数的顺序是[北,西,南,东]
- 下载超时:大区域高分辨率数据可能需要数小时处理,建议拆分为多个小请求
我曾经遇到过下载的数据全是NaN值的情况,后来发现是因为请求了不存在的变量名。建议先在CDS网站上确认变量名称的正确性。
6. 高级技巧与性能优化
6.1 并行下载加速
当需要下载大量数据时,串行方式效率太低。我们可以使用Python的multiprocessing实现并行下载:
from multiprocessing import Pool def download_task(args): year, var = args download_era5([var], [year]) if __name__ == '__main__': tasks = [(year, var) for year in range(2001, 2021) for var in ["2m_temperature", "total_precipitation"]] with Pool(4) as p: # 使用4个进程 p.map(download_task, tasks)需要注意的是,CDS对并发请求有限制,通常不建议超过3-5个并行请求。我一般设置4个进程,这样既能提高速度又不会触发服务限制。
6.2 数据分块处理
对于特别大的数据集,可以考虑按时间或空间分块下载:
# 按季度下载 for year in range(2001, 2006): for quarter in [(1,3), (4,6), (7,9), (10,12)]: request = { # ...其他参数... "month": [f"{m:02d}" for m in range(quarter[0], quarter[1]+1)], } filename = f"ERA5_{var}_{year}_Q{quarter[0]//3+1}.nc" client.retrieve(dataset, request, filename)这种方法特别适合需要高时空分辨率数据的研究。下载后可以使用xarray的concat或merge功能将分块数据合并。
7. 实际应用案例
7.1 气候变化趋势分析
假设我们要分析中国东部地区近20年的温度变化趋势,可以这样处理:
# 下载数据 download_era5( variables=["2m_temperature"], years=range(2001, 2021), bbox=[45, 110, 20, 130], # 中国东部区域 grid='0.5/0.5' # 中等分辨率 ) # 计算区域年平均温度 annual_means = [] for year in range(2001, 2021): ds = xr.open_dataset(f"ERA5_2m_temperature_{year}.nc") annual_mean = ds['t2m'].mean(dim=('time', 'latitude', 'longitude')) - 273.15 annual_means.append(annual_mean.values) # 绘制变化曲线 import matplotlib.pyplot as plt plt.plot(range(2001, 2021), annual_means) plt.xlabel("Year") plt.ylabel("Temperature (°C)") plt.title("Annual Mean Temperature in Eastern China") plt.show()这个例子展示了如何将下载的数据直接用于科研分析。通过调整bbox参数,可以轻松研究不同区域的气候特征。
7.2 气象数据可视化
ERA5数据非常适合制作各种气象图表。下面是一个简单的温度空间分布示例:
import cartopy.crs as ccrs ds = xr.open_dataset("ERA5_2m_temperature_2020.nc") temp = ds['t2m'].isel(time=0) - 273.15 # 取第一个时次并转换单位 fig = plt.figure(figsize=(10, 6)) ax = plt.axes(projection=ccrs.PlateCarree()) temp.plot(ax=ax, transform=ccrs.PlateCarree(), cbar_kwargs={'label': 'Temperature (°C)'}) ax.coastlines() ax.set_title("Surface Air Temperature") plt.show()这个可视化使用了cartopy库来处理地图投影。对于更复杂的可视化需求,可以考虑使用专业的气象绘图软件如Metview或GrADS。
