【Python&RS】基于Python批量下载哨兵二号数据

        学遥感的避免不了使用哨兵数据,毕竟10m的分辨率可以满足大部分的定量分析,同时也是最重要的一点,它免费!!!

        但如果一幅一幅去下载影像实在是太慢了,特别是如果需要研究长时间序列的影像,那下载数据就成了最痛苦的环节了。所以这里给大家分享一下如何使用Python和IDM批量下载哨兵二号数据,当然欧空局的其他数据也可以下载。

        这里说明一下,IDM下载的代码部分参考了一些博主的代码,但我找不到他们了(泪目)。如果有所冒犯,请联系作者删除。

一、注册账号

        想要下载数据,你总归需要一个账号吧!欧空局官网,点击左上角login注册一个账号先。

二、制作兴趣区范围

        我们在查找数据时一般都需要一个研究区,如一个省或者一个市,那么就需要研究区的矢量文件去限制我们查找数据的范围。这里需要使用一个导出GeoJSON的工具,先画出研究区再导出GeoJSON即可。

三、查找数据

        欧空局发布过一个Python的包sentinelsat,大家有兴趣可以自己看看文档,通过这个包我们可以通过日期、云量、范围、卫星类型等查询我们需要的影像数据。

        代码中的注释比较详细,所以我就不过多介绍了。

def Search_data(login, key, path_geojson, start_date, end_date, name, product_type, cloud, filepath):
    """
    :param login: 欧空局账号,字符串类型
    :param key: 欧空局密码,字符串类型
    :param path_geojson: 兴趣区路径及文件名
    :param start_date: 开始时间,字符串
    :param end_date: 结束时间,字符串
    :param name: 卫星名称
    :param product_type: 卫星类型
    :param cloud: 云量筛选,格式:(0,15)
    :param filepath: Url保存路径及文件名
    :return: 返回存有下载链接的excel路径
    """
    api = SentinelAPI(login, key, 'https://scihub.copernicus.eu/dhus')
    # 登陆账号https://scihub.copernicus.eu/apihub/
    footprint = geojson_to_wkt(read_geojson(path_geojson))
    # 读取兴趣区,兴趣区由http://geojson.io导出
    products = api.query(footprint,
                         date=(start_date, end_date),  # 搜索的日期范围
                         platformname=name,   # 卫星平台名,Sentinel-2
                         producttype=product_type,  # 产品数据等级,Sentinel-2: S2MSI2A,S2MSI1C,S2MS2Ap/Sentinel-1:SLC,GRD,OCN
                         cloudcoverpercentage=cloud)  # 云量百分比
    # 搜索A、B双星的数据
    row = 0
    workbook_write = xlwt.Workbook(encoding='utf-8')
    worksheet_write = workbook_write.add_sheet('Url_image')
    for product in products:
        # 通过for循环遍历并打印、下载出搜索到的产品文件名
        info_product = api.get_product_odata(product)
        # 通过OData API获取单一产品数据的主要元数据信息
        worksheet_write.write(row, 0, info_product['url'])
        worksheet_write.write(row, 1, info_product['title'])
        print(info_product['title'])
        # print(product_info['url'])
        # 打印下载的产品数据文件名,id/uuid代码编号,size数据大小,title标题,url链接,md5,date时间
        # api.download(product)
        row += 1
    workbook_write.save(filepath)
    return filepath, api
    # 循环结束后,保存表格

四、调用IDM批量下载

        这里读取之前保存的下载链接的表格,再调用IDM批量对链接进行下载。哨兵数据有些是offline的,不能直接下载。但官方给出了激活函数,可以通过该函数对数据进行激活后就可以下载了。

def Download_image(filepath, Path_Download, Path_IDM, api):
    workbook_read = xlrd2.open_workbook(filepath)
    # 打开表格,创建工作空间
    sheet1 = workbook_read.sheet_by_name('Url_image')
    # 选择需要读取的sheet
    link_list = sheet1.col_values(0)
    # 获取第一列的数据
    print('所有链接下载完成,现在开始下载对应数据')
    num = 0
    while link_list:
        print('---------------------------------------------------')
        num += 1
        print('\n')
        print('第' + str(num) + '次循环' + '\n')
        id = link_list[0].split('\'')[1]
        link = link_list[0]
        info_product = api.get_product_odata(id)
        print('查询当前列表里的第一个数据的状态')
        if info_product['Online']:
            print(info_product['title'] + '为:online产品')
            print('加入IDM的下载列表中: ')
            print('\n')
            call([Path_IDM, '/d', link, '/p', Path_Download, '/n', '/a'])
            link_list.remove(link)
            call([Path_IDM, '/s'])
        else:
            print(info_product['title'] + '为:offline产品')
            print('\n')
            print('激活offline产品')
            code_id = link_list[0].split('\'')[1]
            api.trigger_offline_retrieval(code_id)
            # 激活offline产品
            print('检查任务列表里是否存在online产品: .........')
            # 等待激活成功的时候,检查现在的列表里还有没有online产品
            # 如果有online的产品那就下载
            # 首先检查列表中是否需要下载的数据
            if len(link_list) > 1:
                # 记录列表里可以下载的链接,并在最后把它们删除
                link_list_1 = []
                # 开始寻找列表剩下的元素是否有online产品
                for i in range(1, len(link_list)):
                    id2 = link_list[i].split('\'')[1]
                    link_1 = link_list[i]
                    info_product2 = api.get_product_odata(id2)
                    if info_product2['Online']:
                        print(info_product2['title'] + '为Online产品')
                        print('加入IDM的下载列表中: ')
                        print('--------------------------------------------')
                        call([Path_IDM, '/d', link_1, '/p', Path_Download, '/n', '/a'])
                        # 在列表中加入需要删除产品的HTTP链接信息
                        # 直接在link_list中删除会link_list的长度会发生改变,最终造成i的值超过link_list的长度
                        link_list_1.append(link_1)
                    else:
                        continue
                # 把已经下载的数据的链接给删除掉
                if len(link_list_1) > 0:
                    call([Path_IDM, '/s'])
                    for link_2 in link_list_1:
                        link_list.remove(link_2)
            print('本轮次检查结束,开始等到40分钟')
            # 将该激活的产品删除,再加入到最后
            link_list.remove(link)
            link_list.append(link)
            # 两次激活offline数据的间隔要大于30分钟
            for i in tqdm(range(int(1200)), ncols=100):
                time.sleep(2)

五、完整代码

# -*- coding: utf-8 -*-
"""
@Time : 2023/3/31 15:35
@Auth : RS迷途小书童
@File :Batch download of Sentinel data.py
@IDE :PyCharm
@Purpose :批量下载哨兵数据
"""
from sentinelsat import SentinelAPI, read_geojson, geojson_to_wkt
# 导入用户登录,兴趣区识别模块
from subprocess import call
# 用来唤醒IDM下载数据
from datetime import date
import time
import xlwt
import xlrd2
# excel的读取和写入模块
from tqdm import tqdm


def Search_data(login, key, path_geojson, start_date, end_date, name, product_type, cloud, filepath):
    """
    :param login: 欧空局账号,字符串类型
    :param key: 欧空局密码,字符串类型
    :param path_geojson: 兴趣区路径及文件名
    :param start_date: 开始时间,字符串
    :param end_date: 结束时间,字符串
    :param name: 卫星名称
    :param product_type: 卫星类型
    :param cloud: 云量筛选,格式:(0,15)
    :param filepath: Url保存路径及文件名
    :return: 返回存有下载链接的excel路径
    """
    api = SentinelAPI(login, key, 'https://scihub.copernicus.eu/dhus')
    # 登陆账号https://scihub.copernicus.eu/apihub/
    footprint = geojson_to_wkt(read_geojson(path_geojson))
    # 读取兴趣区,兴趣区由http://geojson.io导出
    products = api.query(footprint,
                         date=(start_date, end_date),  # 搜索的日期范围
                         platformname=name,   # 卫星平台名,Sentinel-2
                         producttype=product_type,  # 产品数据等级,Sentinel-2: S2MSI2A,S2MSI1C,S2MS2Ap/Sentinel-1:SLC,GRD,OCN
                         cloudcoverpercentage=cloud)  # 云量百分比
    # 搜索A、B双星的数据
    row = 0
    workbook_write = xlwt.Workbook(encoding='utf-8')
    worksheet_write = workbook_write.add_sheet('Url_image')
    for product in products:
        # 通过for循环遍历并打印、下载出搜索到的产品文件名
        info_product = api.get_product_odata(product)
        # 通过OData API获取单一产品数据的主要元数据信息
        worksheet_write.write(row, 0, info_product['url'])
        worksheet_write.write(row, 1, info_product['title'])
        print(info_product['title'])
        # print(product_info['url'])
        # 打印下载的产品数据文件名,id/uuid代码编号,size数据大小,title标题,url链接,md5,date时间
        # api.download(product)
        row += 1
    workbook_write.save(filepath)
    return filepath, api
    # 循环结束后,保存表格


def Download_image(filepath, Path_Download, Path_IDM, api):
    workbook_read = xlrd2.open_workbook(filepath)
    # 打开表格,创建工作空间
    sheet1 = workbook_read.sheet_by_name('Url_image')
    # 选择需要读取的sheet
    link_list = sheet1.col_values(0)
    # 获取第一列的数据
    print('所有链接下载完成,现在开始下载对应数据')
    num = 0
    while link_list:
        print('---------------------------------------------------')
        num += 1
        print('\n')
        print('第' + str(num) + '次循环' + '\n')
        id = link_list[0].split('\'')[1]
        link = link_list[0]
        info_product = api.get_product_odata(id)
        print('查询当前列表里的第一个数据的状态')
        if info_product['Online']:
            print(info_product['title'] + '为:online产品')
            print('加入IDM的下载列表中: ')
            print('\n')
            call([Path_IDM, '/d', link, '/p', Path_Download, '/n', '/a'])
            link_list.remove(link)
            call([Path_IDM, '/s'])
        else:
            print(info_product['title'] + '为:offline产品')
            print('\n')
            print('激活offline产品')
            code_id = link_list[0].split('\'')[1]
            api.trigger_offline_retrieval(code_id)
            # 激活offline产品
            print('检查任务列表里是否存在online产品: .........')
            # 等待激活成功的时候,检查现在的列表里还有没有online产品
            # 如果有online的产品那就下载
            # 首先检查列表中是否需要下载的数据
            if len(link_list) > 1:
                # 记录列表里可以下载的链接,并在最后把它们删除
                link_list_1 = []
                # 开始寻找列表剩下的元素是否有online产品
                for i in range(1, len(link_list)):
                    id2 = link_list[i].split('\'')[1]
                    link_1 = link_list[i]
                    info_product2 = api.get_product_odata(id2)
                    if info_product2['Online']:
                        print(info_product2['title'] + '为Online产品')
                        print('加入IDM的下载列表中: ')
                        print('--------------------------------------------')
                        call([Path_IDM, '/d', link_1, '/p', Path_Download, '/n', '/a'])
                        # 在列表中加入需要删除产品的HTTP链接信息
                        # 直接在link_list中删除会link_list的长度会发生改变,最终造成i的值超过link_list的长度
                        link_list_1.append(link_1)
                    else:
                        continue
                # 把已经下载的数据的链接给删除掉
                if len(link_list_1) > 0:
                    call([Path_IDM, '/s'])
                    for link_2 in link_list_1:
                        link_list.remove(link_2)
            print('本轮次检查结束,开始等到40分钟')
            # 将该激活的产品删除,再加入到最后
            link_list.remove(link)
            link_list.append(link)
            # 两次激活offline数据的间隔要大于30分钟
            for i in tqdm(range(int(1200)), ncols=100):
                time.sleep(2)


if __name__ == "__main__":
    """说明文档:https://sentinelsat.readthedocs.io/en/latest/api_overview.html,
    https://scihub.copernicus.eu/userguide/AdvancedSearch"""
    login = '**********'
    key = '********'
    path_geojson = "G:/map.geojson"
    start_date = "20230101"
    end_date = "20230301"
    name = 'Sentinel-2'
    product_type = 'S2MSI2A'
    cloud = (0, 15)
    filepath = 'G:/url.xls'
    # 存储下载链接的表格
    filepath, api = Search_data(login, key, path_geojson, start_date, end_date, name, product_type, cloud, filepath)
    Download_Path = 'G:/try_download/'
    # 数据要下载的地址,IDM的下载地址
    Path_IDM = "D:/IDM/IDMan.exe"
    Download_image(filepath, Download_Path, Path_IDM, api)

        本博文代码是我很久之前写的了,结构有些冗余,但运行没有任何问题。同时有些借鉴的代码已经找不到原作者了,在这里先感谢大佬们的付出,如有侵权,请联系作者删除。

        如果大家在学习Python或者RS时有什么问题,可以随时留言交流!如果大家对批量处理有兴趣同样可以留言给博主,博主会分享相关代码以供学习!

你可能感兴趣的:(Sensing,python,开发语言,arcgis)