ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ECMWF再分析数据下载实战:Python API批量获取ERA5全流程指南

ECMWF再分析数据下载实战:Python API批量获取ERA5全流程指南 ECMWF的再分析数据集尤其是ERA5系列基本是气象、水文、环境、农业遥感这些领域绕不开的公共数据源。但真正用起来很多人第一步就卡在“怎么把数据弄下来”上。网页端手动下一个两个文件还行一旦涉及多年、多变量、多区域一个个点下载按钮能让人崩溃。所以通过Python API批量下载基本是干这行的标配技能。这篇文章我就把从注册账号、配置环境、写脚本到批量拉取数据的完整流程拆开讲清楚附带我这些年踩过的坑和排查经验。1. 为什么要用API而不是网页手动下载在动手敲代码之前先把ECMWF的数据分发机制理清楚。ECMWF本身是欧洲中期天气预报中心他们维护着一系列再分析资料比如ERA5、ERA5-Land以及CAMS大气成分数据、季节性预报数据等等。这些数据并不是以“文件列表”的形式直接摆在那里让你挑的而是存放在一个叫CDSClimate Data Store的数据目录里。你要什么变量、什么时间段、什么区域、什么格式得按条件去“申请”系统审核通过后再把数据拼装好给你下载。这种机制下网页端手动下载的痛点非常明显。首先单次请求能拿到的数据量是有限的你不能一次性申请“1979年至今全球所有变量”这种超大任务系统会直接拒绝或排队排到天荒地老。其次ERA5这种高分辨率再分析资料单一个变量、单一年份、全球范围的数据就可能有几个GB到几十GB浏览器下载一旦断掉就得从头再来。最要命的是当你需要几十上百个文件时手动操作不仅耗费时间而且极易出错——变量名拼错、时间格式写错、区域范围填反都是实际会发生的低级错误。用Python API就完全是另一套体验了。它是CDS提供的官方接口你只需要写一个请求脚本把数据集名、变量列表、时间范围、区域范围、输出格式这些参数填好剩下的交给API去和服务器交互。请求会进入队列服务器处理完成后返回一个下载链接你再用代码把文件拉下来。整个过程全自动化可以循环、可以断点续传、可以并发出错也能通过日志快速定位。这套东西适合谁一句话凡是需要系统性使用ECMWF再分析数据的科研人员、工程师、学生都建议直接用API。哪怕你只需要一两个变量只要时间跨度超过一年API的效率都远高于手动下载。另外如果你做的是那种需要定期更新数据的业务——比如每天拉取前一天的预报或实况数据来跑模型——API几乎是唯一合理的选择。需要说明的是我这里讲的流程以CDS和ERA5为核心但思路完全适用于CDS上托管的其他数据集比如ERA5-Land、CAMS、SEAS5等不同数据集只是dataset名称和请求参数不同而已。2. 动手前的准备账号、API Key和Python环境2.1 注册CDS账号并激活服务要使用API第一步是注册CDS账号。访问CDS官网点击右上角的登录/注册入口用邮箱注册即可。注册流程不复杂但有一点容易忽略部分数据集特别是较新的CDS-Beta平台上托管的数据集需要你额外点击“Accept”接受数据使用协议否则即使账号注册成功发起请求时也会被拒绝。这里稍微提醒一下如果你是新用户现在进入CDS网站时看到的可能是新版CDS-Beta界面和老版界面在交互上有差异。新版平台在用户头像菜单里直接有“API Key”入口老版则是在个人主页底部显示URL和Key。两个平台的API接入URL不同这点后面配置credentials文件时会重点讲。2.2 获取API Key登录CDS后进入个人账户页面新版在头像菜单里老版在个人主页底部你会看到两样东西URLAPI接入地址Key一串由UID和密钥组成的字符串格式类似 UID:APIKEYKey是敏感信息别把它提交到公开仓库或者贴在博客里。我个人习惯把Key存在环境变量里避免硬编码到脚本中。不过cdsapi官方推荐方式是写入一个名为.cdsapirc的配置文件这也是接下来要讲的方法。需要特别留意的是新版CDS-Beta和老版CDS的URL不是同一个。老版是https://cds.climate.copernicus.eu/api新版目前可以通过https://cds.climate.copernicus.eu/api兼容访问但如果你用的是更新的数据中心URL可能会有变化。最稳妥的办法是直接从你账号页面复制官方显示的URL不要凭记忆拼写。2.3 准备Python环境建议使用Python 3.9及以上版本。生态成熟、兼容性好cdsapi这个库在3.8以下版本的部分特性上有兼容问题没必要跟环境较劲。安装cdsapi库很简单pip install cdsapi如果你用的是Anacondaconda install -c conda-forge cdsapi需要确认cdsapi版本。新版CDS-Beta平台需要0.7.0以上版本旧版本可能无法正常工作。安装后用pip show cdsapi检查一下版本号。2.4 配置credentials文件cdsapi库寻找API凭证时会在用户主目录下查找.cdsapirc文件。手动创建这个文件Windows系统在C:\Users\你的用户名\目录下新建文件.cdsapircLinux/Mac系统在~目录下新建文件.cdsapirc文件内容格式极其简单url: https://cds.climate.copernicus.eu/api key: UID:APIKEY注意key这一行填的是你从账号页面看到的完整字符串包含冒号前面的UID冒号本身不要省略。保存后写个简单测试确认配置生效import cdsapi client cdsapi.Client() print(配置成功)如果运行没有报错说明环境和凭证都没问题。如果报错提及URL或key无法验证大概率是.cdsapirc文件里的内容格式有问题或者文件位置不对。注意新版CDS-Beta如果要求使用新的接入端点URL字段可能不同。一定以账号页面显示的URL为准不要照抄网上的教程。很多教程写的老URL在新版平台下会报404或401。3. 核心实操从构造请求到完成下载3.1 初始化客户端并理解数据目录环境准备好之后核心就是如何使用cdsapi发起数据请求。先初始化客户端import cdsapi client cdsapi.Client()如果不指定参数默认读取.cdsapirc配置。如果你把URL和Key硬编码在代码里也是可以的但不建议。接下来要对准数据目录。CDS的数据目录非常庞大但不是所有数据集都支持API请求每个数据集也有自己规定的参数模板。在页面搜索你想要的数据集比如ERA5单层再分析数据进入数据集详情页后点击“Download data”标签页你会看到一个可视化的筛选界面。这里有一个提高效率的技巧在这个界面上用鼠标点选你需要的变量、年份、月份、区域等条件随后点击页面底部的“Show API request”按钮它会自动生成一段完整的Python代码。这是新手学习参数格式最快的方式也是老手避免参数拼写错误最稳妥的兜底方案。3.2 一个标准下载请求的逐参数拆解拿到的API请求代码往往类似这样import cdsapi client cdsapi.Client() client.retrieve( reanalysis-era5-single-levels, { product_type: reanalysis, variable: [ 2m_temperature, total_precipitation ], year: 2020, month: 01, day: [ 01, 02, 03 ], time: 12:00, area: [ 60, 100, 20, 130 ], data_format: netcdf, download_format: unarchived }, download.nc )这就是一个完整的请求我来逐个参数解释。第一个参数是数据集名称reanalysis-era5-single-levels这是CDS目录中该数据集的唯一标识不能随意改动。第二个参数是一个字典包含具体的检索条件。product_type是产品类型ERA5分为reanalysis再分析和ensemble成员集合预报扰动等类型通常选reanalysis。variable是一个列表列出你要下载的变量。ERA5单层数据有上百个变量变量名有固定写法比如2米温度是2m_temperature总降水是total_precipitation海平面气压是mean_sea_level_pressure。常用的变量可以在数据集详情页的变量列表里查到也可以用官方API请求页面点选后自动生成。year、month、day、time定义时间范围。需要注意一个限制在单个API请求中时间维度的组合不能过大。比如你想下载10年的逐月数据推荐的做法是循环请求每年每月的数据而不是一次性申请所有年份。把多年份一次性放进year列表理论上可行但请求会长时间停留在队列中而且一旦失败整个大请求作废重试成本很高。area定义空间范围格式是按“北、西、南、东”顺序排列的四个坐标。这个顺序特别容易搞混。很多人下意识按“北东-南西”或“左上-右下”来填结果下载下来的数据区域完全不对。CDS要求的顺序是[N, W, S, E]即最大纬度、最小经度、最小纬度、最大经度。例如[60, 100, 20, 130]表示北纬20度到60度、东经100度到130度也就是中国中东部的大致范围。不填area字段时默认下载全球数据但全球数据文件体积大很多如果只需要特定区域务必加上。data_format是文件格式常用的是netcdf和grib。如果是用于Python科学计算xarray、pandas等建议选择netcdf因为netCDF文件在Python生态中读取极其方便。如果你是做数值模式同化或使用GRIB工具链才选择grib。新版平台还支持download_format: unarchived直接下载非压缩文件省去解压步骤但有些数据集并不支持该选项保持默认即可。第三个参数是本地保存的文件名。可以自由命名比如era5_2020_01.nc但建议与请求内容对应避免后续管理混乱。3.3 请求的状态流转与监听执行脚本后控制台会输出类似这样的日志2025-05-01 10:23:11,123 INFO Request ID: a1b2c3d4e5f6 2025-05-01 10:23:12,567 INFO Status: queued 2025-05-01 10:23:15,891 INFO Status: running ... 2025-05-01 10:24:30,102 INFO Downloading ...这说明请求已经进入服务器队列。CDS的机制是收到请求后检查参数合法性通过后进入排队queued等资源空闲后开始处理running处理完成后进入下载阶段。对于小请求可能几十秒就完成大请求等几个小时也不奇怪。有一点必须提醒API请求不是“发起即下载”的HTTP同步请求。你的Python进程会阻塞等待服务器处理完成并返回文件。因此如果你在服务器或远程机器上跑长批量任务建议使用nohup或screen/tmux等方式让脚本在后台运行防止SSH断开导致脚本中断。3.4 用“Show API request”生成代码再修改对新手来说最稳的方式不是从零写字典参数而是在数据集页面用鼠标筛选参数点击“Show API request”自动生成代码然后移植到自己的批量脚本中并做循环改造。这个做法有几个好处一是参数名称绝对正确比如变量、时间格式、区域字段名二是新版平台接口如果有变化页面生成的代码会跟随最新规范避免你看的教程和平台版本脱节。说实话CDS平台在2024到2025年经历了一轮迁移很多老教程里的细节已经过时紧跟页面提示是最省心的。4. 批量下载的工程化技巧4.1 按时间切片循环下载实际工作中很少有只需要单个文件的情况。比如你想下载ERA5-Land 2000年到2019年共20年的日降水数据一个请求搞定是不现实的。正确做法是按年循环每一年发一个请求有些场景甚至按月份循环。基本循环模板如下import cdsapi client cdsapi.Client() years [2000, 2001, 2002] months [01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12] for year in years: for month in months: filename fera5land_precip_{year}_{month}.nc client.retrieve( reanalysis-era5-land, { variable: total_precipitation, year: year, month: month, day: [f{d:02d} for d in range(1, 32)], time: 12:00, area: [60, 100, 20, 130], data_format: netcdf, }, filename ) print(f{year}-{month} 下载完成)这个脚本会依次提交240个请求。每个请求在CDS服务器上排队、处理、下载全部完成后再进入下一个。好处是逻辑简单请求之间互不影响某个文件下载失败可以单独重跑。坏处是如果队列等待时间长整体耗时可能很长。4.2 断点续传与重试机制批量下载最怕两个问题一是某个请求因为服务器错误或网络波动直接失败二是下载到一半连接断开文件残缺。cdsapi库在请求失败时会抛出异常而不是自动重试所以脚本需要自己加容错逻辑。我的经验是写一个带重试机制的包装函数import time import cdsapi def download_with_retry(client, dataset, params, filename, max_retries5): for attempt in range(max_retries): try: client.retrieve(dataset, params, filename) return True except Exception as e: print(f第{attempt1}次重试错误: {e}) time.sleep(5 * (attempt 1)) return False注意CDS可能因为请求频率过高返回错误重试间隔建议指数退避即每次重试等待时间递增。另外如果文件名已经存在且大小不为0可以在循环开头跳过import os if os.path.exists(filename) and os.path.getsize(filename) 0: print(f{filename} 已存在跳过) continue这样即使脚本跑了一半中断重新运行也能跳过已完成的部分省去重复下载的时间。4.3 并发控制与请求量估算很多人在批量下载时第一反应是“我要并行、我要多线程”。但CDS服务器对每个用户的并发请求数是有限制的同时挂太多请求反而会触发限流导致请求被拒绝或排队时间暴涨。老版CDS同时排队超过2个请求时会报错新版平台在此基础上还有更严格的限制。因此我不建议在批量下载时写复杂的并发代码。老老实实顺序执行加上断点续传是最稳的方案。如果你确实需要提高并行度建议最多开2到3个并发任务并且观察是否出现大量请求排队或报错据此调整。关于单次请求大小一个粗略估算方法ERA5全球网格约0.25度分辨率约1440×721个格点。单个变量、单小时、全球范围的数据大小可以这样估算1440×721×4字节float32约4MB一天24小时约96MB一年约35GB。注意这是单变量的量级如果多变量、多成员体积会成倍增加。请求前先估算文件大小能避免磁盘被写满的尴尬。4.4 下载完成后的数据校验下载完成不代表万事大吉。网络传输过程中文件是否完整、服务器生成的文件是否损坏都需要校验。最直接的方式是用xarray打开文件检查变量是否存在、维度是否正常import xarray as xr ds xr.open_dataset(era5land_precip_2000_01.nc) print(ds) print(ds[tp].shape)如果能正常打开且shape符合预期说明文件基本完整。如果打开时报错或维度不对就需要重新下载该文件。对于GRIB格式文件xarray需要安装cfgrib后端否则无法直接读取。如果你不熟悉cfgrib建议统一使用netCDF格式省去格式转换的麻烦。5. 常见问题与排查技巧实录5.1 问题速查表我把自己实际踩过、以及在社区里高频出现的报错整理成一张速查表错误/现象常见原因解决办法APIError: Invalid request请求参数拼写错误、变量名不存在用数据集页面“Show API request”生成代码对照修改KeyError: url或找不到key.cdsapirc文件不存在或位置不对检查文件是否在主目录文件名是否为.cdsapircrequests.exceptions.ConnectionError网络不稳定或CDS服务器繁忙加重试机制等待一段时间后再跑HTTP 400/401URL或Key配置错误从账号页面重新复制URL和Key请求一直在队列中请求范围过大或服务器繁忙拆分请求到按月/按年粒度减少并发下载到一半文件损坏网络中断、磁盘空间不足删除不完整文件重新下载该请求Cannot import name xarray等报错缺少依赖库安装对应依赖pip install xarray netcdf4打开GRIB文件报错缺少cfgribpip install cfgrib或改用netCDF格式下载5.2 一个我印象深刻的坑区域范围填错有次我帮一个课题组下载中国区域的ERA5土壤湿度数据脚本跑了一整天下载了十几个文件。最后用xarray打开一看数据的经度范围完全不对——跑到了大西洋上去。检查代码后发现area参数填成了[60, 130, 20, 100]我按了“北、东、南、西”的顺序填而CDS要求的是“北、西、南、东”。就这一个顺序错误整批文件全部作废重跑又花了一整天。后来我把这个顺序写成了一个常量注释贴在脚本头部再也没犯过这种低级错误。建议你也这样做# area 参数顺序为 [N, W, S, E]不是 [N, E, S, W] AREA_CHINA [60, 100, 20, 130]5.3 关于新旧平台切换前面反复提到CDS-Beta和新版平台这里展开说一下。ECMWF在近年将CDS迁移到新架构新用户在官网看到的默认界面已经是新版。新版平台的API接入URL、Key获取路径、部分参数格式都与老版有差异。最大的变化是老版平台的API Key是用户名长字符串新版则是在用户界面生成独立的API Key令牌。如果你的脚本之前用老版配置运行得很好现在突然报401认证错误多半是平台迁移导致的。解决方案就是登录新平台重新生成或复制API Key更新.cdsapirc文件。另外新版平台对某些数据集启用了更严格的“数据使用许可”确认。如果你在发起请求时收到类似“please accept the licences”的提示回到数据集详情页找到许可协议并点击接受即可。5.4 大文件下载中断怎么处理对于超大文件几GB到几十GB即使有重试机制也可能下载到90%时因网络波动中断。cdsapi的retrieve方法在下载阶段如果连接断开会抛出异常而且不支持断点续传。这意味着需要重新下载整个文件相当浪费时间。我这里提供一个变通方案利用CDS请求完成后的临时下载URL用curl或wget配合断点续传方式下载。cdsapi不仅支持直接下载到本地你还可以使用retrieve方法获取响应结果中的下载URL然后再用支持断点续传的工具下载。例如先获取所有请求的下载链接result client.retrieve(dataset, params) url result.download_url print(url)拿到URL后用系统命令下载wget -c 下载链接 -O filename.nc-c参数表示断点续传。不过需要注意CDS返回的临时下载链接有有效期过期后需要重新发请求获取所以这种方式更适合单文件特别大、直接下载频繁失败的场景。5.5 网络不稳定的应对策略如果你的网络环境不太稳定比如校园网、跨境网络批量下载时频繁断连的概率会明显增加。除了重试机制外还可以调整cdsapi的连接超时参数。新版cdsapi支持在Client()初始化时传入timeout参数或者在retrieve时指定max_retries。老版本没有这些参数时可以用requests库的Session和重试策略来自行定制。我自己最常用的做法还是分层处理用小请求月粒度批量下载加上断点续传逻辑。即使高峰期单日下载量不大至少每个文件都是独立的失败后重跑成本低不会出现“一损俱损”的尴尬场面。6. 一点个人经验和额外技巧6.1 把请求参数外部化批量下载脚本中数据集、变量、区域、时间范围这些参数经常需要调整。与其每次改代码不如把这些参数写在一个JSON配置文件里脚本只负责读取和循环。{ dataset: reanalysis-era5-single-levels, variable: [2m_temperature, total_precipitation], area: [60, 100, 20, 130], start_year: 2000, end_year: 2005 }脚本读取配置后生成请求。这样项目换人接手、换参数重跑时只需改配置文件不用动代码逻辑。6.2 注意CDS平台的公平使用原则最后提醒一下CDS虽然是免费开放平台但服务器资源有限。下载大规模数据时请尽量错峰执行避免在多人同时使用的高峰期提交超大请求。同时合理的请求粒度不仅是保护自己的时间也是在为整个社区着想。把请求拆成月粒度、控制并发数、下载完及时释放本地空间这些都是一个成熟数据使用者的基本素养。6.3 下载只是开始数据下载完成后紧接着的问题往往是格式转换、区域裁剪、时间重采样这些属于数据处理环节和下载同样重要。我个人的习惯是在写下载脚本时就把文件名规范好比如变量_区域_年份_月份.nc这样后续用xarray批量读取时可以通过文件名直接对应到时间和区域信息省去很多整理元数据的麻烦。ECMWF数据的下载是一个流程性问题把第一步做扎实了后面的处理才会顺畅。希望这篇总结能帮你少走一些弯路把时间留给真正重要的分析工作。
返回列表