【服务器】上传服务器中数据至 FigShare(Python)

目录

  • [步骤 1:将数据准备在服务器上](#步骤 1:将数据准备在服务器上)
  • [步骤 2:获取 Figshare API Token](#步骤 2:获取 Figshare API Token)
  • [步骤 3:在服务器上使用 Python 脚本上传](#步骤 3:在服务器上使用 Python 脚本上传)
    • [案例1:上传全球 LST 数据](#案例1:上传全球 LST 数据)
    • [案例2:上传全球 Ta 数据](#案例2:上传全球 Ta 数据)
  • 参考

步骤 1:将数据准备在服务器上

如果数据已经在服务器: 直接进行下一步。

步骤 2:获取 Figshare API Token

1、登录 Figshare 网页版。

2、点击右上角头像 -> Integrations。

3、在 "Personal Tokens" 下点击 Create Personal Token。

4、保存好这个长字符串(Token),不要给别人看。

bash 复制代码
随机生成如下:
ad234363651b369fd8e1f6c72b575bd3b45c8aa71ab9n41c6ee78970b5fn6802594db64566fd517f2cb33b4d90b8644655c9b4a79498c9783a6b3217de58754

5、获取 Item ID:从 Figshare 网页 URL 或 API 中找到那个已经创建好的 Item 的 ID。

看浏览器地址栏,通常是 https://figshare.com/account/articles/12345678。

这个 12345678 就是 Article ID。

bash 复制代码
https://datahub.hku.hk/account/items/12345678/
Article ID:12345678

步骤 3:在服务器上使用 Python 脚本上传

在服务器上(Linux 或 Windows 均可),创建一个 Python 脚本(例如 upload_to_figshare.py),使用该脚本可以将服务器上的大文件直接传至 Figshare。

案例1:上传全球 LST 数据

服务器运行命令:

bash 复制代码
source activate myenv3.10
nohup python upload_2021Day.py > 2021Day_log.txt 2>&1 &
nohup python -u upload_2021Day.py > 2021Day_log.txt 2>&1 &
nohup python -u upload_2021Nit.py > 2021Nit_log.txt 2>&1 &

nohup python -u upload_2022Day.py > 2022Day_log.txt 2>&1 &
nohup python -u upload_2022Nit.py > 2022Nit_log.txt 2>&1 &

nohup python -u upload_2023Day.py > 2023Day_log.txt 2>&1 &
nohup python -u upload_2023Nit.py > 2023Nit_log.txt 2>&1 &

nohup python -u upload_2024Day.py > 2024Day_log.txt 2>&1 &
nohup python -u upload_2024Nit.py > 2022Nit_log.txt 2>&1 &

说明:

-u 代表 "unbuffered"(无缓存),输出会立刻写入 log 文件

可以随时查看日志文件来监控进度:

bash 复制代码
tail -f upload_log.txt

upload_figshare.py 文件内容如下:

python 复制代码
import os
import hashlib
import json
import requests
import glob

# ================= 配置区域 (请修改这里) =================

# 1. 您的 Figshare Personal Token
TOKEN = '这里填入您的长字符串Token'

# 2. 目标 Item 的 ID (从浏览器地址栏获取,例如 25234567)
# 注意:必须是数字,不要带引号,或者转换成 int
ARTICLE_ID = 12345678  

# 3. 服务器上的数据文件夹路径
SOURCE_DIR = '/geogfs1/groups/scl/Data/Global_LST/2021Day/'

# =======================================================

BASE_URL = 'https://api.figshare.com/v2'
CHUNK_SIZE = 10 * 1024 * 1024  # 10MB 分片大小

def raw_issue_request(method, url, data=None, binary=False):
    headers = {'Authorization': 'token ' + TOKEN}
    if data is not None and not binary:
        data = json.dumps(data)
    
    try:
        response = requests.request(method, url, headers=headers, data=data)
        response.raise_for_status()
        try:
            return json.loads(response.content)
        except ValueError:
            return response.content
    except requests.exceptions.HTTPError as error:
        print(f"HTTP Error: {error}")
        print(f"Response Body: {response.content}")
        raise error

def get_uploaded_files(article_id):
    """获取该 Item 下已经存在的文件列表,用于去重"""
    endpoint = f'{BASE_URL}/account/articles/{article_id}/files'
    files = raw_issue_request('GET', endpoint)
    return {f['name']: f['id'] for f in files}

def initiate_upload(article_id, file_path):
    endpoint = f'{BASE_URL}/account/articles/{article_id}/files'
    file_name = os.path.basename(file_path)
    size = os.path.getsize(file_path)
    
    # 计算 MD5
    print(f"Calculating MD5 for {file_name} (Size: {size/1024/1024:.2f} MB)...")
    md5 = hashlib.md5()
    with open(file_path, 'rb') as f:
        for chunk in iter(lambda: f.read(4096), b""):
            md5.update(chunk)
    
    data = {
        'name': file_name,
        'md5': md5.hexdigest(),
        'size': size
    }
    
    result = raw_issue_request('POST', endpoint, data)
    location = result['location']
    file_info = raw_issue_request('GET', location)
    print(f"Upload initiated for {file_name}")
    return file_info

def upload_parts(file_info, file_path):
    url = file_info['upload_url']
    result = raw_issue_request('GET', url)
    parts = result['parts']
    
    with open(file_path, 'rb') as fin:
        for part in parts:
            part_no = part['partNo']
            start_offset = part['startOffset']
            end_offset = part['endOffset']
            
            fin.seek(start_offset)
            len_chunk = end_offset - start_offset + 1
            data = fin.read(len_chunk)
            
            # print(f"  - Uploading part {part_no}...") # 如果觉得刷屏太快可以注释掉
            raw_issue_request('PUT', f'{url}/{part_no}', data, binary=True)

def complete_upload(article_id, file_id):
    raw_issue_request('POST', f'{BASE_URL}/account/articles/{article_id}/files/{file_id}')

def main():
    # 1. 获取待上传文件列表
    # 匹配文件夹下所有的 .tif 文件
    search_pattern = os.path.join(SOURCE_DIR, "*.tif")
    files_to_upload = sorted(glob.glob(search_pattern))
    
    if not files_to_upload:
        print(f"No .tif files found in {SOURCE_DIR}")
        return

    print(f"Found {len(files_to_upload)} files to upload.")

    # 2. 获取已上传文件列表(防止重复上传)
    existing_files = get_uploaded_files(ARTICLE_ID)
    print(f"Already on Figshare: {len(existing_files)} files.")

    # 3. 循环上传
    for file_path in files_to_upload:
        file_name = os.path.basename(file_path)
        
        if file_name in existing_files:
            print(f"[Skipping] {file_name} already exists.")
            continue
            
        print(f"\n[Processing] {file_name} ...")
        
        try:
            # 初始化
            file_info = initiate_upload(ARTICLE_ID, file_path)
            # 上传分片
            upload_parts(file_info, file_path)
            # 确认完成
            complete_upload(ARTICLE_ID, file_info['id'])
            print(f"[Success] {file_name} uploaded.")
            
        except Exception as e:
            print(f"[Failed] Error uploading {file_name}: {e}")

if __name__ == '__main__':
    main()

案例2:上传全球 Ta 数据

参考

相关推荐
宝贝儿好1 小时前
【强化学习】第十章:随机高斯策略
人工智能·python·深度学习·神经网络·机器人·自动驾驶
haosend1 小时前
【练习版】使用paramiko批量的查询,管理,配置路由器交换机
python·路由器·交换机·网络自动化
Dxy12393102162 小时前
Python生成随机手机号码
开发语言·python
小义_2 小时前
【Docker】知识四
linux·运维·docker·容器
小志biubiu2 小时前
Linux_进程概念(A)-进程部分【Ubuntu】
linux·运维·服务器·ubuntu·操作系统·进程
小帅学编程2 小时前
Python学习
开发语言·python·学习
普通网友2 小时前
Ubuntu 入门及安装全指南
linux·运维·ubuntu
冷雨夜中漫步2 小时前
DockerDesktop打包docker镜像时报错
运维·docker·容器
两万五千个小时2 小时前
构建mini Claude Code:08 - Fire and Forget:用后台线程解锁 Multi-Agent 并行执行
人工智能·python·架构