近期因师弟师妹抱怨下数据太慢,我搜索一通发现了这个库,虽然说并不是再分析场数据下载,但预报场估计也是大有需求,于是写了这篇教程
ecmwf-opendata 是由 ECMWF(欧洲中期天气预报中心)官方维护的 Python 包,用于简化从 ECMWF Open Data 实时下载全球数值预报数据。
param、levelist、step 等参数只下载需要的部分,避免整文件 726 GiB/天的全量传输数据来源:ECMWF Open Data 采用 CC BY 4.0 许可。
IFS 和 AIFS 都能拉。
!pip install ecmwf-opendata -i https://pypi.mirrors.ustc.edu.cn/simple/
Looking in indexes: https://pypi.mirrors.ustc.edu.cn/simple/
Collecting ecmwf-opendata
Downloading https://mirrors.ustc.edu.cn/pypi/packages/6a/2a/b2a925b4e2830901f6e9064b90892eb3aba4b4ca8564bbaa5acc18666727/ecmwf_opendata-0.3.29-py3-none-any.whl (22 kB)
Collecting multiurl>=0.2.1 (from ecmwf-opendata)
Downloading https://mirrors.ustc.edu.cn/pypi/packages/93/cf/be4e93afbfa0def2cd6fac9302071db0bd6d0617999ecbf53f92b9398de3/multiurl-0.3.7-py3-none-any.whl (21 kB)
Requirement already satisfied: requests in /opt/conda/lib/python3.11/site-packages (from multiurl>=0.2.1->ecmwf-opendata) (2.32.3)
Requirement already satisfied: tqdm in /opt/conda/lib/python3.11/site-packages (from multiurl>=0.2.1->ecmwf-opendata) (4.67.0)
Requirement already satisfied: pytz in /opt/conda/lib/python3.11/site-packages (from multiurl>=0.2.1->ecmwf-opendata) (2024.1)
Requirement already satisfied: python-dateutil in /opt/conda/lib/python3.11/site-packages (from multiurl>=0.2.1->ecmwf-opendata) (2.9.0.post0)
Requirement already satisfied: six>=1.5 in /opt/conda/lib/python3.11/site-packages (from python-dateutil->multiurl>=0.2.1->ecmwf-opendata) (1.17.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /opt/conda/lib/python3.11/site-packages (from requests->multiurl>=0.2.1->ecmwf-opendata) (3.4.0)
Requirement already satisfied: idna<4,>=2.5 in /opt/conda/lib/python3.11/site-packages (from requests->multiurl>=0.2.1->ecmwf-opendata) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/conda/lib/python3.11/site-packages (from requests->multiurl>=0.2.1->ecmwf-opendata) (2.2.3)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.11/site-packages (from requests->multiurl>=0.2.1->ecmwf-opendata) (2024.12.14)
Installing collected packages: multiurl, ecmwf-opendata
Successfully installed ecmwf-opendata-0.3.29 multiurl-0.3.7
Client 是唯一的入口类,构造时可指定数据来源、模型和分辨率等。
参数 | 默认值 | 说明 |
|---|---|---|
source | "ecmwf" | 数据源:ecmwf(官方)、aws(亚马逊云)、google(谷歌云)、azure(微软云) |
model | "ifs" | 模型:ifs(物理驱动)、aifs-single(数据驱动单成员)、aifs-ens(数据驱动集合) |
resol | "0p25" | 分辨率,目前仅支持 0.25°(约 25 km) |
preserve_request_order | False | 是否按请求顺序写入字段;设为 True 会增加服务端负载,建议仅在字段较少时使用 |
infer_stream_keyword | True | 是否自动推断 stream(预报系统)参数 |
提示:
source="ecmwf"有 500 个并发连接限制,如遇下载困难可切换到aws/azure。
from ecmwf.opendata import Client
client = Client(source="aws")
client.retrieve(
type="fc",
param="msl",
step=24,
target="data.grib2",
)
20260603180000-24h-oper-fc.grib2: 0%| | 0.00/515k [00:00<?, ?B/s]
By downloading data from the ECMWF open data dataset, you agree to the terms: Attribution 4.0 International (CC BY 4.0). Please attribute ECMWF when downloading this data.
<ecmwf.opendata.client.Result at 0x7f4ba55bbbd0>
retrieve() 核心参数速查参数 | 是否必填 | 说明 |
|---|---|---|
type | ✅ | 数据类型:fc(预报)、cf(控制预报)、pf(扰动预报)、em(集合平均)、es(集合标准差)、ep(概率产品)、tf(热带气旋路径) |
param | — | 气象参数,如 msl、2t、gh、t、u、v 等;不写则下载全部参数 |
step | — | 预报时效(小时),如 24、[24, 48];不写则下载全部时效 |
date | — | 起报日期,支持 20220125、'2022-01-25'、datetime 对象;不写默认最新 |
time | — | 起报时次,支持 0、6、12、18;不写默认最新 |
levtype | — | 层次类型:sfc(单层面)、pl(等压面);不写自动推断 |
levelist | — | 等压面层列表,如 500、[500, 850];不写则下载全部层 |
stream | — | 预报系统:oper(HRES 00/12)、scda(HRES 06/18)、enfo(ENS)、wave(海浪);infer_stream_keyword=True 时自动推断 |
number | — | 集合成员编号,如 1、[1, 10, 20];不写则下载全部成员 |
target | ✅ | 本地保存路径(GRIB2 或 BUFR 格式) |
retrieve() 返回一个结果对象,可通过 result.datetime 获取实际下载数据的起报时间。
import xarray as xr
ds = xr.open_dataset("data.grib2", engine="cfgrib")
print(ds)
<xarray.Dataset> Size: 4MB
Dimensions: (latitude: 721, longitude: 1440)
Coordinates:
time datetime64[ns] 8B ...
step timedelta64[ns] 8B ...
meanSea float64 8B ...
* latitude (latitude) float64 6kB 90.0 89.75 89.5 ... -89.5 -89.75 -90.0
* longitude (longitude) float64 12kB -180.0 -179.8 -179.5 ... 179.5 179.8
valid_time datetime64[ns] 8B ...
Data variables:
msl (latitude, longitude) float32 4MB ...
Attributes:
GRIB_edition: 2
GRIB_centre: ecmf
GRIB_centreDescription: European Centre for Medium-Range Weather Forecasts
GRIB_subCentre: 0
Conventions: CF-1.7
institution: European Centre for Medium-Range Weather Forecasts
history: 2026-06-04T13:26 GRIB to CDM+CF via cfgrib-0.9.1...
param、levelist、step 都支持传入列表,一次请求即可打包下载多个字段。
client = Client(source="aws")
result = client.retrieve(
type="fc",
param=["gh", "t"],
levelist=[500, 850],
step=[24, 48],
target="gh_t_500_850.grib2",
)
print("起报时间:", result.datetime)
<multiple>: 0%| | 0.00/4.01M [00:00<?, ?B/s]
起报时间: 2026-06-03 18:00:00
ds_multi = xr.open_dataset("gh_t_500_850.grib2", engine="cfgrib")
print(ds_multi)
<xarray.Dataset> Size: 33MB
Dimensions: (step: 2, isobaricInhPa: 2, latitude: 721, longitude: 1440)
Coordinates:
time datetime64[ns] 8B ...
* step (step) timedelta64[ns] 16B 1 days 2 days
* isobaricInhPa (isobaricInhPa) float64 16B 850.0 500.0
* latitude (latitude) float64 6kB 90.0 89.75 89.5 ... -89.5 -89.75 -90.0
* longitude (longitude) float64 12kB -180.0 -179.8 -179.5 ... 179.5 179.8
valid_time (step) datetime64[ns] 16B ...
Data variables:
gh (step, isobaricInhPa, latitude, longitude) float32 17MB ...
t (step, isobaricInhPa, latitude, longitude) float32 17MB ...
Attributes:
GRIB_edition: 2
GRIB_centre: ecmf
GRIB_centreDescription: European Centre for Medium-Range Weather Forecasts
GRIB_subCentre: 0
Conventions: CF-1.7
institution: European Centre for Medium-Range Weather Forecasts
history: 2026-06-04T13:30 GRIB to CDM+CF via cfgrib-0.9.1...
参数 | 说明 | 单位 |
|---|---|---|
2t | 2 米温度 | K |
msl | 海平面气压 | Pa |
sp | 地面气压 | Pa |
10u | 10 米 U 风 | m/s |
10v | 10 米 V 风 | m/s |
tp | 总降水量 | m |
tcwv | 整层可降水量 | kg/m² |
skt | 地表温度 | K |
参数 | 说明 | 单位 |
|---|---|---|
gh | 位势高度 | gpm |
t | 温度 | K |
u | U 风 | m/s |
v | V 风 | m/s |
q | 比湿 | kg/kg |
r | 相对湿度 | % |
vo | 涡度 | s⁻¹ |
d | 散度 | s⁻¹ |
参数 | 说明 | 单位 |
|---|---|---|
swh | 有效波高 | m |
mwp | 平均波周期 | s |
pp1d | 峰值波周期 | s |
mwd | 平均波向 | ° |
预报系统 | 时次 | 预报时效范围 | 步长 |
|---|---|---|---|
HRES (IFS) | 00, 12 | 0–144 h | 3 h |
HRES (IFS) | 00, 12 | 144–240 h | 6 h |
HRES (IFS) | 06, 18 | 0–90 h | 3 h |
ENS (IFS) | 00, 12 | 0–144 h | 3 h |
ENS (IFS) | 00, 12 | 144–360 h | 6 h |
ENS (IFS) | 06, 18 | 0–144 h | 3 h |
提示:数据一般在起报后 7–9 小时 才可在 Open Data 中访问,取决于预报系统和时效。
同一个接口,换一个 model 参数即可切换 IFS 与 AIFS。
# IFS
client_ifs = Client(source="aws", model="ifs")
client_ifs.retrieve(
type="fc", param="msl",
step=24,
target="ifs_msl.grib2",
)
# AIFS
client_aifs = Client(source="aws", model="aifs-single")
client_aifs.retrieve(
type="fc", param="msl",
step=24,
target="aifs_msl.grib2",
)
20260603180000-24h-oper-fc.grib2: 0%| | 0.00/515k [00:00<?, ?B/s]
20260604000000-24h-oper-fc.grib2: 0%| | 0.00/471k [00:00<?, ?B/s]
<ecmwf.opendata.client.Result at 0x7f4acc9bff90>
import os
ifs_size = os.path.getsize("ifs_msl.grib2")
aifs_size = os.path.getsize("aifs_msl.grib2")
print(f"IFS: {ifs_size / 1024:.1f} KB")
print(f"AIFS: {aifs_size / 1024:.1f} KB")
IFS: 514.8 KB
AIFS: 470.9 KB
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import numpy as np
import xarray as xr
# # 下载数据
client = Client(source="aws", model="aifs-single")
client.retrieve(type="fc", param="gh", levelist=500, step=24, target="aifs_gh500.grib2")
client.retrieve(type="fc", param="msl", step=24, target="aifs_msl.grib2")
# 读取
gh = xr.open_dataset("aifs_gh500.grib2", engine="cfgrib")["gh"]
msl = xr.open_dataset("aifs_msl.grib2", engine="cfgrib")["msl"]
# 画图
proj = ccrs.PlateCarree(central_longitude=110)
fig, ax = plt.subplots(figsize=(12, 8), subplot_kw={"projection": proj})
ax.set_extent([70, 140, 15, 55], crs=ccrs.PlateCarree())
ax.add_feature(cfeature.COASTLINE, linewidth=0.8)
# ax.add_feature(cfeature.BORDERS, linewidth=0.4, alpha=0.5)
# 位势高度等值线
levels = np.arange(5000, 6000, 40)
cs = ax.contour(
gh.longitude, gh.latitude, gh.squeeze() / 10,
levels=levels, colors="black", linewidths=1.0,
transform=ccrs.PlateCarree(),
)
ax.clabel(cs, inline=True, fontsize=8, fmt="%d")
# 海平面气压填色
msl_hpa = msl.squeeze() / 100
cf = ax.contourf(
msl.longitude, msl.latitude, msl_hpa,
levels=np.arange(960, 1050, 5),
cmap="RdBu_r", alpha=0.4,
transform=ccrs.PlateCarree(),
)
plt.colorbar(cf, ax=ax, label="MSL (hPa)", shrink=0.7)
ax.set_title(
"AIFS 500hPa Geopotential + MSL\n"
f"Init: {gh.time.values.astype('datetime64[h]').tolist()} "
f"Step: +24h"
)
plt.tight_layout()
plt.savefig("aifs_500hpa_forecast.png", dpi=150)
plt.show()

output
Client.latest() 只查询服务器上最新数据的时间,不执行下载,适合在自动化脚本中判断数据是否已上线。
from ecmwf.opendata import Client
client = Client(source="aws")
latest = client.latest(type="fc", param="msl", step=24)
print("最新可用起报时间:", latest)
Client.download() 与 retrieve() 参数相同,但会忽略 param、levelist、number 等子集参数,直接下载整文件。当你需要下载大部分字段时,整文件下载效率更高。
注意:整天的完整数据约 726 GiB,请谨慎使用。
client = Client(source="aws")
# 仅按 date/time/step/type 定位文件,忽略 param 等子集参数
client.download(
type="fc",
step=24,
target="full_file.grib2",
)
ECMWF 集合预报提供 50 个扰动成员 + 1 个控制成员。使用 stream="enfo"、type="pf"(扰动)或 "cf"(控制),并通过 number 指定成员编号。
# 下载控制成员
client = Client(source="aws")
client.retrieve(
stream="enfo",
type="cf",
step=24,
param="msl",
target="ens_cf_msl.grib2",
)
# 下载第 1、3、5… 奇数成员
client.retrieve(
stream="enfo",
type="pf",
step=24,
param="msl",
number=[num for num in range(1, 51, 2)],
target="ens_pf_msl.grib2",
)
retrieve() 也支持将请求打包为字典传入,方便在配置文件中管理下载任务。
client = Client(source="aws")
request = {
"type": "fc",
"step": [24, 48, 72],
"param": ["2t", "msl"],
}
client.retrieve(request, target="dict_request.grib2")
实际体验下来排队倒是不用排,aws源速度挺慢的,也可能有网络差异,
不论如何这也算是ec排队时间过长下的一种选择