找了一圈下modis数据的,有的不能空间筛选有的不能下初级产品(也可能没找到),不甚满意,自己搞了个
0 前言
- 用到的主要依赖是selenium,下载网站是https://ladsweb.modaps.eosdis.nasa.gov,环境是anaconda,python 3.9.12
- 因为涉及html解析,若该网站结构变了,可能就得修改
- 网站的#Online Archive里可以实现产品和日期筛选,但是不知道怎么进行空间筛选 ,如果可以的话能省很多事
1 安装selenium
需要的主要依赖是selenium,这个库用来模拟浏览器操作。该库的介绍见
https://blog.csdn.net/benzhujie1245com/article/details/117089767
除了库本身,使用它还需要
- 电脑安装了浏览器
- 安装对应的WebDriver
浏览器我用的chrome,以此为例。WebDriver的下载地址是
http://chromedriver.storage.googleapis.com/index.html
将下载的压缩包解压,exe文件找个地方放好就行了
2 注册账号获取token
地址是
https://urs.earthdata.nasa.gov/users/new
注册之后在搜索页右上角可以看token
3 下载脚本
import os
import shutil
import sys
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
import time
USERAGENT = 'tis/download.py_1.0--' + sys.version.replace('\n', '').replace('\r', '')
def geturl(url, out):
"""
根据url下载文件
:param url: 地址
:param out: 存储路径
:return:
"""
headers = {'user-agent': USERAGENT, 'Authorization': 'Bearer ' + token}
import ssl
CTX = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
from urllib.request import urlopen, Request
fh = urlopen(Request(url, headers=headers), context=CTX)
shutil.copyfileobj(fh, out)
def init(url, chrome_driver):
"""
初始化页面解析
:param url: 网页地址
:param chrome_driver: 浏览器驱动地址
"""
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
browser = webdriver.Chrome(executable_path=chrome_driver, chrome_options=chrome_options)
# 设置隐式等待时间,等待页面完整加载,最长等待 60s
browser.implicitly_wait(60)
browser.get(url)
try:
# 等待下载标签加载,最长60s
elements = WebDriverWait(browser, 60).until(
EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#tab4FilesTable a")))
wait_a_list(0, len(elements), browser)
finally:
browser.quit()
def wait_a_list(times, len_a_list, browser):
"""
递归等待下载标签全部加载
:param times: 循环累计次数
:param len_a_list: 下载标签长度
:param browser: browser
"""
# 强制等待 2s 后再执行下一步
time.sleep(2)
elements = browser.find_elements(By.CSS_SELECTOR, "#tab4FilesTable a")
if len(elements) == len_a_list:
times += 1
if times == 5:
print('等待5次,长度不变,输出最终')
for my_elem in elements:
url = my_elem.get_attribute("href")
file_name = url.split('/')[-1]
path = os.path.join(save_dir, file_name)
if not os.path.exists(path):
print('downloading: ', path)
with open(path, 'w+b') as fh:
geturl(url, fh)
else:
print('skipping: ', path)
else:
print('长度不变,循环次数:' + str(times))
wait_a_list(times, len_a_list, browser)
else:
print('长度重置,现在长度:' + str(len(elements)))
wait_a_list(0, len(elements), browser)
if __name__ == '__main__':
# token https://ladsweb.modaps.eosdis.nasa.gov/ 注册后获取
# 如果不设置token,下下来的会是一个让你登录的html页面。。
token = '你的token'
# 存储路径
save_dir = './dataDirectModis'
# 下载地址
_url = 'https://ladsweb.modaps.eosdis.nasa.gov/search/order/4/MOD021KM--61/2023-01-17..2023-01-18/DB/Country:CHN'
# selenium的chromedriver驱动地址
_chrome_driver = 'D:/Program Files/chromedriver.exe'
init(_url, _chrome_driver)
4 脚本解释
4.1 下载地址
下载地址是按照LAADS网站一步步查询拼出来的
筛选主要分四步,这里简单介绍。如果你一步步筛选到第四步,你会发现之前的筛选项都体现在了url里。
-
产品
就上图那些,左边是分类,右边是具体的产品,可多选 -
时间
都很明了,不多说了 -
空间
-
文件
根据上述选择列出的所有文件。手动下载的话,这里就可以选择然后进入第五步了。
再看一下代码里这一段
# 下载地址
_url = 'https://ladsweb.modaps.eosdis.nasa.gov/search/order/4/MOD021KM--61/2023-01-17..2023-01-18/DB/Country:CHN'
明显看出刚才的选项都体现在了url里。拿页面上的url来看
大家可以在第三步换不同的空间筛选种类试试。矩形的话就是两个坐标,国家的话就是国家代码。
4.2 页面解析
进行到第四步,出现的表格就已经可以直接下载了
写个脚本,读出表格,点击下载,岂不轻轻松松
然而问题是,页面加载本身就不快,然后表格是页面元素渲染完成后才出现的,而且数据也不是全部加载好再渲染而是一条一条出现,一个处理不好就会下不全。
-
先等待页面加载
selenium的几种等待见官网文档介绍
https://selenium-python.readthedocs.io/waits.html# 设置隐式等待时间,等待页面完整加载,最长等待 60s browser.implicitly_wait(60)
-
然后等待表格第一行下载标签出现
# 等待下载标签加载,最长60s elements = WebDriverWait(browser, 60).until( EC.visibility_of_all_elements_located((By.CSS_SELECTOR, "#tab4FilesTable a")))
-
递归判断所有行加载完
主要就是代码里的wait_a_list函数,作用是等待2秒后再获取一遍列表下载标签,若和上一次不同,则清空循环次数再来一次,若相同,带着循环次数递归,直到连续五次没有新增行,执行下载
4.3 根据url下载文件
这部分,遍历所有获取到的< a >标签,读取href属性(即文件下载地址),分割出文件名,和存储路径一起构建文件地址,若文件存在就跳过,文件不存在就通过geturl函数写入数据。
geturl函数是根据官网脚本大力删改之后的(完整版见该文章),因为我不需要各种判断和异常抛出,我的环境自己有数。token,USERAGENT都是在这一步放入请求头里的,urlopen的context参数也是,上述几个地方简易保持原样不要改,搞不好就会下下来一个20k的垃圾文件=_=
最后
如果运行过程中遇到什么奇怪错误,可以先自行百度。我记得好像碰到过啥小问题,搜了一下降低了某个库的版本就好了。这种依赖相关的问题每个人环境不一样,碰到的也不同,问我也没用。
参考
https://blog.csdn.net/NingAnMe/article/details/103461808
https://ladsweb.modaps.eosdis.nasa.gov/search/
https://selenium-python.readthedocs.io/api.html