01 说明
1.1 网站和GPP数据集的基本信息
中国科学院地球大数据科学数据中心-网址:https://data.casearth.cn
本博客下载VPM-GPP的网址:https://data.casearth.cn/dataset/5c19a5660600cf2a3c557ad3
2000-2016年全球0.05°基于VPM模型的GPP数据集-产品信息:
1.2 API说明
网站所给API如下:
本博客主要基于通过ID获取文件列表和单文件下载进行VPM-GPP的批量下载,对于元数据信息没有进行获取,但代码可以作为参考。
1.2.1 通过ID获取文件列表
这个Url是不完整的,是相对路径,结合前面的网站地址https://data.casearth.cn和此处的/api/dataset/getAllFileListBySdoId?sdoId=5c19a5660600cf2a3c557ad3拼接得到的网址https://data.casearth.cn/api/dataset/getAllFileListBySdoId?sdoId=5c19a5660600cf2a3c557ad3(通过浏览器即可打开)就是一个文件列表。
结果如下:
但是这里我们不直接下载,我们通过Python直接读取成json文件对这个文件列表进一步处理.(如果想要直接下载直接复制放到文本文件里改个后缀的事情)。
1.2.2 单文件下载
对于单文件下载,这里需要使用到前面获取得到的文件列表的信息补全这里的Url:/api/file/downloadOneFile?fileId=文件Id&username=用户名。
例如取文件列表data中一个文件:{"size":18485479,"file_name":"GPP.VPM.2000321.v20.CMG.tif","id":2148752},需要将id即2148752替换上面Url中的文件Id。
此外还有一个关键点,将用户名替换为登录中国科学院地球大数据科学数据中心后(https://data.casearth.cn)的用户名,注意不是登录时输入的用户名账号,而是登录之后显示的用户名(如下)。
补全之后的Url和之前的网站网址拼接即可得到该文件的下载链接(所以网站为什么索性不直接给一个含下载txt文件让我们自己做,当然现在也还好只是对于不熟悉下载的同学不是很友好)。
最终就是,按照上述的拼接就可以得到指定文件的下载链接例如:https://data.casearth.cn/api/file/downloadOneFile?fileId=2148752&username=何泽煌,现在代码的目标就是一直重复上述操作执行下载。
02 代码说明
完整代码:- # @Author : ChaoQiezi
- # @Time : 2025/7/17 上午11:09
- # @Email : chaoqiezi.one@qq.com
- # @Wechat : GIS茄子
- # @FileName: download_VPM_GPP
- """
- This script is used to 批量下载VPM-GPP
- """
- import requests
- import os
- import time
- # 网站根地址
- base_url = "https://data.casearth.cn"
- # id_url, 网站中所显示的Url
- id_url = "/api/dataset/getAllFileListBySdoId?sdoId=5c19a5660600cf2a3c557ad3"
- # 用户名, 登录后网站显示的名字就是你的用户名, 一般不是登录时的输入账户名
- user_name = "何泽煌"
- # 输出文件夹
- out_dir = r"I:\DataHub\VPM_GPP"
- def get_files_info(base_url, id_url):
- """
- 调用API获取所有文件的信息列表
- :param base_url: 根网址
- :param id_url: 网站中所显示的Url
- :return: 以字典形式返回{file_name: file_id, ···}
- """
- """
- 调用API获取所有文件的信息列表 (文件名 -> 文件ID 的映射)
- """
- # 文件列表的url
- file_info_url = f"{base_url}{id_url}"
- # 获取文件列表的基本信息
- response = requests.get(file_info_url, timeout=30, verify=False) # timeout=30表示超时30s没有链接上报错, verify是因为该网站SSL证书过期了这里不验证
- response.raise_for_status() # 查询请求状态,若请求状态异常说明无法下载直接弹出报错
- files_info = response.json()['data'] # [{'size': xxx, 'file_name': xxx, 'id': xxx}, {}, {}, ···]
- # 获取文件名和id
- files_info = {file['file_name']: file['id'] for file in files_info}
- print(f"成功获取 {len(files_info)} 个文件的信息。")
- return files_info
- def download_file(base_url, filename, file_id, username, save_dir):
- """
- 下载单个文件
- :param base_url: 根网址
- :param filename: 文件名(非自定义的输出, 基于api读取)
- :param file_id: 文件id
- :param username: 用户名(登录后网站显示的名字就是你的用户名, 一般非登录的账户名)
- :param save_dir: 输出文件夹路径
- :return: 成功返回True, 下载失败返回False
- """
- """
- 下载单个文件
- """
- api_url = f"{base_url}/api/file/downloadOneFile?fileId={file_id}&username={username}"
- out_path = os.path.join(save_dir, filename)
- # 如果文件已经存在,则跳过
- if os.path.exists(out_path):
- print(f"文件存在: 文件名-{filename}")
- return True
- print(f"正在下载: 文件名-{filename}, ID-{file_id})")
- try: # 可能由于网络等问题下载容易断开,这里try一下
- with requests.get(api_url, timeout=60, verify=False) as r:
- r.raise_for_status() # 查询请求状态,若请求状态异常说明无法下载报错
- with open(out_path, 'wb') as f:
- # 下方代码表示分块写入为防止下载文件过大而内存爆满, 如果执行这种流式传输,get方法需要设置stream=True
- # for chunk in r.iter_content(chunk_size=8192):
- # f.write(chunk)
- # 一次性写入(确保单个文件大小小于当前可用内存)
- f.write(r.content)
- time.sleep(0.01) # 友好请求,在每次下载后暂停一小段时间,防止因请求过快被服务器屏蔽
- return True
- except Exception as e:
- print(f"下载失败: 文件名-{filename}, 失败原因-{e}")
- time.sleep(0.05)
- return False
- if __name__ == "__main__":
- # 获取文件基本信息
- files_info = get_files_info(base_url, id_url)
- # 遍历下载
- success_count = 0
- for file_name, file_id in files_info.items():
- success_count += download_file(base_url, file_name, file_id, user_name, out_dir)
- print("\n下载完成: 成功-{}, 失败-{}".format(success_count, len(files_info) - success_count))
复制代码 2.1 get_files_info函数说明
简而言之,按照之前的下载链接的拼接方式,我们最关键的是需要所有文件的id,但是由于输出文件时需要指定输出的文件名称,所以这里我还将file_name提取出来与id一一对应。因此这个函数的作用时将从读取的json文件中将file_name和id以字典dict形式返回。形如{文件名_1: 文件的id_1, 文件名_2: 文件的id_2···}
2.2 download_file函数说明
这个函数就是将之前的拼接方式以代码形式呈现得到当前所要下载文件的下载链接,接着通过request库进行进行即可。这里没有具体的说明是因为代码中有较为详细的注释供参考,且函数的参数和使用并不复杂,这里不展开说明,自行研究即可。
本文由博客一文多发平台 OpenWrite 发布!
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |