Pertanyaan Boto3 untuk mengunduh semua file dari Bucket S3


Saya menggunakan boto3 untuk mendapatkan file dari keranjang s3. Saya membutuhkan fungsi serupa seperti aws s3 sync

Kode saya saat ini

#!/usr/bin/python
import boto3
s3=boto3.client('s3')
list=s3.list_objects(Bucket='my_bucket_name')['Contents']
for key in list:
    s3.download_file('my_bucket_name', key['Key'], key['Key'])

Ini berfungsi dengan baik, asalkan keranjang hanya memiliki file. Jika ada folder di dalam keranjang, itu melempar kesalahan

Traceback (most recent call last):
  File "./test", line 6, in <module>
    s3.download_file('my_bucket_name', key['Key'], key['Key'])
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/inject.py", line 58, in download_file
    extra_args=ExtraArgs, callback=Callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 651, in download_file
    extra_args, callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 666, in _download_file
    self._get_object(bucket, key, filename, extra_args, callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 690, in _get_object
    extra_args, callback)
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 707, in _do_get_object
    with self._osutil.open(filename, 'wb') as f:
  File "/usr/local/lib/python2.7/dist-packages/boto3/s3/transfer.py", line 323, in open
    return open(filename, mode)
IOError: [Errno 2] No such file or directory: 'my_folder/.8Df54234'

Apakah ini cara yang tepat untuk mengunduh keranjang s3 lengkap menggunakan boto3. Cara mengunduh folder.


33
2017-08-10 11:58


asal


Jawaban:


Saya mendapat kebutuhan yang sama dan membuat fungsi berikut yang mengunduh file secara rekursif. Direktori dibuat secara lokal hanya jika berisi file.

import boto3
import os

def download_dir(client, resource, dist, local='/tmp', bucket='your_bucket'):
    paginator = client.get_paginator('list_objects')
    for result in paginator.paginate(Bucket=bucket, Delimiter='/', Prefix=dist):
        if result.get('CommonPrefixes') is not None:
            for subdir in result.get('CommonPrefixes'):
                download_dir(client, resource, subdir.get('Prefix'), local, bucket)
        if result.get('Contents') is not None:
            for file in result.get('Contents'):
                if not os.path.exists(os.path.dirname(local + os.sep + file.get('Key'))):
                     os.makedirs(os.path.dirname(local + os.sep + file.get('Key')))
                resource.meta.client.download_file(bucket, file.get('Key'), local + os.sep + file.get('Key'))

Fungsi ini disebut demikian:

def _start():
    client = boto3.client('s3')
    resource = boto3.resource('s3')
    download_dir(client, resource, 'clientconf/', '/tmp')

40
2017-10-26 16:06



Amazon S3 tidak memiliki folder / direktori. Ini adalah sebuah struktur file datar.

Untuk menjaga tampilan direktori, nama jalan disimpan sebagai bagian dari kunci objek (nama file). Sebagai contoh:

  • images/foo.jpg

Dalam hal ini, mereka seluruh Kunci adalah images/foo.jpg, bukan hanya foo.jpg.

Saya menduga bahwa masalah Anda adalah itu boto mengembalikan file bernama my_folder/.8Df54234 dan berusaha menyimpannya ke sistem file lokal. Namun, filesystem lokal Anda menafsirkan my_folder/ bagian sebagai nama direktori, dan direktori itu tidak ada di sistem file lokal Anda.

Anda juga bisa memotong nama file hanya menyimpan .8Df54234 porsi, atau Anda harus buat direktori yang diperlukan sebelum menulis file. Perhatikan bahwa itu bisa berupa direktori bertingkat multi-level.

Cara yang lebih mudah adalah menggunakan Antarmuka Baris Perintah AWS (CLI), yang akan melakukan semua ini untuk Anda, misalnya:

aws s3 cp --recursive s3://my_bucket_name local_folder

Ada juga a sync opsi yang hanya akan menyalin file baru dan diubah.


28
2017-08-10 21:13



import os
import boto3

#intiate s3 resource
s3 = boto3.resource('s3')

# select bucket
my_bucket = s3.Bucket('my_bucket_name')

# download file into current directory
for object in my_bucket.objects.all():
    my_bucket.download_file(object.key, os.path.join(os.curdir, object.key))

14
2018-04-05 15:52



Saat ini saya mencapai tugas, dengan menggunakan yang berikut ini

#!/usr/bin/python
import boto3
s3=boto3.client('s3')
list=s3.list_objects(Bucket='bucket')['Contents']
for s3_key in list:
    s3_object = s3_key['Key']
    if not s3_object.endswith("/"):
        s3.download_file('bucket', s3_object, s3_object)
    else:
        import os
        if not os.path.exists(s3_object):
            os.makedirs(s3_object)

Meskipun, ia melakukan pekerjaan itu, saya tidak yakin itu baik untuk melakukan cara ini. Saya meninggalkannya di sini untuk membantu pengguna lain dan jawaban lebih lanjut, dengan cara yang lebih baik dalam mencapai hal ini


7
2017-08-12 08:55



Lebih baik terlambat daripada tidak pernah :) Jawaban sebelumnya dengan paginator benar-benar baik. Namun itu rekursif, dan Anda mungkin akhirnya memukul batas rekombinasi Python. Berikut ini pendekatan alternatif, dengan beberapa pemeriksaan ekstra.

import os
import errno
import boto3


def assert_dir_exists(path):
    """
    Checks if directory tree in path exists. If not it created them.
    :param path: the path to check if it exists
    """
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise


def download_dir(client, bucket, path, target):
    """
    Downloads recursively the given S3 path to the target directory.
    :param client: S3 client to use.
    :param bucket: the name of the bucket to download from
    :param path: The S3 directory to download.
    :param target: the local directory to download the files to.
    """

    # Handle missing / at end of prefix
    if not path.endswith('/'):
        path += '/'

    paginator = client.get_paginator('list_objects_v2')
    for result in paginator.paginate(Bucket=bucket, Prefix=path):
        # Download each file individually
        for key in result['Contents']:
            # Calculate relative path
            rel_path = key['Key'][len(path):]
            # Skip paths ending in /
            if not key['Key'].endswith('/'):
                local_file_path = os.path.join(target, rel_path)
                # Make sure directories exist
                local_file_dir = os.path.dirname(local_file_path)
                assert_dir_exists(local_file_dir)
                client.download_file(bucket, key['Key'], local_file_path)


client = boto3.client('s3')

download_dir(client, 'bucket-name', 'path/to/data', 'downloads')

2
2018-02-06 22:24



Ini adalah ide yang sangat buruk untuk mendapatkan semua file sekaligus, Anda harus mendapatkannya dalam batch.

Salah satu implementasi yang saya gunakan untuk mengambil folder tertentu (direktori) dari S3 adalah,

def get_directory(directory_path, download_path, exclude_file_names):
    # prepare session
    session = Session(aws_access_key_id, aws_secret_access_key, region_name)

    # get instances for resource and bucket
    resource = session.resource('s3')
    bucket = resource.Bucket(bucket_name)

    for s3_key in self.client.list_objects(Bucket=self.bucket_name, Prefix=directory_path)['Contents']:
        s3_object = s3_key['Key']
        if s3_object not in exclude_file_names:
            bucket.download_file(file_path, download_path + str(s3_object.split('/')[-1])

dan masih jika Anda ingin mendapatkan seluruh ember menggunakannya melalui CIL sebagai @ John Rotenstein disebutkan seperti di bawah ini,

aws s3 cp --recursive s3://bucket_name download_path

1
2017-11-16 19:36



Saya memiliki solusi untuk ini yang menjalankan AWS CLI dalam proses yang sama.

Memasang awscli sebagai python lib:

pip install awscli

Kemudian definisikan fungsi ini:

from awscli.clidriver import create_clidriver

def aws_cli(*cmd):
    old_env = dict(os.environ)
    try:

        # Environment
        env = os.environ.copy()
        env['LC_CTYPE'] = u'en_US.UTF'
        os.environ.update(env)

        # Run awscli in the same process
        exit_code = create_clidriver().main(*cmd)

        # Deal with problems
        if exit_code > 0:
            raise RuntimeError('AWS CLI exited with code {}'.format(exit_code))
    finally:
        os.environ.clear()
        os.environ.update(old_env)

Untuk mengeksekusi:

aws_cli('s3', 'sync', '/path/to/source', 's3://bucket/destination', '--delete')

1
2018-03-11 06:50



for objs in my_bucket.objects.all():
    print(objs.key)
    path='/tmp/'+os.sep.join(objs.key.split(os.sep)[:-1])
    try:
        if not os.path.exists(path):
            os.makedirs(path)
        my_bucket.download_file(objs.key, '/tmp/'+objs.key)
    except FileExistsError as fe:                          
        print(objs.key+' exists')

Kode ini akan mengunduh konten dalam /tmp/ direktori. Jika mau, Anda dapat mengubah direktori.


0
2017-08-08 11:06