Quick Start¶
This guide will help you start using Remote Sensing Satellite Downloader in minutes.
Installation¶
Or from source code:
git clone https://github.com/Aouei/remote-sensing-satellite-downloader.git
cd remote-sensing-satellite-downloader
pip install -e .
Prerequisites¶
For Sentinel (Copernicus)¶
- Create account at Copernicus Data Space
- Note your email and password
For Landsat (USGS)¶
- Create account at USGS Earth Explorer
- Generate API Token:
- Go to "My Profile" → "Access"
- Generate "Application Token"
- Copy the token
First Example: Sentinel-2¶
from sat_download.api.odata import ODataAPI
from sat_download.services.downloader import SatelliteImageDownloader
from sat_download.data_types.search import SearchFilters
from sat_download.enums import COLLECTIONS
# 1. Configure Copernicus API
api = ODataAPI(
username="your_email@example.com",
password="your_password"
)
# 2. Create downloader
downloader = SatelliteImageDownloader(api, verbose=1)
# 3. Define search
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
processing_level="L2A",
start_date="2024-01-01",
end_date="2024-01-31",
tile_id="30TWM" # Madrid, Spain
)
# 4. Search for images
print("Searching for images...")
results = downloader.search(filters)
print(f"Found {len(results)} images")
# 5. Display information
for image in results.values():
print(f"- {image.date}: {image.sensor} {image.tile}")
# 6. Download (optional)
if results:
print("\nDownloading images...")
paths = downloader.bulk_download(results, outdir="./sentinel2_madrid")
print(f"Downloaded {len([p for p in paths if p])} images")
First Example: Landsat 8¶
from sat_download.api.usgs import USGSAPI
from sat_download.services.downloader import SatelliteImageDownloader
from sat_download.data_types.search import SearchFilters
from sat_download.enums import COLLECTIONS
# 1. Configure USGS API (use API Token, not password)
api = USGSAPI(
username="your_username",
password="your_api_token_here"
)
# 2. Create downloader
downloader = SatelliteImageDownloader(api, verbose=1)
# 3. Define search
filters = SearchFilters(
collection=COLLECTIONS.LANDSAT_8.value,
processing_level="T1", # Tier 1 (highest quality)
start_date="2024-01-01",
end_date="2024-01-31",
tile_id="203033" # Path 203, Row 033
)
# 4. Search for images
print("Searching for images...")
results = downloader.search(filters)
print(f"Found {len(results)} images")
# 5. Download
if results:
print("\nDownloading images...")
paths = downloader.bulk_download(results, outdir="./landsat8")
print(f"Downloaded {len([p for p in paths if p])} images")
Key Concepts¶
SearchFilters¶
Define which images to search for:
filters = SearchFilters(
collection="SENTINEL-2", # Which satellite
start_date="2024-01-01", # From when
end_date="2024-01-31", # Until when
processing_level="L2A", # Processing level (optional)
tile_id="30TWM", # Specific tile (optional)
geometry="POINT(-3.7 40.4)" # Coordinates (optional)
)
SearchResults¶
Dictionary of found images:
results = downloader.search(filters)
# Iterate over results
for product_id, image in results.items():
print(f"{image.date}: {image.filename}")
# Count results
print(f"Total: {len(results)}")
SatelliteImage¶
Object with image metadata:
image = results[list(results.keys())[0]]
print(image.sensor) # "Sentinel-2"
print(image.date) # "20240115"
print(image.tile) # "30TWM"
print(image.filename) # "S2A_MSIL2A_...zip"
Search by Location¶
By Tile ID¶
Sentinel-2 (MGRS system):
# Find your tile: https://eatlas.org.au/data/uuid/f7468d15-12be-4e3f-a246-b2882a324f59
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
start_date="2024-01-01",
end_date="2024-01-31",
tile_id="30TWM" # Madrid
)
Landsat 8 (WRS-2 Path/Row system):
# Find Path/Row: https://landsat.usgs.gov/landsat_acq
filters = SearchFilters(
collection=COLLECTIONS.LANDSAT_8.value,
start_date="2024-01-01",
end_date="2024-01-31",
tile_id="203033" # Path 203, Row 033
)
By Coordinates¶
# Madrid (lon, lat in WGS84)
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
start_date="2024-01-01",
end_date="2024-01-31",
geometry="POINT(-3.7037902 40.4167754)"
)
By Area (Polygon)¶
# Bounding box around Barcelona
bbox = "POLYGON((2.05 41.32, 2.25 41.32, 2.25 41.45, 2.05 41.45, 2.05 41.32))"
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
start_date="2024-01-01",
end_date="2024-01-31",
geometry=bbox
)
Image Filtering¶
By Processing Level¶
Sentinel-2:
# L2A = Surface reflectance (recommended)
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
processing_level="L2A",
...
)
# L1C = Top-of-atmosphere reflectance
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
processing_level="L1C",
...
)
Landsat 8:
# T1 = Tier 1 (highest quality)
filters = SearchFilters(
collection=COLLECTIONS.LANDSAT_8.value,
processing_level="T1",
...
)
# T2 = Tier 2 (standard quality)
filters = SearchFilters(
collection=COLLECTIONS.LANDSAT_8.value,
processing_level="T2",
...
)
By Name Content¶
# Filter by strings in filename
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
start_date="2024-01-01",
end_date="2024-01-31",
tile_id="30TWM",
contains=["MSIL2A", "N0510"] # Only L2A with version N0510
)
Selective Download¶
Download Only Most Recent¶
from datetime import datetime
# Search
results = downloader.search(filters)
# Sort by date
sorted_images = sorted(
results.items(),
key=lambda x: x[1].date,
reverse=True # Most recent first
)
# Take only the 3 most recent
recent = dict(sorted_images[:3])
# Download
paths = downloader.bulk_download(recent, "./recent_images")
Download Only from One Satellite¶
# Search
results = downloader.search(filters)
# Filter by Sentinel-2A
s2a_only = {
k: v for k, v in results.items()
if v.brother == "A"
}
# Download
paths = downloader.bulk_download(s2a_only, "./sentinel2a")
Searching Large Date Ranges¶
For date ranges > 1 month, use bulk_search():
# Search entire year
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
start_date="2023-01-01",
end_date="2023-12-31",
tile_id="30TWM"
)
# bulk_search automatically splits the range
results = downloader.bulk_search(filters)
print(f"Total: {len(results)} images")
Common Error Handling¶
Error: Incorrect Credentials¶
Sentinel-2:
Solution: Verify email and password at https://dataspace.copernicus.eu/
Landsat 8:
Solution: Verify that you use API Token (not password) from https://ers.cr.usgs.gov/profile/access
Error: No Images Found¶
results = downloader.search(filters)
if not results:
print("No images found")
# Check:
# - Valid date range
# - Correct Tile ID
# - Correct Collection
Error: Download Failed¶
paths = downloader.bulk_download(results, "./images")
# Check which ones failed
for idx, (product_id, image) in enumerate(results.items()):
if paths[idx] is None:
print(f"Failed: {image.filename}")
# Retry individually if necessary
Next Steps¶
- Architecture: Understand the design
- API Reference: Detailed documentation
Complete Example Script¶
Save as download_sentinel.py:
#!/usr/bin/env python3
"""
Example script to download Sentinel-2 images.
"""
from sat_download.api.odata import ODataAPI
from sat_download.services.downloader import SatelliteImageDownloader
from sat_download.data_types.search import SearchFilters
from sat_download.enums import COLLECTIONS
def main():
# Configuration
USERNAME = "your_email@example.com"
PASSWORD = "your_password"
TILE_ID = "30TWM"
START_DATE = "2024-01-01"
END_DATE = "2024-01-31"
OUTPUT_DIR = "./sentinel2_images"
# Create API and downloader
print("Connecting to Copernicus Data Space...")
api = ODataAPI(username=USERNAME, password=PASSWORD)
downloader = SatelliteImageDownloader(api, verbose=1)
# Define search
filters = SearchFilters(
collection=COLLECTIONS.SENTINEL_2.value,
processing_level="L2A",
start_date=START_DATE,
end_date=END_DATE,
tile_id=TILE_ID
)
# Search
print(f"\nSearching for L2A images from tile {TILE_ID}...")
results = downloader.search(filters)
if not results:
print("No images found.")
return
print(f"\nFound {len(results)} images:")
for image in results.values():
print(f" - {image.date}: {image.filename}")
# Confirm download
response = input(f"\nDownload {len(results)} images? (y/n): ")
if response.lower() != 'y':
print("Download cancelled.")
return
# Download
print(f"\nDownloading to {OUTPUT_DIR}...")
paths = downloader.bulk_download(results, OUTPUT_DIR)
# Report
successful = len([p for p in paths if p is not None])
print(f"\n✓ Completed: {successful}/{len(results)} successful downloads")
if __name__ == "__main__":
main()
Run:
Help and Support¶
- Issues: GitHub Issues
- Documentation: This documentation
- Copernicus Support: Forum
- USGS Support: Contact