Boto3 zum Herunterladen aller Dateien aus einem S3-Bucket

82

Ich benutze boto3, um Dateien aus dem s3-Bucket zu bekommen. Ich brauche eine ähnliche Funktionalität wieaws s3 sync

Mein aktueller Code ist

#!/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'])

Dies funktioniert einwandfrei, solange der Bucket nur Dateien enthält. Wenn sich ein Ordner im Bucket befindet, wird ein Fehler ausgegeben

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'

Ist dies ein geeigneter Weg, um einen kompletten s3-Bucket mit boto3 herunterzuladen? So laden Sie Ordner herunter.

Shan
quelle

Antworten:

34

Wenn Sie mit Buckets mit mehr als 1000 Objekten arbeiten, müssen Sie eine Lösung implementieren, die die NextContinuationTokenaufeinander folgenden Sätze von höchstens 1000 Schlüsseln verwendet. Diese Lösung erstellt zuerst eine Liste von Objekten, erstellt dann iterativ die angegebenen Verzeichnisse und lädt die vorhandenen Objekte herunter.

import boto3
import os

s3_client = boto3.client('s3')

def download_dir(prefix, local, bucket, client=s3_client):
    """
    params:
    - prefix: pattern to match in s3
    - local: local path to folder in which to place files
    - bucket: s3 bucket with target contents
    - client: initialized s3 client object
    """
    keys = []
    dirs = []
    next_token = ''
    base_kwargs = {
        'Bucket':bucket,
        'Prefix':prefix,
    }
    while next_token is not None:
        kwargs = base_kwargs.copy()
        if next_token != '':
            kwargs.update({'ContinuationToken': next_token})
        results = client.list_objects_v2(**kwargs)
        contents = results.get('Contents')
        for i in contents:
            k = i.get('Key')
            if k[-1] != '/':
                keys.append(k)
            else:
                dirs.append(k)
        next_token = results.get('NextContinuationToken')
    for d in dirs:
        dest_pathname = os.path.join(local, d)
        if not os.path.exists(os.path.dirname(dest_pathname)):
            os.makedirs(os.path.dirname(dest_pathname))
    for k in keys:
        dest_pathname = os.path.join(local, k)
        if not os.path.exists(os.path.dirname(dest_pathname)):
            os.makedirs(os.path.dirname(dest_pathname))
        client.download_file(bucket, k, dest_pathname)
Grant Langseth
quelle
Ändern Sie diese in eine akzeptierte Antwort, da sie einen breiteren Anwendungsfall behandelt. Vielen Dank Grant
Shan
Mein Code geht in eine Endlosschleife umwhile next_token is not None:
gpd
@gpd Dies sollte nicht passieren, da der boto3-Client eine Seite ohne NextContinuationToken zurückgibt, wenn er die letzte Seite erreicht hat und die while-Anweisung beendet. Wenn Sie die letzte Antwort einfügen, die Sie durch die Verwendung der boto3-API erhalten (was auch immer in der Antwortvariablen gespeichert ist), wird meiner Meinung nach klarer, was in Ihrem speziellen Fall passiert. Versuchen Sie, die Variable 'results' nur zum Testen auszudrucken. Ich vermute, Sie haben ein Präfixobjekt angegeben, das keinem Inhalt Ihres Buckets entspricht. Hast du das überprüft?
Grant Langseth
Beachten Sie, dass Sie geringfügige Änderungen benötigen, damit Digital Ocean funktioniert. wie hier
David D.
1
Bei Verwendung dieses Codes wird folgende Fehlermeldung angezeigt: Das Objekt 'NoneType' ist nicht iterierbar: TypeError
NJones
76

Ich habe die gleichen Anforderungen und habe die folgende Funktion erstellt, mit der die Dateien rekursiv heruntergeladen werden.

Die Verzeichnisse werden nur dann lokal erstellt, wenn sie Dateien enthalten.

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)
        for file in result.get('Contents', []):
            dest_pathname = os.path.join(local, file.get('Key'))
            if not os.path.exists(os.path.dirname(dest_pathname)):
                os.makedirs(os.path.dirname(dest_pathname))
            resource.meta.client.download_file(bucket, file.get('Key'), dest_pathname)

Die Funktion heißt so:

def _start():
    client = boto3.client('s3')
    resource = boto3.resource('s3')
    download_dir(client, resource, 'clientconf/', '/tmp', bucket='my-bucket')
Glefait
quelle
6
Ich glaube nicht, dass Sie eine Ressource und einen Client erstellen müssen. Ich glaube, ein Kunde ist immer in der Ressource verfügbar. Sie können einfach verwenden resource.meta.client.
TheHerk
2
Ich denke, das sollte "download_dir (Client, Ressource, subdir.get ('Präfix'), lokal, Bucket )" sein
rm999
6
Ich bekam eine, OSError: [Errno 21] Is a directoryalso habe ich den Aufruf von download_file mit aufgelöst if not file.get('Key').endswith('/'). Vielen Dank, dass Sie @glefait und @Shan
user336828
5
Gibt aws s3 synces in der boto3-Bibliothek nicht ein Äquivalent zum Befehl aws-cli ?
Greperror
8
Was ist disthier
Rob Rose
49

Amazon S3 verfügt nicht über Ordner / Verzeichnisse. Es ist eine flache Dateistruktur .

Um das Erscheinungsbild von Verzeichnissen beizubehalten, werden Pfadnamen als Teil des Objektschlüssels (Dateiname) gespeichert . Zum Beispiel:

  • images/foo.jpg

In diesem Fall ist der gesamte Schlüssel images/foo.jpgnicht nur foo.jpg.

Ich vermute, dass Ihr Problem darin besteht, dass botoeine aufgerufene Datei zurückgegeben wird my_folder/.8Df54234und versucht wird, sie im lokalen Dateisystem zu speichern. Ihr lokales Dateisystem interpretiert den my_folder/Teil jedoch als Verzeichnisnamen, und dieses Verzeichnis ist in Ihrem lokalen Dateisystem nicht vorhanden .

Sie könnten entweder den Dateinamen abschneiden, um nur den .8Df54234Teil zu speichern , oder Sie müssten die erforderlichen Verzeichnisse erstellen, bevor Sie Dateien schreiben. Beachten Sie, dass es sich um mehrstufige verschachtelte Verzeichnisse handeln kann.

Eine einfachere Möglichkeit wäre die Verwendung der AWS-Befehlszeilenschnittstelle (CLI) , die all diese Arbeiten für Sie erledigt, z.

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

Es gibt auch eine syncOption, die nur neue und geänderte Dateien kopiert.

John Rotenstein
quelle
1
@j Ich verstehe das. Aber ich musste den Ordner erstellen, automatisch genau wie aws s3 sync. Ist es in boto3 möglich.
Shan
4
Sie müssten die Erstellung eines Verzeichnisses als Teil Ihres Python-Codes einschließen. Wenn der Schlüssel ein Verzeichnis enthält (z. B. foo/bar.txt), sind Sie dafür verantwortlich, das Verzeichnis ( foo) vor dem Aufruf zu erstellen s3.download_file. Es ist keine automatische Fähigkeit von boto.
John Rotenstein
Hier ist der Inhalt des S3-Buckets dynamisch, daher muss ich nach s3.list_objects(Bucket='my_bucket_name')['Contents']Ordnerschlüsseln suchen, diese filtern und erstellen.
Shan
2
Nachdem Sie eine Weile mit Boto3 herumgespielt haben, ist der hier aufgeführte AWS CLI-Befehl definitiv der einfachste Weg, dies zu tun.
AdjunctProfessorFalcon
1
@Ben Bitte starten Sie eine neue Frage, anstatt eine Frage als Kommentar zu einer alten (2015) Frage zu stellen.
John Rotenstein
43
import os
import boto3

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

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

# download file into current directory
for s3_object in my_bucket.objects.all():
    # Need to split s3_object.key into path and file name, else it will give error file not found.
    path, filename = os.path.split(s3_object.key)
    my_bucket.download_file(s3_object.key, filename)
Tushar Niras
quelle
3
Sauber und einfach, warum nicht? Es ist viel verständlicher als alle anderen Lösungen. Sammlungen scheinen im Hintergrund viele Dinge für Sie zu tun.
Joost
3
Ich denke, Sie sollten zuerst alle Unterordner erstellen, damit dies ordnungsgemäß funktioniert.
Panai
2
Dieser Code legt alles im Ausgabeverzeichnis der obersten Ebene ab, unabhängig davon, wie tief es in S3 verschachtelt ist. Und wenn mehrere Dateien in verschiedenen Verzeichnissen denselben Namen haben, stampft es miteinander. Ich denke, Sie brauchen noch eine Zeile : os.makedirs(path), und dann sollte das Download-Ziel sein object.key.
Scott Smith
13

Ich erreiche gerade die Aufgabe, indem ich Folgendes verwende

#!/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)

Obwohl es den Job macht, bin ich mir nicht sicher, ob es gut ist, dies zu tun. Ich lasse es hier, um anderen Benutzern und weiteren Antworten zu helfen, um dies besser zu erreichen

Shan
quelle
9

Besser spät als nie :) Die vorherige Antwort mit Paginator ist wirklich gut. Es ist jedoch rekursiv und es kann vorkommen, dass Sie die Rekursionsgrenzen von Python erreichen. Hier ist ein alternativer Ansatz mit ein paar zusätzlichen Überprüfungen.

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')
ifoukarakis
quelle
1
Verstanden KeyError: 'Contents'. Eingabepfad '/arch/R/storeincomelogs/, vollständiger Pfad /arch/R/storeincomelogs/201901/01/xxx.parquet.
Mithril
3

Ich habe eine Problemumgehung dafür, die die AWS-CLI im selben Prozess ausführt.

awscliAls Python-Bibliothek installieren :

pip install awscli

Dann definieren Sie diese Funktion:

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)

Ausführen:

aws_cli('s3', 'sync', '/path/to/source', 's3://bucket/destination', '--delete')
mattalxndr
quelle
Ich habe die gleiche Idee verwendet, aber ohne den syncBefehl zu verwenden und den Befehl einfach auszuführen aws s3 cp s3://{bucket}/{folder} {local_folder} --recursive. Die Zeiten wurden von Minuten (fast 1
Stunde
Ich verwende diesen Code, habe jedoch ein Problem, bei dem alle Debug-Protokolle angezeigt werden. Ich habe dies global deklariert: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING) logger = logging.getLogger()und möchte nur, dass Protokolle von root ausgegeben werden. Irgendwelche Ideen?
April Polubiec
1

Es ist eine sehr schlechte Idee, alle Dateien auf einmal abzurufen. Sie sollten sie lieber stapelweise abrufen.

Eine Implementierung, mit der ich einen bestimmten Ordner (Verzeichnis) aus S3 abrufe, ist:

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])

und trotzdem, wenn Sie den ganzen Eimer bekommen möchten, verwenden Sie ihn über CIL als @John Rotenstein, wie unten erwähnt,

aws s3 cp --recursive s3://bucket_name download_path
Ganatra
quelle
0
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')

Dieser Code lädt den Inhalt im /tmp/Verzeichnis herunter . Wenn Sie möchten, können Sie das Verzeichnis ändern.

Rajesh Rajendran
quelle
0

Wenn Sie ein Bash-Skript mit Python aufrufen möchten, können Sie eine Datei auf einfache Weise aus einem Ordner im S3-Bucket in einen lokalen Ordner (auf einem Linux-Computer) laden:

import boto3
import subprocess
import os

###TOEDIT###
my_bucket_name = "your_my_bucket_name"
bucket_folder_name = "your_bucket_folder_name"
local_folder_path = "your_local_folder_path"
###TOEDIT###

# 1.Load thes list of files existing in the bucket folder
FILES_NAMES = []
s3 = boto3.resource('s3')
my_bucket = s3.Bucket('{}'.format(my_bucket_name))
for object_summary in my_bucket.objects.filter(Prefix="{}/".format(bucket_folder_name)):
#     print(object_summary.key)
    FILES_NAMES.append(object_summary.key)

# 2.List only new files that do not exist in local folder (to not copy everything!)
new_filenames = list(set(FILES_NAMES )-set(os.listdir(local_folder_path)))

# 3.Time to load files in your destination folder 
for new_filename in new_filenames:
    upload_S3files_CMD = """aws s3 cp s3://{}/{}/{} {}""".format(my_bucket_name,bucket_folder_name,new_filename ,local_folder_path)

    subprocess_call = subprocess.call([upload_S3files_CMD], shell=True)
    if subprocess_call != 0:
        print("ALERT: loading files not working correctly, please re-check new loaded files")
HazimoRa3d
quelle
0

Ich habe die ähnliche Anforderung erhalten und Hilfe beim Lesen einiger der oben genannten Lösungen erhalten. Auf anderen Websites habe ich mir das folgende Skript ausgedacht. Ich wollte nur mitteilen, ob es jemandem helfen könnte.

from boto3.session import Session
import os

def sync_s3_folder(access_key_id,secret_access_key,bucket_name,folder,destination_path):    
    session = Session(aws_access_key_id=access_key_id,aws_secret_access_key=secret_access_key)
    s3 = session.resource('s3')
    your_bucket = s3.Bucket(bucket_name)
    for s3_file in your_bucket.objects.all():
        if folder in s3_file.key:
            file=os.path.join(destination_path,s3_file.key.replace('/','\\'))
            if not os.path.exists(os.path.dirname(file)):
                os.makedirs(os.path.dirname(file))
            your_bucket.download_file(s3_file.key,file)
sync_s3_folder(access_key_id,secret_access_key,bucket_name,folder,destination_path)
Kranti
quelle
0

Reposting @glefaits Antwort mit einer if-Bedingung am Ende, um OS-Fehler 20 zu vermeiden. Der erste Schlüssel, den es erhält, ist der Ordnername selbst, der nicht in den Zielpfad geschrieben werden kann.

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)
        for file in result.get('Contents', []):
            print("Content: ",result)
            dest_pathname = os.path.join(local, file.get('Key'))
            print("Dest path: ",dest_pathname)
            if not os.path.exists(os.path.dirname(dest_pathname)):
                print("here last if")
                os.makedirs(os.path.dirname(dest_pathname))
            print("else file key: ", file.get('Key'))
            if not file.get('Key') == dist:
                print("Key not equal? ",file.get('Key'))
                resource.meta.client.download_file(bucket, file.get('Key'), dest_pathname)enter code here
vinay
quelle
0

Ich bin schon eine Weile auf dieses Problem gestoßen und mit all den verschiedenen Foren, die ich durchlaufen habe, habe ich keinen vollständigen Überblick darüber gesehen, was funktioniert. Also habe ich alle Teile genommen (einige Sachen selbst hinzugefügt) und einen vollständigen End-to-End-S3-Downloader erstellt!

Dadurch werden Dateien nicht nur automatisch heruntergeladen, sondern wenn sich die S3-Dateien in Unterverzeichnissen befinden, werden sie im lokalen Speicher erstellt. In der Instanz meiner Anwendung muss ich Berechtigungen und Eigentümer festlegen, damit ich dies ebenfalls hinzugefügt habe (kann kommentiert werden, wenn es nicht benötigt wird).

Dies wurde getestet und funktioniert in einer Docker-Umgebung (K8), aber ich habe die Umgebungsvariablen im Skript hinzugefügt, nur für den Fall, dass Sie es lokal testen / ausführen möchten.

Ich hoffe, dies hilft jemandem bei der Suche nach S3-Download-Automatisierung. Ich freue mich auch über Ratschläge, Informationen usw., wie dies bei Bedarf besser optimiert werden kann.

#!/usr/bin/python3
import gc
import logging
import os
import signal
import sys
import time
from datetime import datetime

import boto
from boto.exception import S3ResponseError
from pythonjsonlogger import jsonlogger

formatter = jsonlogger.JsonFormatter('%(message)%(levelname)%(name)%(asctime)%(filename)%(lineno)%(funcName)')

json_handler_out = logging.StreamHandler()
json_handler_out.setFormatter(formatter)

#Manual Testing Variables If Needed
#os.environ["DOWNLOAD_LOCATION_PATH"] = "some_path"
#os.environ["BUCKET_NAME"] = "some_bucket"
#os.environ["AWS_ACCESS_KEY"] = "some_access_key"
#os.environ["AWS_SECRET_KEY"] = "some_secret"
#os.environ["LOG_LEVEL_SELECTOR"] = "DEBUG, INFO, or ERROR"

#Setting Log Level Test
logger = logging.getLogger('json')
logger.addHandler(json_handler_out)
logger_levels = {
    'ERROR' : logging.ERROR,
    'INFO' : logging.INFO,
    'DEBUG' : logging.DEBUG
}
logger_level_selector = os.environ["LOG_LEVEL_SELECTOR"]
logger.setLevel(logger_level_selector)

#Getting Date/Time
now = datetime.now()
logger.info("Current date and time : ")
logger.info(now.strftime("%Y-%m-%d %H:%M:%S"))

#Establishing S3 Variables and Download Location
download_location_path = os.environ["DOWNLOAD_LOCATION_PATH"]
bucket_name = os.environ["BUCKET_NAME"]
aws_access_key_id = os.environ["AWS_ACCESS_KEY"]
aws_access_secret_key = os.environ["AWS_SECRET_KEY"]
logger.debug("Bucket: %s" % bucket_name)
logger.debug("Key: %s" % aws_access_key_id)
logger.debug("Secret: %s" % aws_access_secret_key)
logger.debug("Download location path: %s" % download_location_path)

#Creating Download Directory
if not os.path.exists(download_location_path):
    logger.info("Making download directory")
    os.makedirs(download_location_path)

#Signal Hooks are fun
class GracefulKiller:
    kill_now = False
    def __init__(self):
        signal.signal(signal.SIGINT, self.exit_gracefully)
        signal.signal(signal.SIGTERM, self.exit_gracefully)
    def exit_gracefully(self, signum, frame):
        self.kill_now = True

#Downloading from S3 Bucket
def download_s3_bucket():
    conn = boto.connect_s3(aws_access_key_id, aws_access_secret_key)
    logger.debug("Connection established: ")
    bucket = conn.get_bucket(bucket_name)
    logger.debug("Bucket: %s" % str(bucket))
    bucket_list = bucket.list()
#    logger.info("Number of items to download: {0}".format(len(bucket_list)))

    for s3_item in bucket_list:
        key_string = str(s3_item.key)
        logger.debug("S3 Bucket Item to download: %s" % key_string)
        s3_path = download_location_path + "/" + key_string
        logger.debug("Downloading to: %s" % s3_path)
        local_dir = os.path.dirname(s3_path)

        if not os.path.exists(local_dir):
            logger.info("Local directory doesn't exist, creating it... %s" % local_dir)
            os.makedirs(local_dir)
            logger.info("Updating local directory permissions to %s" % local_dir)
#Comment or Uncomment Permissions based on Local Usage
            os.chmod(local_dir, 0o775)
            os.chown(local_dir, 60001, 60001)
        logger.debug("Local directory for download: %s" % local_dir)
        try:
            logger.info("Downloading File: %s" % key_string)
            s3_item.get_contents_to_filename(s3_path)
            logger.info("Successfully downloaded File: %s" % s3_path)
            #Updating Permissions
            logger.info("Updating Permissions for %s" % str(s3_path))
#Comment or Uncomment Permissions based on Local Usage
            os.chmod(s3_path, 0o664)
            os.chown(s3_path, 60001, 60001)
        except (OSError, S3ResponseError) as e:
            logger.error("Fatal error in s3_item.get_contents_to_filename", exc_info=True)
            # logger.error("Exception in file download from S3: {}".format(e))
            continue
        logger.info("Deleting %s from S3 Bucket" % str(s3_item.key))
        s3_item.delete()

def main():
    killer = GracefulKiller()
    while not killer.kill_now:
        logger.info("Checking for new files on S3 to download...")
        download_s3_bucket()
        logger.info("Done checking for new files, will check in 120s...")
        gc.collect()
        sys.stdout.flush()
        time.sleep(120)
if __name__ == '__main__':
    main()
Genosse35
quelle
0

Aus AWS S3-Dokumenten (Wie verwende ich Ordner in einem S3-Bucket?):

In Amazon S3 sind Buckets und Objekte die primären Ressourcen, und Objekte werden in Buckets gespeichert. Amazon S3 hat eine flache Struktur anstelle einer Hierarchie, wie Sie sie in einem Dateisystem sehen würden. Der Einfachheit halber unterstützt die Amazon S3-Konsole das Ordnerkonzept als Mittel zum Gruppieren von Objekten. Amazon S3 verwendet dazu ein gemeinsames Namenspräfix für Objekte (dh Objekte haben Namen, die mit einer gemeinsamen Zeichenfolge beginnen). Objektnamen werden auch als Schlüsselnamen bezeichnet.

Sie können beispielsweise auf der Konsole einen Ordner mit dem Namen photos erstellen und ein Objekt mit dem Namen myphoto.jpg darin speichern. Das Objekt wird dann mit dem Schlüsselnamen photos / myphoto.jpg gespeichert, wobei photos / das Präfix ist.

So laden Sie alle Dateien von "mybucket" unter Berücksichtigung der emulierten Verzeichnisstruktur des Buckets in das aktuelle Verzeichnis herunter (Erstellen der Ordner aus dem Bucket, falls sie nicht bereits lokal vorhanden sind):

import boto3
import os

bucket_name = "mybucket"
s3 = boto3.client("s3")
objects = s3.list_objects(Bucket = bucket_name)["Contents"]
for s3_object in objects:
    s3_key = s3_object["Key"]
    path, filename = os.path.split(s3_key)
    if len(path) != 0 and not os.path.exists(path):
        os.makedirs(path)
    if not s3_key.endswith("/"):
        download_to = path + '/' + filename if path else filename
        s3.download_file(bucket_name, s3_key, download_to)
Daria
quelle
Es wäre besser, wenn Sie eine Erklärung Ihres Codes hinzufügen könnten.
Johan
1
@johan, danke für das Feedback! Ich habe relevante Erklärung hinzugefügt
Daria