Listando o conteúdo de um bucket com boto3

198

Como posso ver o que há dentro de um balde no S3 boto3? (ou seja, faça um"ls" )?

Fazendo o seguinte:

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

retorna:

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

Como vejo o seu conteúdo?

Amelio Vazquez-Reina
fonte

Respostas:

241

Uma maneira de ver o conteúdo seria:

for my_bucket_object in my_bucket.objects.all():
    print(my_bucket_object)
garnaat
fonte
1
posso buscar as chaves no caminho particular no bucket ou com delimitador específico usando boto3 ??
Rahul KP
109
Você deve poder dizer mybucket.objects.filter(Prefix='foo/bar')e ele listará apenas objetos com esse prefixo. Você também pode passar um Delimiterparâmetro.
garnaat
3
não trabalhando com boto3 AttributeError: objeto 'S3' tem nenhum atributo 'objetos'
Shek
2
@garnaat Seu comentário mencionando que o método de filtro realmente me ajudou (meu código acabou muito mais simples e rápido) - obrigado!
Edward Dixon
24
Eu desaconselho o uso objectcomo um nome de variável, pois isso sombreará o tipo global object.
Oliland
100

É semelhante a um 'ls', mas não leva em consideração a convenção da pasta de prefixos e listará os objetos no bucket. Cabe ao leitor filtrar os prefixos que fazem parte do nome da chave.

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

No Python 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
fonte
39
Se você quiser usar o prefixo, bem, você pode fazê-lo como este:conn.list_objects(Bucket='bucket_name', Prefix='prefix_string')['Contents']
markonovak
13
Isso lista apenas as primeiras 1000 teclas. Na documentação: "Retorna alguns ou todos (até 1000) dos objetos em um balde". Além disso, é recomendável usar list_objects_v2 em vez de list_objects (embora, isso também retorne apenas as primeiras 1000 chaves).
Brett Widmeier 21/03/19
3
Essa limitação deve ser tratada com o uso de Paginators
v25
44

Suponho que você configurou a autenticação separadamente.

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

my_bucket = s3.Bucket('bucket_name')

for file in my_bucket.objects.all():
    print(file.key)
Tushar Niras
fonte
30

Se você deseja passar as chaves ACCESS e SECRET (o que você não deve fazer, porque não é seguro):

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
fonte
13
Isso é menos seguro do que ter um arquivo de credenciais em ~ / .aws / credentials. Embora seja uma solução válida.
nu everest
6
Isso exigiria o comprometimento de segredos no controle de origem. Não é bom.
Jan Groth
2
Essa resposta não acrescenta nada a respeito da API / mecânica da lista objetos ao adicionar um método de autenticação não relevante que é comum para todos os recursos boto e é uma segurança má prática sábio
Froyke
Foi adicionado um aviso de isenção à resposta sobre segurança.
Rjurney
E se as chaves fossem fornecidas por um sistema de gerenciamento de chaves / segredo como o Vault (Hashicorp) - isso não seria melhor do que apenas colocar o arquivo de credenciais em ~ / .aws / credentials?
SunnyAk 20/09/19
25

Para lidar com listagens de chaves grandes (por exemplo, quando a lista de diretórios é maior que 1000 itens), usei o código a seguir para acumular valores de chave (por exemplo, nomes de arquivos) com várias listagens (graças a Amelio acima para as primeiras linhas). O código é para 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
Hefesto
fonte
20

Minha função de utilitário s3keys é essencialmente uma versão otimizada da resposta de @ Hephaestus:

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

Nos meus testes (boto3 1.9.84), é significativamente mais rápido que o código equivalente (mas mais simples):

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

Como o S3 garante resultados classificados binários UTF-8 , uma start_afterotimização foi adicionada à primeira função.

Sean Summers
fonte
Esta é de longe a melhor resposta. Eu estava apenas modificando a resposta de @ Hefesto (porque era a mais alta) quando rolei para baixo. Essa deve ser a resposta aceita e deve obter pontos extras por ser concisa. Eu acrescentaria que o gerador do segundo código precisa ser empacotado list()para retornar uma lista de arquivos.
Richard D
@RichardD ambos os resultados retornam geradores. Muitos buckets que eu alvo com esse código têm mais chaves do que a memória do executor de código pode manipular de uma só vez (por exemplo, AWS Lambda); Eu prefiro consumir as chaves conforme elas são geradas.
Sean Summers
6

De uma maneira mais parcimoniosa, em vez de percorrer um loop for, você também pode imprimir o objeto original que contém todos os arquivos dentro do seu bucket do 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
fonte
3
@petezurich, você pode explicar por que uma edição tão mesquinha da minha resposta - substituir um "a" por um "A" maiúsculo no início da minha resposta diminuiu minha reputação por -2, no entanto, eu acho que você e eu podemos concordar não apenas sua correção NÃO é relevante, mas na verdade é mesquinha, você não diria isso? Por favor, se concentrar no conteúdo ao invés de revisão infantis, a maioria obrigados ol'boy
Daniel Vieira
Essas foram duas interações diferentes. 1. Editei sua resposta, que é recomendada mesmo para erros de ortografia menores. Concordo que as fronteiras entre menor e trivial são ambíguas. Não diminuo o voto de nenhuma postagem porque vejo erros e não vi neste caso. Eu simplesmente corrijo todos os erros que vejo.
petezurich
2. Eu diminuí a votação da sua resposta porque você escreveu que files_in_s3é um "objeto de lista". Não existe tal coisa no Python. É bastante iterável e não pude fazer seu código funcionar e, portanto, com voto negativo. Então eu encontrei o erro e vi o seu ponto, mas não consegui desfazer o meu voto negativo.
petezurich
5
@petezurich não tem problema, entendi o seu, aponte, apenas uma coisa, em Python uma lista é um objeto porque praticamente tudo em python é um objeto, então também se segue que uma lista também é iterável, mas antes de tudo, é uma objeto! é por isso que eu não entendi seu voto negativo - você estava votando em algo que estava correto e no código que funciona. Enfim, obrigado por seu pedido de desculpas e tudo de melhor #
Daniel Vieira
1
@petezurich Tudo em Python é um objeto. "Listar objeto" é completamente aceitável.
Zach Garwood
4

ObjectSummary:

Existem dois identificadores anexados ao ObjectSummary:

  • bucket_name
  • chave

boto3 S3: ObjectSummary

Mais sobre chaves de objeto da documentação do AWS S3:

Chaves de objeto:

Ao criar um objeto, você especifica o nome da chave, que identifica exclusivamente o objeto no bucket. Por exemplo, no console do Amazon S3 (consulte Console de gerenciamento da AWS), quando você realça um depósito, uma lista de objetos é exibida. Esses nomes são as chaves do objeto. O nome de uma chave é uma sequência de caracteres Unicode cuja codificação UTF-8 tem no máximo 1024 bytes.

O modelo de dados do Amazon S3 é uma estrutura plana: você cria um depósito e o depósito armazena objetos. Não há hierarquia de sub-baldes ou subpastas; no entanto, você pode inferir a hierarquia lógica usando prefixos e delimitadores de nomes de chave, como o console do Amazon S3. O console do Amazon S3 suporta um conceito de pastas. Suponha que seu bucket (criado pelo administrador) tenha quatro objetos com as seguintes chaves de objeto:

Desenvolvimento / Projects1.xls

Finanças / statement1.pdf

Private / taxdocument.pdf

s3-dg.pdf

Referência:

AWS S3: chaves de objeto

Aqui está um código de exemplo que demonstra como obter o nome do bloco e a chave do objeto.

Exemplo:

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
fonte
3

Eu fiz assim, incluindo o método de autenticação:

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
fonte
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
fonte
Ambos "get_s3_keys" retornam apenas a última chave.
Alexey Vazhnov
1

Com poucas modificações no código de @Hephaeastus em um dos comentários acima, escrevi o método abaixo para listar pastas e objetos (arquivos) em um determinado caminho. Funciona de maneira semelhante ao comando 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

Isso lista todos os objetos / pastas em um determinado caminho. O caminho_da_pasta pode ser deixado como Nenhum por padrão e o método listará o conteúdo imediato da raiz do bucket.

RAM
fonte
0

Aqui está a solução

import boto3

s3 = boto3.resource ('s3')

BUCKET_NAME = 'O nome do seu balde S3, por exemplo, deletemetesting11' '

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

para arquivo em allFiles: print (file.key)

Shashi Kumar Singh
fonte
0

Também pode ser feito da seguinte maneira:

csv_files = s3.list_objects_v2(s3_bucket_path)
    for obj in csv_files['Contents']:
        key = obj['Key']
KayV
fonte