Python으로 URL의 파일을 S3 버킷에 업로드하는 방법

URL의 응답을 임시 파일 없이 boto3의 upload_fileobj로 바로 스트리밍하세요. 생성된 영상이라면 웹훅을 받을 때 복사하고 바이트를 확인하세요.

읽는 시간 5분Sume
전체 글

URL의 파일을 S3 버킷에 업로드하려면 여러분의 코드에서 파일을 내려받되, 응답 본문을 업로드로 바로 스트리밍해 디스크에 아무것도 남기지 마세요. Python에서는 requests.get(url, stream=True)로 URL을 열고, 그 raw 스트림을 boto3의 upload_fileobj에 넘기세요. upload_fileobj는 필요하면 멀티파트 업로드로 전환하는 관리형 전송입니다. AI로 생성한 영상이라면 실행의 웹훅이 도착했을 때, 레코드를 준비 완료로 표시하기 전에 아티팩트의 media.sume.com URL에서 복사하세요.

AWS 관련 내용은 boto3의 파일 업로드 가이드와 upload_fileobj 레퍼런스, Amazon S3의 객체 업로드 페이지에서, Requests 관련 내용은 빠른 시작과 고급 사용법 페이지에서, Sume 관련 내용은 실행과 결과 (영문), Format 임베드하기 (영문), Sume API 레퍼런스에서 가져왔습니다. 모두 2026-09-27에 확인했습니다. Sume에는 S3 전용 커넥터가 없으며, 복사는 여러분의 코드가 합니다.

Python으로 URL의 파일을 S3로 어떻게 스트리밍하나요?

stream=True를 쓰면 Requests는 처음에 헤더만 내려받고 본문은 읽을 때까지 남겨 두며, Response.raw는 전송된 바이트를 변환하지 않고 그대로 넘겨줍니다. upload_fileobj는 최소한 read를 구현하고 바이트를 반환하는 파일 같은 객체를 받으므로, 작은 래퍼로 boto3가 가져가는 바이트를 세고 해시할 수 있습니다. ContentType은 허용되는 ExtraArgs 가운데 하나이며, 넘길 타입이 없으면 코드는 응답 자체의 Content-Type 헤더를 대신 씁니다. with 블록은 업로드가 실패해도 연결을 닫습니다.

S3는 PUT 한 번으로 최대 5 GB, 멀티파트 업로드로 최대 50 TB까지 받습니다.

import hashlib
import boto3
import requests

s3 = boto3.client("s3")

class HashingReader:
    """Counts and hashes the bytes as boto3 reads them."""
    def __init__(self, raw):
        self.raw, self.sha256, self.size = raw, hashlib.sha256(), 0

    def read(self, *args):
        chunk = self.raw.read(*args)
        self.sha256.update(chunk)
        self.size += len(chunk)
        return chunk

def copy_url_to_s3(url, bucket, key, content_type=None):
    with requests.get(url, stream=True, timeout=30) as resp:
        resp.raise_for_status()
        reader = HashingReader(resp.raw)
        ctype = content_type or resp.headers.get("content-type", "application/octet-stream")
        s3.upload_fileobj(reader, bucket, key, ExtraArgs={"ContentType": ctype})
    return reader.size, reader.sha256.hexdigest()

생성된 영상은 어떤 URL과 필드를 복사해야 하나요?

끝난 Sume Format 실행은 만든 모든 파일을 artifacts[]에 나열하고, primary_output_url은 그중 보여 줄 파일을 가리킵니다. 이 URL은 만료되지 않는 내구성 있는 media.sume.com URL이고 URL을 가진 누구에게나 공개되므로, 읽을 때 API 키가 필요 없습니다. 제품에 고객별 접근 제어가 필요하다면 파일을 복사하세요. 저장할 것은 Sume URL이며, 원본 프로바이더 URL은 절대 저장하지 마세요. POST /v1/videos로 만든 Job은 다릅니다. 그 unsigned_urls는 API 키가 필요한 API 라우트를 가리키며, 이 경우는 API에서 생성된 영상 다운로드하기에서 다룹니다.

실행과 결과 (영문)와 Sume API 레퍼런스 기준, 2026-09-27 확인.
아티팩트 필드용도
url스트리밍할 원본 URL
content_typeS3 객체의 ContentType. null일 수 있음
size_bytes값이 있으면 복사한 바이트 수와 비교. null일 수 있음
checksum_sha256null일 수 있으므로 기대지 말 것. 자체 다이제스트를 보관
idS3 키의 일부. 복사가 반복되어도 같은 객체를 덮어씀

복사는 언제 실행해야 하나요?

웹훅을 받았을 때, 레코드를 준비 완료로 표시하기 전에 실행하세요. Sume의 연동 쿡북은 Sume를 떠나더라도 남는 사본을 원하는 경우에 이 순서를 제시합니다. 웹훅 자체는 10초 안에 2xx를 받아야 하므로, 이벤트를 내구성 있게 기록하고 응답한 다음, 그 시간 제한에 묶이지 않는 백그라운드 작업에서 복사를 실행하세요.

  • 재시도는 전달의 request_id를 그대로 반복하며 최대 10회까지 시도되므로, 복사를 시작하기 전에 이 값으로 중복을 제거하세요.
  • S3 키는 videos/{run_id}/{artifact_id}.mp4처럼 ID로 만드세요. 그러면 복사가 두 번 실행되어도 같은 객체에 씁니다.
  • 애초에 복사할지, 링크만 저장할지는 Sume 영상 URL은 만료되나요?에서 다룹니다.

복사가 끝났는지 어떻게 알 수 있나요?

레코드를 준비 완료로 바꾸기 전에 래퍼가 센 값을 확인하세요.

  • 영수증에 아티팩트의 size_bytes가 있으면 바이트 수를 그 값과 비교하세요.
  • SHA-256 다이제스트를 레코드와 함께 저장하세요. API 레퍼런스는 checksum_sha256을 null일 수 있다고 표시하므로 영수증에 없을 수도 있습니다. 보관할 값은 실제로 업로드한 바이트에서 직접 계산한 다이제스트입니다. 아티팩트에 체크섬이 있다면 둘을 비교하세요.
  • 값이 맞지 않거나 예외가 발생하면 레코드를 준비되지 않은 상태로 두고 복사를 다시 실행하세요. 원본 URL은 만료되지 않으므로 나중에 재시도해도 같은 파일을 읽습니다.

출처

관련 글

연동 카테고리의 다른 글

연동 글 전체 보기

작성자 Sume