目录
基于Python的ERA-5多线程下载分为两部分,《基于Python的ERA-5多线程下载 (1)》,直接再本地使用,即写代码的人使用;《基于Python的ERA-5多线程下载 (2)》使用 pyinsaller 将写好的程序,打包成 .exe 文件,以便其他人使用。
动机
恩师推荐,我的论文可以用到相关数据,然后就对相关数据下载方式调研,在这里做笔记!!!! 2024年10月20日,由于官网更新,所以对代码进行了重新调整。 后面贴的代码,我也同时上传到了到了我的 资源 中,.py文件,下载就可以用,只需关注就能下载(下载之后取消关注也无所谓)。 提示:以下是本篇文章正文内容,案例可供参考一、正文
基于Python的ERA-5多线程下载分为两部分,《基于Python的ERA-5多线程下载 (1)》,直接再本地使用,即写代码的人使用;《基于Python的ERA-5多线程下载 (2)》将会将写好的程序,打包成 .exe 文件,以便其他人使用。
1.注册账号
登录 cds.climate.copernicus.eu 网站注册账号。
2.登录账号,复制 url: 与 key:
登录账号后,访问 api-how-to 网页,复制 url: 与 key: 。
注意:如果显示 url:{} 、key: {} 为空,刷新界面;刷新后如果依然是空,网页右上角查看自己的账号是否是登录状态。
3.创建.cdsapirc本地文件
在本地,进入 C:\Users\Administrator 目录,右键创建空白.txt文件,将名字修改为为".cdsapirc",将第2.步网页复制的 url: {########}与 key:{#######}粘贴到.cdsapirc文件中,保存。(我下面的url 和 key 是错的,最新的是url是以/api 结尾)
注意:
在创建文.txt文件,修改文件名,需要确保”文件扩展名“是打开的,否则你创建的.cdsapirc文件的实际名字为".cdsapirc.txt",因为文件扩展名未打开,你看到的是".cdsapirc"。
此外,根据我的经验,感觉.cdsapirc相当于一个Cookies的文件,让服务器认为你一直处于登录状态,可能不对,但是你可以这么理解。
4.安装python环境
庆幸的是,ECMWF提供的cdsapi包,在python2.x与python3.x均可运行,所以大家就无需纠结python版本。我这里用的是python3.7(Anaconda-2019.10),大家自行安装python(Anaconda)版本就可,我的其他几篇博文中都有提到。
如果你原来安装过“cdsapi”
,那要注意了。最新的要求 cdsapi>=0.7.2
,所以需要更新。
pip install 'cdsapi>=0.7.2'
# 或
python -m pip insyall --upgrade cdsapi
5.安装cdsapi包
开始菜单—Anaconda3 (64-bit)—Anaconda Prompt (Anaconda3),执行以下代码:
如果将自己的python或者Anaconda已经加入环境变量后,直接通过"命令提示符"即 cmd,输入以下代码就可安装。
pip install cdsapi
6.复制脚本内容至本地
在本地创建空白文本(.txt)文件,复制python脚本内容(后面贴出)粘贴至空白文本,将 .txt 后缀改为 .py 后缀。
7.运行脚本,批量下载
开始菜单—Anaconda3 (64-bit)—Anaconda Prompt (Anaconda3),cd 到.py文件所在目录(如果不在c盘,需要再输入一次盘符,才能进入到目标目录中,如图)
8.修改参量,下载自己产品
大家可以根据自己的需求,调整自己的参数,主要调整参数有:
outDir、‘format’、‘variable’、begin、end
注:
变量名称,大家可以去产品页面,选择自己需要的产品,然后点击 ”show api request“ ,在代码中,将变量名称复制下来,替换自己的代码中 ‘variable’ 。如图:
二、更新后的最新python脚本
废话不多说:贴上我的脚本
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
@version: Anaconda
@author: LeYongkang
@contact: 1363989042@qq.com
@software: PyCharm
@file: ERA5_Download_Edit
@time: 2024/10/20 下午 9:23
"""
from queue import Queue
from threading import Thread
import cdsapi
from time import time
import datetime
import os
def downloadonefile(data):
ts = time()
outDir = r"D:\Download\mslp"
try:
os.makedirs(outDir)
except:
pass
filename=os.path.join(outDir,"era5.mslp."+data+".nc")
if(os.path.isfile(filename)): #如果存在文件名则返回
print("ok",filename)
else:
print(filename)
dataset = "reanalysis-era5-land"
request ={
"variable": [
"10m_u_component_of_wind",
"10m_v_component_of_wind",
"surface_pressure",
"total_precipitation"
],
# 其它变量名参见 https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels
'year' : data[0:4],
'month' : data[-4:-2],
'day' : data[-2:],
"time": [
"00:00", "01:00", "02:00",
"03:00", "04:00", "05:00",
"06:00", "07:00", "08:00",
"09:00", "10:00", "11:00",
"12:00", "13:00", "14:00",
"15:00", "16:00", "17:00",
"18:00", "19:00", "20:00",
"21:00", "22:00", "23:00"
],
"data_format": "netcdf",
"download_format": "unarchived"
}
client = cdsapi.Client()
client.retrieve(dataset, request, filename)# .download()
# 下载脚本
class DownloadWorker(Thread):
def __init__(self, queue):
Thread.__init__(self)
self.queue = queue
def run(self):
while True:
# 从队列中获取任务并扩展tuple
data = self.queue.get()
downloadonefile(data)
self.queue.task_done()
if __name__ == '__main__':
# 定义程序起始时间,下载结束后,根据结束时间计算共花费多长时间
ts = time()
# 定义下载数据的 起始日期
begin = datetime.date(2015,1,1)
# 定义下载数据的 结束日期
end = datetime.date(2015,3,31)
d = begin
delta = datetime.timedelta(days=1)
#建立下载日期序列
links = []
while d <= end:
data=d.strftime("%Y%m%d")
links.append(str(data))
d += delta
# 创建一个主进程与工作进程通信
queue = Queue()
# 创建四个工作线程
for x in range(4):
worker = DownloadWorker(queue)
#将daemon设置为True将会使主线程退出,即使所有worker都阻塞了
worker.daemon = True
worker.start()
# 将任务以tuple的形式放入队列中
for link in links:
queue.put((link))
# 让主线程等待队列完成所有的任务
queue.join()
print('Took Time:{}'.format(time() - ts))
三、旧python脚本(大家可以对比差异)
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
@version: Anaconda
@author: LeYongkang
@contact: 1363989042@qq.com
@software: PyCharm
@file: ERA5_Download_Edit
@time: 2021/1/20 0020 下午 9:23
"""
from queue import Queue
from threading import Thread
import cdsapi
from time import time
import datetime
import os
def downloadonefile(data):
ts = time()
outDir = r"E:\python\python3_64b\ERA-5\mslp"
try:
os.makedirs(outDir)
except:
pass
filename=os.path.join(outDir,"era5.mslp."+data+".grib")
if(os.path.isfile(filename)): #如果存在文件名则返回
print("ok",filename)
else:
print(filename)
c = cdsapi.Client()
c.retrieve(
'reanalysis-era5-land',
{
'product_type' : 'reanalysis',
'format' : 'grib', # Supported format: grib and netcdf. Default: grib
# 需要下载的变量产品名称
'variable': ['skin_temperature', 'surface_thermal_radiation_downwards',],
# 其它变量名参见 https://cds.climate.copernicus.eu/cdsapp#!/dataset/reanalysis-era5-single-levels
'year' : data[0:4],
'month' : data[-4:-2],
'day' : data[-2:],
'time':[
'00:00','01:00','02:00',
'03:00','04:00','05:00',
'06:00','07:00','08:00',
'09:00','10:00','11:00',
'12:00','13:00','14:00',
'15:00','16:00','17:00',
'18:00','19:00','20:00',
'21:00','22:00','23:00'
], #<---注意此逗号,不选择区域和分辨率需要去掉!
# 'area' : [60, -10, 50, 2], # North, West, South, East. Default: global
# 'grid' : [1.0, 1.0], # Latitude/longitude grid: east-west (longitude) and north-south resolution (latitude). Default: 0.25 x 0.25
},
filename)
# 下载脚本
class DownloadWorker(Thread):
def __init__(self, queue):
Thread.__init__(self)
self.queue = queue
def run(self):
while True:
# 从队列中获取任务并扩展tuple
data = self.queue.get()
downloadonefile(data)
self.queue.task_done()
if __name__ == '__main__':
# 定义程序起始时间,下载结束后,根据结束时间计算共花费多长时间
ts = time()
# 定义下载数据的 起始日期
begin = datetime.date(2015,1,1)
# 定义下载数据的 结束日期
end = datetime.date(2018,12,31)
d = begin
delta = datetime.timedelta(days=1)
#建立下载日期序列
links = []
while d <= end:
data=d.strftime("%Y%m%d")
links.append(str(data))
d += delta
# 创建一个主进程与工作进程通信
queue = Queue()
# 注意,每个用户同时最多接受4个
# 参考:request https://cds.climate.copernicus.eu/vision
# 创建四个工作线程
for x in range(4):
worker = DownloadWorker(queue)
#将daemon设置为True将会使主线程退出,即使所有worker都阻塞了
worker.daemon = True
worker.start()
# 将任务以tuple的形式放入队列中
for link in links:
queue.put((link))
# 让主线程等待队列完成所有的任务
queue.join()
print('Took Time:{}'.format(time() - ts))
四、引用
虽然代码不多,但是以我的能力不可能独立完成,90%参考,然后根据我的代码习惯(比如说不经常使用main(文件))稍微修改了一下下:
https://mp.weixin.qq.com/s/lOQ_6s8grFSY3TU6XcnO8w
https://github.com/jiangleads/Get_ECMWF_Data
感谢几位博主的贡献!!!
五、结语
最新结语: 时隔4年,我也不再是渣渣了。虽然现在还是比不上大佬,但是对比第一次的“一知半解”,所有代码可以在不做参考的情况下写出来,也是一大提升。最近开始学习多进程、多线程的方法来提升代码效率。大家可以关注我的公众号“遥感派”,知道更多最新的分享。
第一次写的结语:我也只是个渣渣,是代码搬运工;这个博文我感觉写的很细,把我最初接触代码的遇到的问题全部都贴上了,希望仔细每一个按照我流程走下来的人,都能得到正确的结果。
最后,其实我参考的博文、GitHub都是我老师给我发过来的,我只是整理了下,走通而已,这么好的老师哪里找。