告别手动点击!用Python脚本批量下载ERA5气象数据的保姆级教程(附.cdsapirc配置避坑指南)
·
告别手动点击!用Python脚本批量下载ERA5气象数据的保姆级教程(附.cdsapirc配置避坑指南)
气象数据分析的第一步永远是数据获取。对于需要处理长时间序列、多变量的研究者来说,手动在网页上逐个勾选日期和参数无异于一场噩梦。我曾见过同行为了下载10年的逐小时数据,连续三天守在电脑前重复点击操作——直到浏览器崩溃。本文将彻底解决这个痛点,教你用Python脚本构建自动化工作流,把重复劳动交给代码,把宝贵时间留给真正的科研。
1. 环境准备与CDS API密钥配置
1.1 注册CDS账户并获取API凭证
访问 Copernicus Climate Data Store 完成注册后,个人资料页的"API key"选项卡藏着自动化下载的钥匙。这里需要特别注意:
- UID :形如
123456的数字串 - API Key :由32位字母数字组成的字符串(如
a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8)
这两个凭证的组合将构成 .cdsapirc 文件的核心内容。常见错误包括混淆UID与登录用户名,或误用包含特殊字符的旧版密钥。
1.2 创建.cdsapirc配置文件
在用户根目录(Linux/Mac的 ~ 或Windows的 C:\Users\<用户名> )创建这个隐藏文件。以下是典型错误与正确示例对比:
# 错误示例(缺少冒号、格式错乱)
url: https://cds.climate.copernicus.eu/api/v2
key 123456:a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8
# 正确格式
url: https://cds.climate.copernicus.eu/api/v2
key: 123456:a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8
验证配置是否生效的最快方法是在终端执行:
cat ~/.cdsapirc | grep -E "url|key" # Linux/Mac
type %USERPROFILE%\.cdsapirc # Windows
2. Python自动化下载核心代码解析
2.1 基础请求模板生成技巧
在CDS网页选择数据时,"Show API request"按钮生成的代码往往需要优化。原始代码可能长这样:
import cdsapi
c = cdsapi.Client()
c.retrieve(
'reanalysis-era5-single-levels',
{
'product_type': 'reanalysis',
'variable': '2m_temperature',
'year': '2020',
'month': '01',
'day': '01',
'time': '12:00',
'format': 'netcdf',
},
'download.nc')
改进后的模板应包含错误处理和参数化设计:
def era5_download(variable, years, months, days, times, output_file):
"""增强版下载函数"""
try:
c = cdsapi.Client()
request = {
'product_type': 'reanalysis',
'format': 'netcdf',
'variable': variable,
'year': years,
'month': months,
'day': days,
'time': times,
}
c.retrieve('reanalysis-era5-single-levels', request, output_file)
print(f"成功下载: {output_file}")
except Exception as e:
print(f"下载失败: {str(e)}")
2.2 多时间批次下载实战
处理跨年数据时,直接传入所有年份可能导致服务器拒绝请求。更稳健的做法是分批次处理:
from datetime import datetime, timedelta
def date_range(start_date, end_date):
"""生成日期序列"""
delta = end_date - start_date
return [start_date + timedelta(days=i) for i in range(delta.days + 1)]
# 示例:下载2020-2022年每日00时和12时数据
dates = date_range(datetime(2020,1,1), datetime(2022,12,31))
for dt in dates:
filename = f"era5_{dt.strftime('%Y%m%d')}.nc"
era5_download(
variable='2m_temperature',
years=dt.strftime('%Y'),
months=dt.strftime('%m'),
days=dt.strftime('%d'),
times=['00:00', '12:00'],
output_file=filename
)
3. 高频报错解决方案精要
3.1 证书验证失败问题
当遇到 SSL: CERTIFICATE_VERIFY_FAILED 错误时,可通过以下方式解决:
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
但更安全的做法是更新本地证书库:
# Ubuntu/Debian
sudo apt-get install ca-certificates
# Mac (Homebrew)
brew install openssl
3.2 请求配额与限流处理
CDS对并发请求有限制,建议:
- 添加随机延迟(5-30秒)
import random
import time
time.sleep(5 + random.random() * 25) # 随机等待5-30秒
- 使用指数退避重试机制
import math
def download_with_retry(max_retries=3):
retries = 0
while retries < max_retries:
try:
# 下载代码...
break
except Exception as e:
wait_time = math.pow(2, retries)
print(f"等待{wait_time}秒后重试...")
time.sleep(wait_time)
retries += 1
4. 高级技巧与性能优化
4.1 多变量并行下载
使用 concurrent.futures 实现并行下载(注意遵守CDS使用政策):
from concurrent.futures import ThreadPoolExecutor
variables = [
'2m_temperature',
'mean_sea_level_pressure',
'total_precipitation'
]
def download_var(var):
era5_download(
variable=var,
years=['2020', '2021'],
months=['{:02d}'.format(m) for m in range(1,13)],
days=['{:02d}'.format(d) for d in range(1,32)],
times=['00:00', '12:00'],
output_file=f'{var}_2020-2021.nc'
)
with ThreadPoolExecutor(max_workers=3) as executor:
executor.map(download_var, variables)
4.2 数据分块与合并策略
对于超大范围数据,采用分块下载后合并的策略:
# 下载欧洲和亚洲分区数据
regions = {
'europe': [35, 70, -10, 40], # lat_min, lat_max, lon_min, lon_max
'asia': [10, 55, 60, 140]
}
for name, area in regions.items():
era5_download(
variable='2m_temperature',
years='2020',
area=area, # 关键参数:North/West/South/East
output_file=f'temp_{name}.nc'
)
# 使用xarray合并文件
import xarray as xr
ds = xr.open_mfdataset('temp_*.nc', combine='by_coords')
ds.to_netcdf('global_temp_2020.nc')
4.3 元数据自动记录
为每个下载文件添加说明性元数据:
import netCDF4 as nc
from datetime import datetime
def add_metadata(filename):
with nc.Dataset(filename, 'a') as ds:
ds.download_date = datetime.now().isoformat()
ds.download_script = "era5_auto_downloader v1.2"
ds.creator_email = "your@email.com"
5. 完整工作流示例
结合上述技术点的典型应用场景:
# config.py
CDS_API_URL = "https://cds.climate.copernicus.eu/api/v2"
API_KEY = "your:key"
# era5_downloader.py
import os
import time
import random
from config import CDS_API_URL, API_KEY
def configure_cds():
"""确保API配置正确"""
cds_dir = os.path.expanduser('~')
cds_file = os.path.join(cds_dir, '.cdsapirc')
if not os.path.exists(cds_file):
with open(cds_file, 'w') as f:
f.write(f"url: {CDS_API_URL}\nkey: {API_KEY}")
def batch_download(variables, years, output_dir):
"""批量下载主函数"""
os.makedirs(output_dir, exist_ok=True)
for year in years:
for var in variables:
filename = os.path.join(output_dir, f"{var}_{year}.nc")
if os.path.exists(filename):
continue
try:
era5_download(
variable=var,
years=str(year),
months=[f"{m:02d}" for m in range(1,13)],
days=[f"{d:02d}" for d in range(1,32)],
times=['00:00', '06:00', '12:00', '18:00'],
output_file=filename
)
time.sleep(10 + random.random() * 20) # 限流延迟
except Exception as e:
print(f"Error downloading {var} {year}: {str(e)}")
time.sleep(60) # 出错后延长等待
if __name__ == "__main__":
configure_cds()
important_vars = [
'2m_temperature',
'total_column_water_vapour',
'surface_pressure'
]
batch_download(important_vars, range(2010, 2023), "era5_data")
更多推荐
所有评论(0)