关注公众号,分享GIS知识、ArcGIS教程、SCI论文与科研日常等
关于
之前提到一个下载MODIS数据的网站,在这篇博客。不过该网站没有MOD06,MOD07,MOD03等产品。这些2级产品和3级产品命名不同,而且没有固定的行列号(文件名里面没有位置信息)。以MOD06_L2产品为例(来自官网MOD06产品指导手册):
这个名字里面并没有行列好信息(hxvx),实际上,连位置信息都没有。我自己也在官网上检索了很多数据并观察了他们的命名,还是没发现什么规律,同一个地点的数据filename好像没有固定不变的部分。
先说怎么在官网上下载:访问这个网站,就可以检索你需要的数据,数据量少的话也是可以一个个下载,不过,数据量大的情况下这样就显得很呆。下面是检索和下载数据的页面
同样,官网提供了批量下载的方法,看这个页面
这里我就把python的方法贴出来了,稍作改动,实现批量下载。在使用这个代码前你需要知道的几点:
1 提前准备
下载的核心函数:sync(src, dest, tok),需要指定下载源,下载到本地的位置,和令牌。
令牌需要登陆-profile-然后生成app keys即可。
2 下载源
数据从这个站点下载,界面如下:
首先要找到自己下载的数据在哪个位置,例如要下载MOD06_L2,他在:
https://ladsweb.modaps.eosdis.nasa.gov/archive/allData/61/MOD06_L2/,再下一级文件夹为year/DOY,DOY下才是hdf文件,DOY为儒略日,下面的代码也给了如何将年月日转为儒略日。
3 想下载特定地方的数据
时间和位置是下载数据的两大筛选条件,时间由于官网良好的数据组织也很好实现。但是最后一级文件夹下是当天的全球数据,而且文件名本身不包含位置信息,观察一下也没发现同一位置的文件有什么相同的部分(据我观察)。所以代码实现上走了其他路。
首先再官网的search页面筛选出来我们需要的数据,筛选后下载下来包含所有数据条目的csv或json文件,然后程序中从下载的文件中获取所有数据条目,下载时做个判断即可。
4 提交订单下载
除此之外,也可以向官网提交订单,官网会发送一个URL到邮件,这个url就可以用来下载筛选的数据。上图第五步为提交订单。需要5分钟到10天的审核期。
python代码
说明:python代码在官网提供的下载代码基础上进行的修改
from __future__ import (division, print_function, absolute_import, unicode_literals)
import os
import os.path
import shutil
import sys
try:
from StringIO import StringIO # python2
except ImportError:
from io import StringIO # python3
USERAGENT = 'tis/download.py_1.0--' + sys.version.replace('\n','').replace('\r','')
def geturl(url, token=None, out=None):
headers = { 'user-agent' : USERAGENT }
if not token is None:
headers['Authorization'] = 'Bearer ' + token
try:
import ssl
CTX = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
if sys.version_info.major == 2:
import urllib2
try:
fh = urllib2.urlopen(urllib2.Request(url, headers=headers), context=CTX)
if out is None:
return fh.read()
else:
shutil.copyfileobj(fh, out)
except urllib2.HTTPError as e:
print('HTTP GET error code: %d' % e.code(), file=sys.stderr)
print('HTTP GET error message: %s' % e.message, file=sys.stderr)
except urllib2.URLError as e:
print('Failed to make request: %s' % e.reason, file=sys.stderr)
return None
else:
from urllib.request import urlopen, Request, URLError, HTTPError
try:
fh = urlopen(Request(url, headers=headers), context=CTX)
if out is None:
return fh.read().decode('utf-8')
else:
shutil.copyfileobj(fh, out)
except HTTPError as e:
print('HTTP GET error code: %d' % e.code(), file=sys.stderr)
print('HTTP GET error message: %s' % e.message, file=sys.stderr)
except URLError as e:
print('Failed to make request: %s' % e.reason, file=sys.stderr)
return None
except AttributeError:
# OS X Python 2 and 3 don't support tlsv1.1+ therefore... curl
import subprocess
try:
args = ['curl', '--fail', '-sS', '-L', '--get', url]
for (k,v) in headers.items():
args.extend(['-H', ': '.join([k, v])])
if out is None:
# python3's subprocess.check_output returns stdout as a byte string
result = subprocess.check_output(args)
return result.decode('utf-8') if isinstance(result, bytes) else result
else:
subprocess.call(args, stdout=out)
except subprocess.CalledProcessError as e:
print('curl GET error message: %' + (e.message if hasattr(e, 'message') else e.output), file=sys.stderr)
return None
################################################################################
"""
"""
DESC = "This script will recursively download all files if they don't exist from a LAADS URL and stores them to the specified path"
def sync(src, dest, tok):
'''synchronize src url with dest directory'''
try:
import csv
files = [ f for f in csv.DictReader(StringIO(geturl('%s.csv' % src, tok)), skipinitialspace=True) ]
except ImportError:
import json
files = json.loads(geturl(src + '.json', tok))
# use os.path since python 2/3 both support it while pathlib is 3.4+
items = getItems(r'D:\User Files\caishuohao\MOD07\downloadfile\heihe_mod06l2_mod03_mod04.csv')
for f in files:
# currently we use filesize of 0 to indicate directory
filesize = int(f['size'])
path = os.path.join(dest, f['name'])
url = src + '/' + f['name']
if filesize == 0:
try:
print('creating dir:', path)
os.mkdir(path)
sync(src + '/' + f['name'], path, tok)
except IOError as e:
print("mkdir `%s': %s" % (e.filename, e.strerror), file=sys.stderr)
sys.exit(-1)
else:
try:
if not os.path.exists(path) and f['name'] in items:
print('downloading: ', path)
with open(path, 'w+b') as fh:
geturl(url, tok, fh)
else:
print('skipping: ', path)
except IOError as e:
print("open `%s': %s" % (e.filename, e.strerror), file=sys.stderr)
sys.exit(-1)
return 0
def date2julian(year, month, day):
hour = 10
JD0 = int(365.25 * (year - 1)) + int(30.6001 * (1 + 13)) + 1 + hour / 24 + 1720981.5
if month <= 2:
JD2 = int(365.25 * (year - 1)) + int(30.6001 * (month + 13)) + day + hour / 24 + 1720981.5
else:
JD2 = int(365.25 * year) + int(30.6001 * (month + 1)) + day + hour / 24 + 1720981.5
DOY = JD2 - JD0 + 1
return int(DOY)
def getItems(filename):
f = open(filename, 'r')
f.readline() #读掉表头
items = []
while True:
itemstr = f.readline()
if itemstr == '':
break
items.append(itemstr.split(',')[1].split('/')[7])
return items
if __name__ == '__main__':
destination = r'D:\User Files\caishuohao\MOD07'
urlPsth_MOD06 = r'https://ladsweb.modaps.eosdis.nasa.gov/archive/allData/61/MOD06_L2'
startDoy = date2julian(2019, 7, 1)
endDoy = date2julian(2019, 9, 1)
for doy in range(startDoy, endDoy):
sync(urlPsth_MOD06 + '/2019/' + str(doy) + '/', destination, '你的TOKEN')
MODIS数据处理
MOD06,MOD07等产品,处理起来更麻烦,MRT无法识别。这里提供一个很好用的ENVI插件工具:MODIS Coversion Toolkit,GitHub上可以免费下载
指导书很详细,可以界面,也可以IDL编程批量处理,指导书上都有代码示例。现有的MODIS数据基本都可以处理
(感谢大神的开源项目,前人栽树,后人乘凉,我们搞研究的目的大概也是为后人栽一棵树吧)