如何用Siphon循环批量下载2020-2022年GFS数据及解决连接错误
问题排查与解决方案
错误原因分析
- 请求频率超限:你设置的
time.sleep(0.01)间隔过短,RDA.UCAR.EDU服务器存在请求频率限制,短时间内大量请求会被服务器主动断开连接,触发RemoteDisconnected错误。 - 循环逻辑错误:当前循环顺序为
时效i→日期day→月份month,会引发两个问题:一是生成不存在的日期(比如2月30日),请求无效的目录链接;二是重复创建目录,冗余操作增加服务器交互次数。 - 缺少异常处理与重试机制:未捕获连接类异常,单次连接失败就直接终止脚本,没有重试机会。
- 资源未及时释放:下载后打开的xarray数据集未显式关闭,长期运行可能引发资源泄漏,间接影响网络连接稳定性。
修复后的代码
from siphon.catalog import TDSCatalog from siphon.ncss import NCSS import numpy as np import ipywidgets as widgets from datetime import datetime, timedelta import xarray as xr from netCDF4 import num2date import os import time from requests.exceptions import ConnectionError, RemoteDisconnected # 下载GFS子集 - 辐射(6小时平均)和行星边界层高度 def download_gfs_data(year, month, day, fhour): dir_out = f'/home/william/GFS_Siphon/{year}{month:02d}' os.makedirs(dir_out, exist_ok=True) file_path = f'{dir_out}/gfs.0p25.{year}{month:02d}{day:02d}00.f{fhour:03d}.nc' if os.path.isfile(file_path): print(f"文件已存在,跳过: {file_path}") return cat_url = f"https://rda.ucar.edu/thredds/catalog/files/g/ds084.1/{year}/{year}{month:02d}{day:02d}/catalog.xml" dataset_name = f'gfs.0p25.{year}{month:02d}{day:02d}00.f{fhour:03d}.grib2' # 重试机制,最多3次 max_retries = 3 for attempt in range(max_retries): try: time.sleep(2) # 延长请求间隔,避免触发频率限制 catalog = TDSCatalog(cat_url) ds = catalog.datasets[dataset_name] ncss = ds.subset() query = ncss.query() query.lonlat_box(east=-30, west=-50, south=-20, north=0) query.variables( 'Downward_Short-Wave_Radiation_Flux_surface_6_Hour_Average', 'Planetary_Boundary_Layer_Height_surface').add_lonlat() query.accept('netcdf4') nc = ncss.get_data(query) # 显式关闭资源 with xr.open_dataset(xr.backends.NetCDF4DataStore(nc)) as data: data.to_netcdf(file_path) print(f"下载完成: {file_path}") return except (ConnectionError, RemoteDisconnected) as e: print(f"连接失败,第{attempt+1}次重试: {str(e)}") time.sleep(5) # 重试前等待更长时间 except KeyError: print(f"数据集不存在: {dataset_name},跳过") return print(f"重试{max_retries}次后仍失败,放弃: {file_path}") # 遍历2020-2022年,UTC00时次,时效3-168小时 for year in range(2020, 2023): for month in range(1, 13): # 获取当月最后一天,避免无效日期 last_day = (datetime(year, month, 1) + timedelta(days=32)).replace(day=1) - timedelta(days=1) for day in range(1, last_day.day + 1): for fhour in range(3, 169, 6): download_gfs_data(year, month, day, fhour)
关键修复点
- 调整循环顺序:改为
年→月→日→时效,同时计算当月最后一天,避免请求不存在的日期目录。 - 延长请求间隔:将
time.sleep(0.01)改为time.sleep(2),降低请求频率,符合服务器限制。 - 添加重试机制:针对连接类异常最多重试3次,重试前等待更长时间,提升成功率。
- 资源管理:使用
with语句自动关闭xarray数据集,避免资源泄漏。 - 存在性检查优化:用
os.makedirs(exist_ok=True)简化目录创建逻辑,跳过已存在的文件。
内容的提问来源于stack exchange,提问作者William Jacondino
相关产品推荐
相关产品推荐

