48

私はPythonWeb環境で作業しており、botoのkey.set_contents_from_filename(path / to / file)を使用して、ファイルシステムからS3にファイルをアップロードするだけです。ただし、すでにWeb上にある画像をアップロードしたいと思います(https://pbs.twimg.com/media/A9h_htACIAAaCf6.jpg:largeなど)。

どういうわけか、イメージをファイルシステムにダウンロードしてから、通常どおりbotoを使用してS3にアップロードしてから、イメージを削除する必要がありますか?

理想的なのは、botoのkey.set_contents_from_fileまたは、ファイルコピーをサーバーに明示的にダウンロードしなくても、URLを受け入れて画像をS3に適切にストリーミングするその他のコマンドを取得する方法がある場合です。

def upload(url):
    try:
        conn = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
        bucket_name = settings.AWS_STORAGE_BUCKET_NAME
        bucket = conn.get_bucket(bucket_name)
        k = Key(bucket)
        k.key = "test"
        k.set_contents_from_file(url)
        k.make_public()
                return "Success?"
    except Exception, e:
            return e

上記のようにset_contents_from_fileを使用すると、「文字列オブジェクトに属性'tell'がありません」というエラーが発生します。urlでset_contents_from_filenameを使用すると、「そのようなファイルまたはディレクトリはありません」というエラーが発生します。botoストレージのドキュメントでは、ローカルファイルのアップロードは省略されており、リモートに保存されているファイルのアップロードについては触れられていません。

4

10 に答える 10

24

これが私がリクエストでそれをどのように行ったかです。キーstream=Trueは最初にリクエストを行うときに設定し、upload.fileobj()メソッドを使用してs3にアップロードすることです。

import requests
import boto3

url = "https://upload.wikimedia.org/wikipedia/en/a/a9/Example.jpg"
r = requests.get(url, stream=True)

session = boto3.Session()
s3 = session.resource('s3')

bucket_name = 'your-bucket-name'
key = 'your-key-name' # key is the name of file on your bucket

bucket = s3.Bucket(bucket_name)
bucket.upload_fileobj(r.raw, key)
于 2018-08-09T02:41:40.653 に答える
22

わかりました。@garnaatから、S3が現在URLによるアップロードを許可しているようには聞こえません。リモートイメージをメモリにのみ読み込むことで、S3にアップロードすることができました。これは機能します。

def upload(url):
    try:
        conn = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
        bucket_name = settings.AWS_STORAGE_BUCKET_NAME
        bucket = conn.get_bucket(bucket_name)
        k = Key(bucket)
        k.key = url.split('/')[::-1][0]    # In my situation, ids at the end are unique
        file_object = urllib2.urlopen(url)           # 'Like' a file object
        fp = StringIO.StringIO(file_object.read())   # Wrap object    
        k.set_contents_from_file(fp)
        return "Success"
    except Exception, e:
        return e

また、urllib.urlopen()が返す「ファイルのようなオブジェクト」からGzipFileインスタンスを作成するにはどうすればよいですか?

于 2013-01-15T21:26:00.777 に答える
18

(元の回答の古い「boto」パッケージの代わりに)公式の「boto3」パッケージを使用するこの質問に対する2017関連の回答の場合:

Python 3.5

Pythonをクリーンインストールしている場合は、最初に両方のパッケージをpipインストールします。

pip install boto3

pip install requests

import boto3
import requests

# Uses the creds in ~/.aws/credentials
s3 = boto3.resource('s3')
bucket_name_to_upload_image_to = 'photos'
s3_image_filename = 'test_s3_image.png'
internet_image_url = 'https://docs.python.org/3.7/_static/py.png'


# Do this as a quick and easy check to make sure your S3 access is OK
for bucket in s3.buckets.all():
    if bucket.name == bucket_name_to_upload_image_to:
        print('Good to go. Found the bucket to upload the image into.')
        good_to_go = True

if not good_to_go:
    print('Not seeing your s3 bucket, might want to double check permissions in IAM')

# Given an Internet-accessible URL, download the image and upload it to S3,
# without needing to persist the image to disk locally
req_for_image = requests.get(internet_image_url, stream=True)
file_object_from_req = req_for_image.raw
req_data = file_object_from_req.read()

# Do the actual upload to s3
s3.Bucket(bucket_name_to_upload_image_to).put_object(Key=s3_image_filename, Body=req_data)
于 2017-02-27T18:26:18.080 に答える
10

残念ながら、これを行う方法は実際にはありません。少なくとも現時点ではありません。たとえば、botoにメソッドを追加することもできますset_contents_from_urlが、そのメソッドでは、ファイルをローカルマシンにダウンロードしてから、アップロードする必要があります。それでも便利な方法かもしれませんが、何も節約できません。

あなたが本当にやりたいことをするために、私たちはS3サービス自体にURLを渡し、それが私たちのためにバケットにURLを保存することを可能にするいくつかの機能を持っている必要があります。それはかなり便利な機能のように聞こえます。それをS3フォーラムに投稿することをお勧めします。

于 2013-01-15T20:24:27.803 に答える
6

すぐに使用できるラムダで機能する単純な3行の実装:

import boto3
import requests

s3_object = boto3.resource('s3').Object(bucket_name, object_key)

with requests.get(url, stream=True) as r:
    s3_object.put(Body=r.content)

パーツのソースは、ドキュメント.getから直接取得されますrequests

于 2018-11-20T21:47:20.347 に答える
2

boto3upload_fileobjメソッドを使用すると、ディスクに保存せずにファイルをS3バケットにストリーミングできます。これが私の関数です:

import boto3
import StringIO
import contextlib
import requests

def upload(url):
    # Get the service client
    s3 = boto3.client('s3')

    # Rember to se stream = True.
    with contextlib.closing(requests.get(url, stream=True, verify=False)) as response:
        # Set up file stream from response content.
        fp = StringIO.StringIO(response.content)
        # Upload data to S3
        s3.upload_fileobj(fp, 'my-bucket', 'my-dir/' + url.split('/')[-1])
于 2018-02-16T12:55:01.470 に答える
2

私はboto3で次のように試しましたが、うまくいきました。

import boto3;
import contextlib;
import requests;
from io import BytesIO;

s3 = boto3.resource('s3');
s3Client = boto3.client('s3')
for bucket in s3.buckets.all():
  print(bucket.name)


url = "@resource url";
with contextlib.closing(requests.get(url, stream=True, verify=False)) as response:
        # Set up file stream from response content.
        fp = BytesIO(response.content)
        # Upload data to S3
        s3Client.upload_fileobj(fp, 'aws-books', 'reviews_Electronics_5.json.gz')
于 2018-02-25T22:16:53.223 に答える
2

S3は現在、リモートアップロードをサポートしていないようです。以下のクラスを使用して、S3に画像をアップロードできます。ここでのアップロード方法は、最初に画像のダウンロードを試み、アップロードされるまでしばらくの間メモリに保持します。S3に接続できるようにするには、コマンドを使用してAWS CLIをインストールしてから、コマンドpip install awscliを使用していくつかのクレデンシャルを入力する必要がありaws configureます。

import urllib3
import uuid
from pathlib import Path
from io import BytesIO
from errors import custom_exceptions as cex

BUCKET_NAME = "xxx.yyy.zzz"
POSTERS_BASE_PATH = "assets/wallcontent"
CLOUDFRONT_BASE_URL = "https://xxx.cloudfront.net/"


class S3(object):
    def __init__(self):
        self.client = boto3.client('s3')
        self.bucket_name = BUCKET_NAME
        self.posters_base_path = POSTERS_BASE_PATH

    def __download_image(self, url):
        manager = urllib3.PoolManager()
        try:
            res = manager.request('GET', url)
        except Exception:
            print("Could not download the image from URL: ", url)
            raise cex.ImageDownloadFailed
        return BytesIO(res.data)  # any file-like object that implements read()

    def upload_image(self, url):
        try:
            image_file = self.__download_image(url)
        except cex.ImageDownloadFailed:
            raise cex.ImageUploadFailed

        extension = Path(url).suffix
        id = uuid.uuid1().hex + extension
        final_path = self.posters_base_path + "/" + id
        try:
            self.client.upload_fileobj(image_file,
                                       self.bucket_name,
                                       final_path
                                       )
        except Exception:
            print("Image Upload Error for URL: ", url)
            raise cex.ImageUploadFailed

        return CLOUDFRONT_BASE_URL + id
于 2019-09-18T18:33:12.647 に答える
2
from io import BytesIO
def send_image_to_s3(url, name):
    print("sending image")
    bucket_name = 'XXX'
    AWS_SECRET_ACCESS_KEY = "XXX"
    AWS_ACCESS_KEY_ID = "XXX"

    s3 = boto3.client('s3', aws_access_key_id=AWS_ACCESS_KEY_ID,
                      aws_secret_access_key=AWS_SECRET_ACCESS_KEY)

    response = requests.get(url)
    img = BytesIO(response.content)

    file_name = f'path/{name}'
    print('sending {}'.format(file_name))
    r = s3.upload_fileobj(img, bucket_name, file_name)

    s3_path = 'path/' + name
    return s3_path
于 2021-04-07T14:10:04.613 に答える
1
import boto
from boto.s3.key import Key
from boto.s3.connection import OrdinaryCallingFormat
from urllib import urlopen


def upload_images_s3(img_url):
    try:
        connection = boto.connect_s3('access_key', 'secret_key', calling_format=OrdinaryCallingFormat())       
        bucket = connection.get_bucket('boto-demo-1519388451')
        file_obj = Key(bucket)
        file_obj.key = img_url.split('/')[::-1][0]
        fp = urlopen(img_url)
        result = file_obj.set_contents_from_string(fp.read())
    except Exception, e:
        return e
于 2018-03-01T13:53:42.427 に答える