Boto3를 사용하여 S3 버킷에서 모든 파일 다운로드
s3 버킷에서 파일을 가져 오기 위해 boto3를 사용하고 있습니다. 비슷한 기능이 필요합니다.aws s3 sync
내 현재 코드는
#!/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'])
버킷에 파일 만있는 한 제대로 작동합니다. 버킷 내부에 폴더가 있으면 오류가 발생합니다.
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'
boto3를 사용하여 완전한 s3 버킷을 다운로드하는 적절한 방법입니까? 폴더를 다운로드하는 방법.
1000 개 이상의 객체가있는 버킷으로 작업 할 때 NextContinuationToken
최대 1000 개의 키의 순차적 집합 을 사용하는 솔루션을 구현해야 합니다. 이 솔루션은 먼저 개체 목록을 컴파일 한 다음 지정된 디렉터리를 반복적으로 만들고 기존 개체를 다운로드합니다.
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)
나는 동일한 요구를 가지고 있으며 파일을 재귀 적으로 다운로드하는 다음 기능을 만들었습니다.
디렉토리는 파일이 포함 된 경우에만 로컬로 작성됩니다.
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)
함수는 다음과 같이 호출됩니다.
def _start():
client = boto3.client('s3')
resource = boto3.resource('s3')
download_dir(client, resource, 'clientconf/', '/tmp', bucket='my-bucket')
Amazon S3에는 폴더 / 디렉터리가 없습니다. 그것은이다 플랫 파일 구조 .
디렉토리의 모양을 유지하기 위해 경로 이름은 오브젝트 키 (파일 이름)의 일부로 저장됩니다 . 예를 들면 :
images/foo.jpg
이 경우, 전체 키는 images/foo.jpg
오히려 단지보다 foo.jpg
.
나는 당신의 문제 boto
가라는 파일을 반환하고 my_folder/.8Df54234
그것을 로컬 파일 시스템에 저장하려고 시도하고 있다고 생각합니다. 그러나 로컬 파일 시스템은 my_folder/
부분을 디렉토리 이름으로 해석 하고 해당 디렉토리는 로컬 파일 시스템에 존재하지 않습니다 .
당신도 할 수 절단 에만 저장에 파일 이름을 .8Df54234
부분, 또는 당신이해야 필요한 디렉토리를 작성 파일을 작성하기 전에. 다중 레벨 중첩 디렉토리 일 수 있습니다.
더 쉬운 방법은 다음과 같은 모든 작업을 수행 하는 AWS 명령 줄 인터페이스 (CLI) 를 사용하는 것입니다.
aws s3 cp --recursive s3://my_bucket_name local_folder
sync
새 파일과 수정 된 파일 만 복사 하는 옵션 도 있습니다.
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)
현재 다음을 사용하여 작업을 수행하고 있습니다.
#!/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)
비록 그것이 일을하지만, 나는 이런 식으로하는 것이 좋은지 잘 모르겠습니다. 나는 이것을 달성하는 더 나은 방법으로 다른 사용자와 추가 답변을 돕기 위해 여기에 남겨 둡니다.
결코 늦지 않는 것보다 낫습니다 :) 페이지 매김에 대한 이전 답변은 정말 좋습니다. 그러나 재귀 적이므로 Python의 재귀 제한에 도달 할 수 있습니다. 다음은 몇 가지 추가 검사가 포함 된 대체 방법입니다.
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')
동일한 프로세스에서 AWS CLI를 실행하는 해결 방법이 있습니다.
awscli
python lib로 설치합니다 .
pip install awscli
그런 다음이 함수를 정의하십시오.
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)
실행하다:
aws_cli('s3', 'sync', '/path/to/source', 's3://bucket/destination', '--delete')
모든 파일을 한 번에 가져 오는 것은 매우 나쁜 생각입니다. 오히려 일괄 적으로 가져와야합니다.
S3에서 특정 폴더 (디렉토리)를 가져 오는 데 사용하는 한 가지 구현은 다음과 같습니다.
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])
여전히 전체 버킷을 얻으려면 CIL을 통해 @John Rotenstein 이 아래와 같이 언급했듯이 사용하십시오 .
aws s3 cp --recursive s3://bucket_name download_path
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')
이 코드는 /tmp/
디렉토리 의 콘텐츠를 다운로드합니다 . 원하는 경우 디렉토리를 변경할 수 있습니다.
If you want to call a bash script using python, here is a simple method to load a file from a folder in S3 bucket to a local folder (in a Linux machine) :
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")
참고URL : https://stackoverflow.com/questions/31918960/boto3-to-download-all-files-from-a-s3-bucket
'development' 카테고리의 다른 글
Python, 문자열에서 알파벳이 아닌 모든 문자 제거 (0) | 2020.11.26 |
---|---|
Spring Boot 및 Spring Security 애플리케이션에서 정적 웹 리소스 제공 (0) | 2020.11.26 |
UML 클래스 다이어그램에서 '#'기호는 무엇을 의미합니까? (0) | 2020.11.26 |
파이썬에서 콘솔 창을 숨기는 방법? (0) | 2020.11.26 |
JavaScript / jQuery를 사용하여 양식의 동작 변경 (0) | 2020.11.26 |