ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python批量下载Sentinel-2遥感数据:新平台CDSE实操与避坑指南

Python批量下载Sentinel-2遥感数据:新平台CDSE实操与避坑指南 做遥感的人应该都有这种体会找数据不难难的是把数据批量弄到手。以Sentinel-2为例这两年欧空局一直在调整数据分发方式旧的Copernicus Open Access Hub在2023年正式关停后大家都陆续迁移到了新的Copernicus Data Space Ecosystem。如果你还在翻两年前的老教程大概率会卡在接口失效、认证报错、下载链接404这类问题上。这篇内容我结合自己从S2A/B数据申请、搜索、批量下载到预处理落地的完整过程把2024年用Python批量下载Sentinel-2的整套流程重新梳理了一遍包括新平台账号注册、Python环境与依赖库配置、核心代码实现以及一份真正从错误堆里爬出来的避坑清单。无论你是刚入门的遥感学生还是已经在项目里长期用过哨兵数据的研究人员这篇文章应该能帮你少走不少弯路。1. 为什么需要Python批量下载Sentinel-2数据1.1 Sentinel-2数据的获取现状与痛点先说一个很现实的问题手工下载Sentinel-2到底有多麻烦一景Sentinel-2 L2A产品解压后大约是2.5GB到3GB包含13个波段的JPEG2000影像文件、气溶胶和云掩膜等辅助产品、元数据XML、预览图等几十个文件。网页浏览器手动下载通常只能逐文件点选一个tile可能要分好多次才能下完更别说一次研究往往要覆盖几十上百个时相的影像手工操作几乎不可行。我在实际项目里遇到过更头疼的情况做一个县域尺度的土地利用分类研究区跨越了3个MGRS分幅需要收集过去一整年的多时相影像加起来一百多景。如果全靠网页操作光下载和整理文件就能耗掉一周时间而且极容易漏文件、错文件。批量下载脚本的核心价值就在这里通过代码自动完成“区域圈定→影像检索→云量过滤→时间筛选→批量下载→完整性校验→自动解压整理”这一整套流程人只需要盯着进度条和处理报错就行。从2024年的实际情况看老教程里广泛使用的sentinelsat库已经处于半废弃状态它对旧的Open Access Hub API的依赖导致新平台基本不可用。很多刚接触卫星数据的小白却还在按旧教程操作自然会踩坑。这让我觉得很有必要写一篇基于新平台和当前可用库的实操指南。1.2 2024年后的新下载途径与选型思路现在的官方数据分发平台是Copernicus Data Space Ecosystem以下简称CDSE。它提供了多种数据访问方式最常用的有下面几种网页手动下载。适合偶尔下几景图不适合批量处理。S3命令行工具。直接通过AWS CLI访问官方S3桶适合Linux/服务器环境下快速拉取但需要自己处理元数据检索门槛偏高。OData / STAC API。适合程序化检索数据但需要自己写请求逻辑且token管理和分页处理比较繁琐。Python库cdsetool。把检索、下载、token管理、断点续传封装成相对顺手的高层接口是目前社区里比较推崇的新平台下载方式。我最终选择的是cdsetool主要原因有三点一是它能自动处理OAuth 2.0 token的获取和刷新不用自己手动维护过期时间二是内部已实现了一定程度的断点续传和并发下载控制省去了很多底层的网络逻辑三是返回的feature对象可以直接对接下载函数写出来的代码非常简洁。当然cdsetool也有自己的局限性比如它的文档不够详尽某些边界情况处理得并不完美这些我会在第4部分配合避坑清单具体展开。1.3 几种方案的核心对比为了帮你根据自己场景做判断我整理了一张方案对比表都是基于我实际操作体验得出的结论方案适用场景工作量批处理能力上手难度网页手动下载少量、临时需求低基本没有低AWS CLI S3协议Linux环境、懂命令行中强但检索要自己写中高STAC/OData API直接写需要高度定制化高强高cdsetool常规批量下载低强接口简洁中如果只是偶尔做一次小范围研究直接在网页上找数据就够了没必要折腾脚本。但如果你需要长期、定期地更新某个区域的影像或者一做项目就是几十上百景数据那么花一点时间配置好Python环境、掌握cdsetool的用法是绝对值得的。接下来我会手把手走一遍完整流程。2. 准备工作账号与Python环境配置2.1 在Copernicus Data Space申请账号第一步是注册CDSE账号。打开dataspace.copernicus.eu右上角找到Sign Up入口用邮箱注册、设置密码走完邮箱验证流程即可。相较于旧平台CDSE的账号申请几乎没有门槛普通教育或研究用途都可以直接通过。需要注意的一点是新注册的账号通常有几分钟到几小时的权限同步延迟如果你刚注册完就去调API很可能会遇到401或403错误这个我在后面排查清单里会再提到。登录状态下你可以通过网页端的Search界面先手动搜索几幅影像验证账号权限已经生效。搜索界面支持按时间范围、云量、轨道号、产品级别等条件过滤建议先在这里做一轮小范围的测试确认你的研究区、时间范围和产品类型选择都没问题再写脚本跑批量。这样能把“数据本身是否存在”和“代码是否有bug”两个变量分离开来排查。2.2 安装Python与依赖库cdsetool要求Python 3.8以上建议直接用3.10或3.11版本比较稳。如果你机器上还没有Python环境推荐用Miniconda或者官方Python安装包搭建一个独立环境避免和系统自带的Python版本互相干扰。Windows环境记得在安装时勾选“Add Python to PATH”Linux/macOS一般直接装就好。依赖库方面核心的是cdsetool另外我强烈建议一并安装rasterio、geopandas和tqdm它们分别用于后续数据读取、矢量范围处理和进度条显示。安装命令如下pip install cdsetool rasterio geopandas tqdm如果你在国内网络环境下安装比较慢可以临时换用镜像源比如清华大学的PyPI镜像安装速度会快很多。安装完成后建议在终端里执行一遍pip show cdsetool确认版本号我测试时用的版本是0.3.2理论上主要接口和最新版本保持一致。2.3 cdsetool库的初始化与凭证配置cdsetool通过Credentials对象来管理和传递账号凭证。最简单的用法是直接把用户名密码写在初始化参数里代码如下from cdsetool.credentials import Credentials credentials Credentials( usernameyour_username, passwordyour_password )但直接硬编码密码毕竟不安全我自己的做法是读取环境变量避免把明文密码提交到代码仓库里。Windows可以在系统环境变量里配置Linux/macOS可以在~/.bashrc里配置也可以在运行时临时设置。有一点需要提前说明cdsetool内部需要下载OData/STAC的基础schema信息到本地缓存这个首次运行时可能需要一些时间看似像卡住了其实是在下载定义文件耐心等待即可。如果这一步反复失败可以尝试升级库版本或者检查当前网络是否能正常访问CDSE域名。3. 核心实操完整批量下载流程3.1 按区域和日期搜索影像批量下载的第一步是确定要搜索哪些影像也就是定义“研究区”和“时间窗口”。我可以直接在代码里用GeoJSON字典定义研究区这种方式最简洁不需要额外的shp文件。以某块矩形区域为例代码如下from cdsetool.query import query_features geometry { type: Polygon, coordinates: [[ [116.3, 39.9], [116.5, 39.9], [116.5, 40.1], [116.3, 40.1], [116.3, 39.9] ]] } features query_features( Sentinel-2, { geometry: geometry, startDate: 2024-01-01, endDate: 2024-06-30, maxCloudCoverage: 20, productType: S2MSI2A } ) print(fSearch returned {len(features)} products)这里有几个参数需要重点关注。productType设置成S2MSI2A表示要L2A级表面反射率产品这是当前绝大多数地表应用推荐的级别因为它已经完成了大气校正。如果后续需要自己处理大气校正可以选S2MSI1C。startDate和endDate是影像的感应时间注意它们遵循UTC时区在跨时区的时候要小心边界情况。maxCloudCoverage是整景影像的全景云量百分比上限20表示只保留云量低于20%的产品。如果需要用shp文件来做搜索范围cdsetool还提供了shape_to_geojson辅助函数可以直接把本地的shapefile转成GeoJSON格式示例代码如下from cdsetool.query import shape_to_geojson geometry shape_to_geojson(path/to/your/shp_file.shp)3.2 筛选条件设置与云量控制搜索条件不一定越严格越好关键要看你的实际应用场景。云量阈值就是我经常被人问起的一个点到底是设20还是50如果你做的是裸地分类、建筑提取这类对云不敏感的任务设50甚至80都无所谓但如果你做的是植被指数分析云和云阴影对结果影响非常大我建议设10到20。不过要注意CDSE的云量指标是整景产品的平均云量不是研究区范围内的局部云量。有时候整景云量10%却恰好把研究区盖住了一片云整景云量30%研究区反而晴空万里。想要更精确的按局部区域筛选要么人工目视检查预览图要么结合cloud mask产品自己计算研究区范围的云覆盖率。另外还要考虑产品的重返周期和过境轨道。Sentinel-2的两颗卫星联合起来赤道附近区域的重访周期大约是5天在中纬度地区会更频繁。时间窗口设得太窄可能会导致一景符合条件的影像都没有这时候需要适当放宽云量限制或扩展时间范围。3.3 批量下载与断点续传搜索到目标产品列表后正式开始批量下载。cdsetool提供了一个比较高层的download_features函数直接传入前面得到的features列表和输出目录即可from cdsetool.download import download_features download_features( features, downloaded_data, credentialscredentials, max_concurrent4 )downloaded_data是输出目录不存在的话会自动创建。max_concurrent表示并发下载的线程数设置越大下载速度越快但同时也更吃带宽和服务器端的配额。我自己的经验是日常下载设4到6个并发比较平衡如果网速很好且需要抢数据可以临时开到8个。并发太大容易触发服务器端的限流反而会拖慢整体速度。cdsetool在下载过程中会为每个产品生成一个.lock类型的临时锁定文件用来标识当前正在下载的产品。下载完成后lock文件会移除如果某个下载意外中断lock文件会残留下来。在后续版本中重新执行下载脚本时已经完成的产品会被跳过已存在lock文件但未完成的下载可能会被当作正在下载处理这点需要在断点续传时特别留意。我自己的处理方式是脚本跑完一轮后先清理掉所有残留的.lock文件再重新执行下载这样中断的任务就能重新开始。如果你对下载过程的可见性有要求还可以自己写一个外层循环配合tqdm来显示进度这样就能直观地看到“当前正在下载第几个产品”。这一层封装不复杂但能让长时间跑批时心里有底。3.4 下载结果的校验与整理下载完成不代表万事大吉。Sentinel-2产品在CDSE上是以zip压缩包形式提供的下载过程如果断断续续很容易出现zip文件损坏但文件名完全正常的情况。所以下载完成后我强烈建议做一轮完整性校验最简单有效的方法是用zipfile模块测试每个压缩包import zipfile from pathlib import Path for zpath in Path(downloaded_data).glob(*.zip): try: with zipfile.ZipFile(zpath) as zf: bad_file zf.testzip() if bad_file: print(fCorrupt file in {zpath.name}: {bad_file}) else: print(fOK: {zpath.name}) except zipfile.BadZipFile: print(fBad zip: {zpath.name})把所有zip文件跑一遍如果有损坏就删掉重新下载。校验完之后再统一解压。解压后建议按“传感器/年份/MGRS分幅号”这样的层级结构整理文件例如S2_2024/T50RKV/S2A_MSIL2A_20240601T025551_N9999_R132_T50RKV_20240601T080214.SAFE这样后续做时间序列分析时定位文件会非常方便。4. 避坑清单我实测踩过的那些坑4.1 账号授权与token的坑第一个坑来自新账号权限延迟。我最初注册CDSE后用账号密码去请求token返回的是401错误代码检查了半天以为是写错了。后来才发现是账号权限还没同步完成等了大约2小时后再次运行就正常了。如果你的账号是新注册的遇到401可以先别急着改代码去网页端登录一次在网页上搜索一下数据确认网页端能看到结果再回来跑脚本。第二个坑是token过期。OAuth 2.0 token默认有效期通常只有几十分钟到几小时如果你是自己封装API请求就一定要处理token续期逻辑。cdsetool帮我们做了这层处理所以用它的主要原因之一就是省心。不过我自己在长时间批量下载时遇到过一种情况单个产品下载本身耗时很长超过token有效期后下载请求中断。这种情况通过断点续传和重新运行脚本基本能解决不需要自己写复杂的重试逻辑。4.2 下载速度与并发数的平衡策略我实测下来CDSE对单连接下载并没有特别严格的限速但覆盖面很广。如果并发数开得太大比如10个以上反而可能出现部分线程长时间无响应、下载卡死的现象。如果你发现明明有网速但某些下载任务一直不结束可以适当降低并发数。更稳妥的做法是先用4个并发跑一轮观察几个产品的平均耗时再根据网络波动调整。另外要强调一点下载工具和下载数据时的网络稳定性非常关键。我遇到过因为网络波动导致zip包只下载了80%文件名却正常的情况如果不校验直接解压后面用数据时才发现文件缺失会浪费大量时间。4.3 磁盘空间与文件名管理一景L2A产品的zip文件大约在800MB到1.2GB之间解压后更大到2.5GB以上。如果你一次下载100景那就是上百GB的空间需求。所以在跑批量下载之前一定要先检查磁盘剩余空间。我建议预留下载文件加解压文件约2倍的空间否则很容易出现下到一半磁盘写满、脚本报错退出的尴尬情况。另外Sentinel-2的产品文件名很长里面包含了卫星编号、数据级别、感应时间、处理时间、轨道号、MGRS分幅号等信息。Windows下文件名长度有限制如果解压路径很深可能触发Path Too Long错误。解决办法是把所有产品解压到路径较短的一级目录下不要嵌套太深。4.4 与数据格式本身相关的小坑下载下来的L2A产品内部是JPEG2000格式的.jp2文件很多通用图像处理库并不能直接读取。如果你用的是rasterio需要确保底层GDAL编译时带有JPEG2000驱动常见的OpenJPEG驱动一般默认都有。如果你用的是OpenCV或PIL这类库大概率会报“unsupported file format”这不是数据损坏只是格式支持的问题换成rasterio或GDAL就好。还有坐标系的问题。Sentinel-2 L2A产品默认采用UTM投影每条轨道有对应的投影带不同MGRS分幅可能对应不同的UTM带。在做多景影像镶嵌时要先统一坐标系否则直接拼接会产生错位和缝隙。这点在后面的预处理中提到一下但真正实现时要单独处理。5. 常见问题与排查技巧实录5.1 常见错误代码速查表我在实际工作中把最容易遇到的几类错误整理成了表格下次再遇到直接查表定位错误现象可能原因解决方法401 Unauthorized用户名密码错误或账号权限未激活检查凭证新账号登录网页端一次后在重试403 Forbiddentoken失效或权限不足重新生成token用cdsetool自动刷新凭证404 Not Found产品已被删除或下载URL过期重新搜索最新结果或更换产品503 Service Unavailable服务端过载或临时维护休息一下再重试降低并发数下载卡在某个产品上网络波动或该产品文件特别大清理lock文件后重跑下载降低并发解压时报CRC错误zip下载不完整删除该zip用断点续传逻辑重新下载5.2 几个高价值排查案例第一个案例搜索返回0结果但网页端能看到数据。这个问题通常是geometry格式有问题比如坐标多边形没有闭合、顶点顺序写错或者自相交。建议先用一个极小的矩形区域测试搜索排除这个因素后再换成真实研究区。第二个案例下载到一半时脚本崩溃。我遇到过内存占用不断上涨最后被系统杀掉的情况。排查后发现这是把features列表一次性传给download_features在极端情况下处理缓存过多导致的。解决方法是分批处理比如每10景一批分批调用下载函数既降低了内存压力也方便定位失败的任务。第三个案例下载成功但磁盘上找不到文件。这个看起来有点离谱但确实发生过。原因是输出目录权限设置不对cdsetool写入时可能静默失败。解决办法是给输出目录显式赋权或者更换到有写入权限的路径。5.3 我的一套建议排查流程碰到任何下载异常我的标准流程是先看错误类型是网络错误、权限错误还是服务端错误网络错误先检查网络连续性和第三方下载工具的连通性权限错误重新验证账号、刷新token服务端错误则主动退避等待后重试。做完这一步还是搞不定就去CDSE的论坛或官方GitHub issue区搜索同样的报错通常都能找到别人已经踩过并解决过的问题。核心思路就是把“不会写代码”和“平台限制”区分开。很多时候你觉得是代码问题其实是平台服务不稳定反过来也有看似平台报错、实际是数据格式或坐标参数的问题。6. 拿到数据之后快速预处理入门6.1 检查数据完整性的几个命令下载解压完成后我建议先用系统命令快速看一下数据结构的完整性。一个成熟的S2产品包内部至少有GRANULE、IMG_DATA、AUX_DATA等文件夹METADATA目录下还有产品的元数据XML。在终端或Python里检查关键文件是否存在是最快的完整性验证find . -name *.jp2 | wc -lL2A产品一般有13个波段加上若干辅助波段正常情况下JP2文件数量应该在20个以上。如果数量明显偏少说明解压不完整或产品本身有缺失需要重新下载。更严格的做法是打开MTD_MSIL2A.xml检查XML能否被完整解析同时比对产品标识和内部Granule标识是否一致。6.2 用rasterio快速读取与预处理预处理的第一步往往是提取需要的波段。以常用的红、绿、蓝、近红外波段为例可以用rasterio定位到对应的JP2文件并读取为numpy数组import rasterio import numpy as np with rasterio.open(path/to/T50RKV_20240601_B04.jp2) as src: red src.read(1) profile src.profile print(red.shape, red.dtype, profile[crs])这里需要特别注意的是L2A产品的表面反射率通常不是直接存储为0到1的浮点数而是缩放后的整数常见的缩放因子是10000。也就是说DN值5000表示反射率0.5。做地表参数反演之前一定要先阅读产品说明文档确认缩放系数否则计算出来的NDVI等指数会整体偏大或偏小。多景影像做镶嵌或时间序列分析时先用gdalbuildvrt或gdal.Warp统一投影、统一分辨率生成一个虚拟栅格目录这会大大加快后续重复读取的速度。我也看到很多人喜欢直接用SNAP Desktop做预处理和波段运算功能确实全面但如果数据量很大SNAP的图形界面会非常卡。我会优先用命令行或脚本方式先做批量重投影、裁剪和镶嵌只在需要精细目视检查时才打开SNAP。6.3 项目管理角度的几点建议最后分享一点项目管理上的心得一定要把下载脚本、参数配置、产物目录和校验结果都保存下来。一个研究项目往往要持续几个月如果每次重新下载相同的区域浪费的不仅仅是流量和时间还可能因为平台数据更新导致下载结果前后不一致。我会习惯把每次下载的feature id列表保存成CSV或者JSON文件里面记录产品ID、下载时间、文件路径之后复查或复现结果时直接查这个清单效率会高很多。实际上我经历过几次“到底哪一景数据是从哪个批次下载的”这种混乱。如果一开始就做好文件名管理和元数据索引后期处理时能省掉大量重复精力。建议所有做遥感批处理的人都养成“脚本参数清单”统一归档的好习惯这比写任何花哨的代码都更影响最终项目产出。根据我个人经验批量下载Sentinel-2这件事最关键的其实不是代码本身怎么写而是你先找准自己的数据需求理清平台规则再动手。把账号权限、token机制、搜索过滤逻辑、下载并发策略和完整性校验这套流程一次跑通之后后面的所有预处理和分析工作都会顺畅很多。希望这份实操指南能帮你避掉我已经踩过的坑祝你下载顺利。
返回列表