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, 網站中<API:通過ID獲取文件列表>所顯示的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: 網站中<API:通過ID獲取文件列表>所顯示的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 發佈!