yannforget / landsatxplore

Search and download Landsat scenes from EarthExplorer.
MIT License
223 stars 98 forks source link

scenes found, but "EarthExplorerError: Download is not available" error comes while downloading #46

Open abhilashsinghimd opened 3 years ago

abhilashsinghimd commented 3 years ago

import json from landsatxplore.api import API from landsatxplore.earthexplorer import EarthExplorer

Initialize a new API instance and get an access key

usgs_username = "****" usgs_password = "****"

api = API(usgs_username, usgs_password)

Search for Landsat TM scenes

scenes = api.search( dataset='landsat_ot_c2_l1', latitude=30.9, longitude=75.85,

bbox= (70, 28, 80, 32), #(xmin, ymin, xmax, ymax),

start_date='2017-01-01',
end_date='2017-04-01',
max_cloud_cover=10

)

print(f"{len(scenes)} scenes found.")

Process the result

for scene in scenes: print(scene['acquisition_date'].strftime('%Y-%m-%d'))

Write scene footprints to disk

fname = f"{scene['landsat_product_id']}.geojson"
with open(fname, "w") as f:
    json.dump(scene['spatial_coverage'].__geo_interface__, f)
    print(f)

api.logout()

output

3 scenes found. 2017-03-19

<_io.TextIOWrapper name='LC08_L1TP_148038_20170319_20200904_02_T1.geojson' mode='w' encoding='cp1252'> 2017-03-19 <_io.TextIOWrapper name='LC08_L1TP_148039_20170319_20200904_02_T1.geojson' mode='w' encoding='cp1252'> 2017-02-15 <_io.TextIOWrapper name='LC08_L1TP_148039_20170215_20200905_02_T1.geojson' mode='w' encoding='cp1252'> # Downloading Scenes ee = EarthExplorer(usgs_username, usgs_password) ee.download('LC08_L1TP_148038_20170319_20200904_02_T1', output_dir=r'D:\RF_Paper\JAM\MODIS') ee.logout() # error --------------------------------------------------------------------------- EarthExplorerError Traceback (most recent call last) in 2 ee = EarthExplorer(usgs_username, usgs_password) 3 ----> 4 ee.download('LC08_L1TP_148038_20170319_20200904_02_T1', output_dir=r'D:\RF_Paper\JAM\MODIS') 5 6 ee.logout() ~\Anaconda3\lib\site-packages\landsatxplore\earthexplorer.py in download(self, identifier, output_dir, dataset, timeout, skip) 148 data_product_id=DATA_PRODUCTS[dataset], entity_id=entity_id 149 ) --> 150 filename = self._download(url, output_dir, timeout=timeout, skip=skip) 151 return filename ~\Anaconda3\lib\site-packages\landsatxplore\earthexplorer.py in _download(self, url, output_dir, timeout, chunk_size, skip) 90 error_msg = r.json().get("errorMessage") 91 if error_msg: ---> 92 raise EarthExplorerError(error_msg) 93 download_url = r.json().get("url") 94 EarthExplorerError: Download is not available
MartinPontius commented 3 years ago

Hi!

I faced the same issue and did some research/debugging. My understanding so far:

The problem is how the download url is created. Here is one example (product from 2021): https://earthexplorer.usgs.gov/download/5e83d14f30ea90a9/LC81960242021089LGN00/EE/ This should run successfully.

The middle part of this url 5e83d14f30ea90a9 is hard-coded in the source code and different for different product types (Landsat Level 1, Landsat Level 2, Sentinel, etc.). However, some tests showed that it's not always the same for the same product type. It seems to be a different string for older products of the same type. For older products this works: 5e83d14fec7cae84. An example for an "old" product (2015) is: https://earthexplorer.usgs.gov/download/5e83d14fec7cae84/LC80350242015225LGN03/EE/

However, I didn't find out yet at which date/time it changes. Try and error would be lengthy and I didn't find anything in the official documentation.

I think I will contact USGS and let you know if I can find out more.

P.S.: I also tested the version of the Landsat Scene Identifier (last two characters), but I didn't find a clear correlation.

MartinPontius commented 3 years ago

Just noticed there are two other issues about this: 42 and 45...

scku208 commented 1 year ago

I also facing this problem recent days, like @MartinPontius says, the middle part of url changes from time to time for different product types. So I decide to list all possible middle url with python's try except... here's the code:

#earthexplore.py
#(skipped)
# IDs of GeoTIFF data product for each dataset
DATA_PRODUCTS = {
#  ... (skipped)
}

DATA_PRODUCTS_II = {
#  ... (skipped)
}

#add this, change single quess url to list, which contains all possible middle urls. 
DATA_PRODUCTS_ALL = {
    "landsat_tm_c1": ["5e83d08fd9932768"],
    "landsat_etm_c1": ["5e83a507d6aaa3db"],
    "landsat_8_c1": ["5e83d0b84df8d8c2"],
    "landsat_tm_c2_l1": ["5e83d0a0f94d7d8d"],
    "landsat_etm_c2_l1": ["5e83d0d0d2aaa488", "5e83d0d08fec8a66"],

    #this line, add "5e81f14f92acf9ef" for newer dataset
    "landsat_ot_c2_l1": ["632211e26883b1f7", "5e81f14ff4f9941c", "5e81f14f92acf9ef"],

    "landsat_tm_c2_l2": ["5e83d11933473426"],
    "landsat_etm_c2_l2": ["5e83d12aada2e3c5", "5e83d12aed0efa58"],
    "landsat_ot_c2_l2": ["5e83d14f30ea90a9", "5e83d14fec7cae84"],
    "sentinel_2a": ["5e83a42c6eba8084"],
}

#(skipped...)

#def download(skipped...):
     #(skipped...)
     if is_display_id(identifier):
            entity_id = self.api.get_entity_id(identifier, dataset)
        else:
            entity_id = identifier

    #get all possible middle url
    all_possible_data_product_id = DATA_PRODUCTS_ALL[dataset]

            success = False
            # forloop trying all possible middle url
            for possible_data_product_id in all_possible_data_product_id:
                try:
                    url = EE_DOWNLOAD_URL.format(
                        data_product_id=possible_data_product_id, entity_id=entity_id
                    )
                    #for debugging
                    print(f'dataset: {dataset}')
                    print(f'data_product_id: {possible_data_product_id}')
                    print(f'download location:{url}')
                    filename = self._download(url, output_dir, timeout=timeout, skip=skip)
                    success = True
                except:
                    print("guess_failed")
            #change to return success for check
            return success

Then you can use like...

success = ee.download(fname, output_dir=tar_file_path)
if not success:
    raise ValueError('Download Failed')
else:
    print(f"{scene['display_id']}, Download success....")