Wyświetlanie zawartości wiadra za pomocą boto3

198

Jak mogę zobaczyć, co znajduje się w wiadrze w S3 boto3? (tj. zrobić "ls")?

Wykonując następujące czynności:

import boto3
s3 = boto3.resource('s3')
my_bucket = s3.Bucket('some/path/')

zwroty:

s3.Bucket(name='some/path/')

Jak mogę zobaczyć jego zawartość?

Amelio Vazquez-Reina
źródło

Odpowiedzi:

242

Jednym ze sposobów zobaczenia zawartości byłoby:

for my_bucket_object in my_bucket.objects.all():
    print(my_bucket_object)
garnaat
źródło
1
czy mogę pobrać klucze pod określoną ścieżką w wiadrze lub za pomocą określonego separatora za pomocą boto3?
Rahul KP
109
Powinieneś być w stanie powiedzieć, mybucket.objects.filter(Prefix='foo/bar')a wyświetli się lista obiektów z tym prefiksem. Możesz także przekazać Delimiterparametr.
garnaat
3
nie działa z boto3 AttributeError: Obiekt „S3” nie ma atrybutu „objects”
Shek
2
@garnaat Twój komentarz dotyczący tej metody filtrowania naprawdę mi pomógł (mój kod był znacznie prostszy i szybszy) - dziękuję!
Edward Dixon,
24
Odradzałbym używanie objectjako nazwy zmiennej, ponieważ będzie to cień globalnego typu object.
oliland
100

Jest to podobne do „ls”, ale nie uwzględnia konwencji folderów z prefiksem i wyświetla listę obiektów w segmencie. Czytelnik musi odfiltrować prefiksy, które są częścią nazwy klucza.

W Python 2:

from boto.s3.connection import S3Connection

conn = S3Connection() # assumes boto.cfg setup
bucket = conn.get_bucket('bucket_name')
for obj in bucket.get_all_keys():
    print(obj.key)

W Pythonie 3:

from boto3 import client

conn = client('s3')  # again assumes boto.cfg setup, assume AWS S3
for key in conn.list_objects(Bucket='bucket_name')['Contents']:
    print(key['Key'])
cgseller
źródło
39
Jeśli chcesz również użyć prefiksu, możesz to zrobić w następujący sposób:conn.list_objects(Bucket='bucket_name', Prefix='prefix_string')['Contents']
markonovak
13
Zawiera tylko pierwsze 1000 kluczy. Z dokumentacji: „Zwraca część lub całość (do 1000) obiektów w wiadrze”. Zalecane jest także użycie list_objects_v2 zamiast list_objects (chociaż zwraca to tylko pierwsze 1000 kluczy).
Brett Widmeier
3
Ograniczenie to powinno być rozpatrywane przy użyciu Paginators
V25
44

Zakładam, że osobno skonfigurowałeś uwierzytelnianie.

import boto3
s3 = boto3.resource('s3')

my_bucket = s3.Bucket('bucket_name')

for file in my_bucket.objects.all():
    print(file.key)
Tushar Niras
źródło
30

Jeśli chcesz przekazać klucze ACCESS i SECRET (czego nie powinieneś robić, ponieważ nie jest to bezpieczne):

from boto3.session import Session

ACCESS_KEY='your_access_key'
SECRET_KEY='your_secret_key'

session = Session(aws_access_key_id=ACCESS_KEY,
                  aws_secret_access_key=SECRET_KEY)
s3 = session.resource('s3')
your_bucket = s3.Bucket('your_bucket')

for s3_file in your_bucket.objects.all():
    print(s3_file.key)
Erwin Alberto
źródło
13
Jest to mniej bezpieczne niż posiadanie pliku poświadczeń na ~ / .aws / credentials. Chociaż jest to prawidłowe rozwiązanie.
nu everest
6
Wymagałoby to przekazania tajemnic kontroli źródła. Niedobrze.
Jan Groth,
2
Ta odpowiedź nic nie dodaje w odniesieniu do API / mechaniki wyświetlania obiektów przy jednoczesnym dodaniu nieistotnej metody uwierzytelniania, która jest wspólna dla wszystkich zasobów boto i stanowi złą praktykę pod względem bezpieczeństwa
Froyke
Dodano wyłączenie odpowiedzialności do odpowiedzi na temat bezpieczeństwa.
rjurney
Co by było, gdyby klucze były dostarczane przez system zarządzania kluczami / sekretami, taki jak Vault (Hashicorp) - czy nie byłoby to lepsze niż po prostu umieszczenie pliku poświadczeń na ~ / .aws / credentials?
SunnyAk
25

W celu obsługi dużych list kluczy (tj. Gdy lista katalogów jest większa niż 1000 pozycji), użyłem następującego kodu do kumulacji wartości kluczy (tj. Nazw plików) z wieloma listami (dzięki Amelio powyżej dla pierwszych wierszy). Kod dotyczy python3:

    from boto3  import client
    bucket_name = "my_bucket"
    prefix      = "my_key/sub_key/lots_o_files"

    s3_conn   = client('s3')  # type: BaseClient  ## again assumes boto.cfg setup, assume AWS S3
    s3_result =  s3_conn.list_objects_v2(Bucket=bucket_name, Prefix=prefix, Delimiter = "/")

    if 'Contents' not in s3_result:
        #print(s3_result)
        return []

    file_list = []
    for key in s3_result['Contents']:
        file_list.append(key['Key'])
    print(f"List count = {len(file_list)}")

    while s3_result['IsTruncated']:
        continuation_key = s3_result['NextContinuationToken']
        s3_result = s3_conn.list_objects_v2(Bucket=bucket_name, Prefix=prefix, Delimiter="/", ContinuationToken=continuation_key)
        for key in s3_result['Contents']:
            file_list.append(key['Key'])
        print(f"List count = {len(file_list)}")
    return file_list
Hefajstos
źródło
20

Moja funkcja narzędziowa s3keys jest zasadniczo zoptymalizowaną wersją odpowiedzi @ Hefajstosa:

import boto3


s3_paginator = boto3.client('s3').get_paginator('list_objects_v2')


def keys(bucket_name, prefix='/', delimiter='/', start_after=''):
    prefix = prefix[1:] if prefix.startswith(delimiter) else prefix
    start_after = (start_after or prefix) if prefix.endswith(delimiter) else start_after
    for page in s3_paginator.paginate(Bucket=bucket_name, Prefix=prefix, StartAfter=start_after):
        for content in page.get('Contents', ()):
            yield content['Key']

W moich testach (boto3 1.9.84) jest znacznie szybszy niż równoważny (ale prostszy) kod:

import boto3


def keys(bucket_name, prefix='/', delimiter='/'):
    prefix = prefix[1:] if prefix.startswith(delimiter) else prefix
    bucket = boto3.resource('s3').Bucket(bucket_name)
    return (_.key for _ in bucket.objects.filter(Prefix=prefix))

Ponieważ S3 gwarantuje binarne wyniki UTF-8 , start_afterdo pierwszej funkcji dodano optymalizację.

Sean Summers
źródło
To zdecydowanie najlepsza odpowiedź. Właśnie modyfikowałem odpowiedź @ Hefajstosa (ponieważ była najwyższa), kiedy przewijałem w dół. To powinna być zaakceptowana odpowiedź i powinna otrzymać dodatkowe punkty za zwięzłość. Dodałbym, że generator z drugiego kodu musi być zapakowany, list()aby zwrócić listę plików.
Richard D
@RichardD oba wyniki zwracają generatory. Wiele segmentów, na które celuję za pomocą tego kodu, ma więcej kluczy niż pamięć modułu wykonującego kod może obsłużyć jednocześnie (np. AWS Lambda); Wolę konsumować klucze podczas ich generowania.
Sean Summers
6

Bardziej oszczędny sposób, zamiast iteracji przez pętlę for, możesz po prostu wydrukować oryginalny obiekt zawierający wszystkie pliki w segmencie S3:

session = Session(aws_access_key_id=aws_access_key_id,aws_secret_access_key=aws_secret_access_key)
s3 = session.resource('s3')
bucket = s3.Bucket('bucket_name')

files_in_s3 = bucket.objects.all() 
#you can print this iterable with print(list(files_in_s3))
Daniel Vieira
źródło
3
@petezurich, czy mógłbyś wyjaśnić, dlaczego tak drobna edycja mojej odpowiedzi - zastąpienie „a” wielką literą „A” na początku mojej odpowiedzi obniżyło moją reputację o -2, jednak uważam, że zarówno ja, jak i ja zgadzam się że nie tylko wasza korekta wcale nie jest istotna, ale raczej raczej drobna, nie powiedziałbyś tak? Skoncentruj się na treściach, a nie na dziecięcych wersjach, najbardziej zobowiązany ol'boy
Daniel Vieira
Były to dwie różne interakcje. 1. Zredagowałem twoją odpowiedź, która jest zalecana nawet w przypadku drobnych błędów ortograficznych. Zgadzam się, że granice między drobnym a trywialnym są niejednoznaczne. Nie głosuję za żadnym postem, ponieważ widzę błędy i nie zrobiłem tego w tym przypadku. Po prostu naprawiam wszystkie błędy, które widzę.
petezurich
2. Głosowałem za odpowiedzią, ponieważ napisałeś, że files_in_s3jest to „obiekt listy”. W Pythonie nie ma czegoś takiego. Raczej jest iterowalny i nie mogłem sprawić, by Twój kod działał i dlatego został odrzucony. Potem znalazłem błąd i zrozumiałem twój punkt, ale nie mogłem cofnąć mojej oceny.
petezurich
5
@petezurich nie ma problemu, zrozumiałem, punkt, tylko jedna rzecz, w Pythonie lista JEST obiektem, ponieważ prawie wszystko w Pythonie jest obiektem, to wynika również, że lista jest również iterowalna, ale przede wszystkim jest to obiekt! dlatego nie zrozumiałem twojego zdania - głosowałeś coś, co było poprawne i działał kod. W każdym razie dzięki za przeprosiny i wszystkiego najlepszego
Daniel Vieira,
1
@petezurich Wszystko w Pythonie jest obiektem. „Obiekt listy” jest całkowicie akceptowalny.
Zach Garwood
4

ObjectSummary:

Istnieją dwa identyfikatory, które są dołączone do ObjectSummary:

  • nazwa_ wiadra
  • klucz

boto3 S3: ObjectSummary

Więcej na temat kluczy obiektów z dokumentacji AWS S3:

Klucze obiektów:

Tworząc obiekt, określasz nazwę klucza, która jednoznacznie identyfikuje obiekt w wiadrze. Na przykład w konsoli Amazon S3 (patrz Konsola zarządzania AWS) po podświetleniu segmentu pojawia się lista obiektów w tym segmencie. Te nazwy są kluczami obiektowymi. Nazwa klucza to ciąg znaków Unicode, których kodowanie UTF-8 ma długość maksymalnie 1024 bajtów.

Model danych Amazon S3 ma płaską strukturę: tworzysz segment, a segment ten przechowuje obiekty. Nie ma hierarchii podbucketów ani podfolderów; Można jednak wnioskować o hierarchii logicznej przy użyciu prefiksów i ograniczników nazw kluczy, tak jak robi to konsola Amazon S3. Konsola Amazon S3 obsługuje koncepcję folderów. Załóżmy, że twój segment (utworzony przez administratora) ma cztery obiekty z następującymi kluczami obiektów:

Rozwój / Projekty 1.xls

Finanse / oświadczenie1.pdf

Private / taxdocument.pdf

s3-dg.pdf

Odniesienie:

AWS S3: Klucze obiektów

Oto przykładowy kod, który pokazuje, jak uzyskać nazwę segmentu i klucz obiektu.

Przykład:

import boto3
from pprint import pprint

def main():

    def enumerate_s3():
        s3 = boto3.resource('s3')
        for bucket in s3.buckets.all():
             print("Name: {}".format(bucket.name))
             print("Creation Date: {}".format(bucket.creation_date))
             for object in bucket.objects.all():
                 print("Object: {}".format(object))
                 print("Object bucket_name: {}".format(object.bucket_name))
                 print("Object key: {}".format(object.key))

    enumerate_s3()


if __name__ == '__main__':
    main()
Gothburz
źródło
3

Właśnie tak to zrobiłem, w tym metodę uwierzytelniania:

s3_client = boto3.client(
                's3',
                aws_access_key_id='access_key',
                aws_secret_access_key='access_key_secret',
                config=boto3.session.Config(signature_version='s3v4'),
                region_name='region'
            )

response = s3_client.list_objects(Bucket='bucket_name', Prefix=key)
if ('Contents' in response):
    # Object / key exists!
    return True
else:
    # Object / key DOES NOT exist!
    return False
Milean
źródło
2
#To print all filenames in a bucket
import boto3

s3 = boto3.client('s3')

def get_s3_keys(bucket):

    """Get a list of keys in an S3 bucket."""
    resp = s3.list_objects_v2(Bucket=bucket)
    for obj in resp['Contents']:
      files = obj['Key']
    return files


filename = get_s3_keys('your_bucket_name')

print(filename)

#To print all filenames in a certain directory in a bucket
import boto3

s3 = boto3.client('s3')

def get_s3_keys(bucket, prefix):

    """Get a list of keys in an S3 bucket."""
    resp = s3.list_objects_v2(Bucket=bucket, Prefix=prefix)
    for obj in resp['Contents']:
      files = obj['Key']
      print(files)
    return files


filename = get_s3_keys('your_bucket_name', 'folder_name/sub_folder_name/')

print(filename)
Imran Selim
źródło
Oba „get_s3_keys” zwraca tylko ostatni klucz.
Aleksiej Waznowow
Zawiera jednak listę wszystkich plików w wiadrze; pytanie brzmiało, jak to zrobić ls. Jak byś to zrobił ... wydrukuj tylko pliki w katalogu głównym
Herman
1

Z niewielką modyfikacją kodu @Hephaeastus w jednym z powyższych komentarzy, napisałem poniższą metodę, aby wyświetlić listę folderów i obiektów (plików) w danej ścieżce. Działa podobnie do polecenia s3 ls.

from boto3 import session

def s3_ls(profile=None, bucket_name=None, folder_path=None):
    folders=[]
    files=[]
    result=dict()
    bucket_name = bucket_name
    prefix= folder_path
    session = boto3.Session(profile_name=profile)
    s3_conn   = session.client('s3')
    s3_result =  s3_conn.list_objects_v2(Bucket=bucket_name, Delimiter = "/", Prefix=prefix)
    if 'Contents' not in s3_result and 'CommonPrefixes' not in s3_result:
        return []

    if s3_result.get('CommonPrefixes'):
        for folder in s3_result['CommonPrefixes']:
            folders.append(folder.get('Prefix'))

    if s3_result.get('Contents'):
        for key in s3_result['Contents']:
            files.append(key['Key'])

    while s3_result['IsTruncated']:
        continuation_key = s3_result['NextContinuationToken']
        s3_result = s3_conn.list_objects_v2(Bucket=bucket_name, Delimiter="/", ContinuationToken=continuation_key, Prefix=prefix)
        if s3_result.get('CommonPrefixes'):
            for folder in s3_result['CommonPrefixes']:
                folders.append(folder.get('Prefix'))
        if s3_result.get('Contents'):
            for key in s3_result['Contents']:
                files.append(key['Key'])

    if folders:
        result['folders']=sorted(folders)
    if files:
        result['files']=sorted(files)
    return result

Spisuje wszystkie obiekty / foldery w danej ścieżce. Ścieżkę_folderu można domyślnie pozostawić jako Brak, a metoda wyświetli bezpośrednią zawartość katalogu głównego wiadra.

Baran
źródło
0

Oto rozwiązanie

importuj boto3

s3 = boto3.resource ('s3')

BUCKET_NAME = 'Twoja nazwa wiadra S3 np.

allFiles = s3.Bucket (BUCKET_NAME) .objects.all ()

dla pliku we wszystkich plikach: print (plik.key)

Shashi Kumar Singh
źródło
0

Można to również zrobić w następujący sposób:

csv_files = s3.list_objects_v2(s3_bucket_path)
    for obj in csv_files['Contents']:
        key = obj['Key']
KayV
źródło
0

Pytasz więc o odpowiednik aws s3 lsw boto3. Będzie to lista wszystkich folderów i plików najwyższego poziomu. To najbliższe, jakie mogłem dostać; wyświetla tylko wszystkie foldery najwyższego poziomu. Zaskakujące, jak trudna jest taka prosta operacja.

import boto3

def s3_ls():
  s3 = boto3.resource('s3')
  bucket = s3.Bucket('example-bucket')
  result = bucket.meta.client.list_objects(Bucket=bucket.name,
                                           Delimiter='/')
  for o in result.get('CommonPrefixes'):
    print(o.get('Prefix'))
Herman
źródło