S3 बाल्टी से सभी फ़ाइलों को डाउनलोड करने के लिए Boto3


84

मैं 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 बाल्टी डाउनलोड करने का एक उचित तरीका है। फोल्डर कैसे डाउनलोड करें।


जवाबों:


40

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

व्यापक उपयोग के मामले को संभालने के लिए इसे स्वीकार किए गए उत्तर में बदल रहा है।
शान

मेरा कोड एक अनंत लूप में जाता हैwhile next_token is not None:
gpd

@gpd ऐसा नहीं होना चाहिए क्योंकि boto3 क्लाइंट नेक्स्टकॉर्पोरेशनटूकन के बिना एक पेज लौटाएगा जब वह अंतिम पेज पर पहुंच गया होगा, जबकि स्टेटमेंट से बाहर निकल जाएगा। यदि आप boto3 API (जो कुछ भी प्रतिक्रिया चर में संग्रहीत है) का उपयोग करने से प्राप्त अंतिम प्रतिक्रिया को चिपकाते हैं तो मुझे लगता है कि यह अधिक स्पष्ट होगा कि आपके विशिष्ट मामले में क्या हो रहा है। केवल परीक्षण करने के लिए 'परिणाम' चर को प्रिंट करने का प्रयास करें। मेरा अनुमान है कि आपने एक उपसर्ग वस्तु दी है जो आपकी बाल्टी की किसी भी सामग्री से मेल नहीं खाती है। क्या आपने इसकी जाँच की?
लांघेस

1
ध्यान दें कि डिजिटल महासागर के साथ काम करने के लिए आपको छोटे बदलावों की आवश्यकता होगी। जैसा कि यहाँ
डेविड डी।

2
इस कोड का उपयोग करके मुझे यह त्रुटि मिल रही है: 'noneType' ऑब्जेक्ट चलने योग्य नहीं है: TypeError
NJones

76

मेरे पास समान आवश्यकताएं हैं और निम्न फ़ंक्शन बनाया है जो फ़ाइलों को पुन: डाउनलोड करता है।

निर्देशिकाएं केवल स्थानीय रूप से बनाई जाती हैं, यदि उनमें फ़ाइलें हों।

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

6
मुझे नहीं लगता कि आपको एक संसाधन और ग्राहक बनाने की आवश्यकता है। मेरा मानना ​​है कि एक ग्राहक हमेशा संसाधन पर उपलब्ध होता है। आप बस उपयोग कर सकते हैं resource.meta.client
TheHerk

2
मुझे लगता है कि "download_dir (क्लाइंट, रिसोर्स, सबडेयर.गेट ('उपसर्ग'), लोकल, बकेट ) होना चाहिए"
rm999

6
मैं एक OSError: [Errno 21] Is a directoryतो हो रहा था मैं if not file.get('Key').endswith('/')हल करने के लिए डाउनलोड_फाइल को कॉल लपेट दिया । साभार @glefait और @Shan
user336828

5
वहाँ aws s3 syncboto3 पुस्तकालय में उपलब्ध aws-cli कमांड के बराबर नहीं है ?
greperror

8
distयहाँ क्या है ?
रोब रोज

49

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विकल्प भी है जो केवल नई और संशोधित फ़ाइलों की नकल करेगा।


1
@ मैं समझता हूं कि लेकिन मुझे फ़ोल्डर बनाने की ज़रूरत थी, स्वचालित रूप से पसंद है aws s3 sync। क्या यह बोटो 3 में संभव है।
शान

4
आपको अपने पायथन कोड के हिस्से के रूप में एक निर्देशिका के निर्माण को शामिल करना होगा। यदि कुंजी में निर्देशिका है (उदाहरण के लिए foo/bar.txt), तो आप fooकॉल करने से पहले निर्देशिका ( ) बनाने के लिए जिम्मेदार होंगे s3.download_file। यह एक स्वचालित क्षमता नहीं है boto
जॉन रोटेनस्टीन

यहां, S3 बाल्टी की सामग्री गतिशील है, इसलिए मुझे s3.list_objects(Bucket='my_bucket_name')['Contents']फ़ोल्डर कुंजियों की जांच और फ़िल्टर करना होगा और उन्हें बनाना होगा।
शान

2
कुछ समय के लिए Boto3 के साथ खेलने के बाद, यहां सूचीबद्ध AWS CLI कमांड निश्चित रूप से ऐसा करने का सबसे आसान तरीका है।
एडजक्टप्रोफेसर फाल्कन

1
@ किसी पुराने (2015) प्रश्न पर टिप्पणी के रूप में प्रश्न पूछने के बजाय कृपया एक नया प्रश्न शुरू करें।
जॉन रोटेनस्टीन

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)

3
स्वच्छ और सरल, किसी भी कारण से इसका उपयोग क्यों नहीं करना चाहिए? यह अन्य सभी समाधानों की तुलना में बहुत अधिक समझने योग्य है। कलेक्शन आपके लिए बैकग्राउंड में बहुत सारी चीजें करने लगता है।
जोस्ट

3
मुझे लगता है कि आपको ठीक से काम करने के लिए पहले सभी सबफ़ोल्डर बनाने चाहिए।
रपनई

2
यह कोड S3 में कितना गहरा नेस्टेड है इसकी परवाह किए बिना सब कुछ शीर्ष-स्तरीय आउटपुट निर्देशिका में डाल देगा। और अगर कई फाइलों का अलग-अलग निर्देशिकाओं में एक ही नाम है, तो यह एक दूसरे के साथ स्टॉम्प करेगा। मुझे लगता है कि आपको एक और पंक्ति की आवश्यकता है: os.makedirs(path)और फिर डाउनलोड गंतव्य होना चाहिए object.key
स्कॉट स्मिथ

13

मैं वर्तमान में निम्न का उपयोग करके कार्य को प्राप्त कर रहा हूं

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

हालांकि, यह काम करता है, मुझे यकीन नहीं है कि इस तरह से अच्छा होगा। मैं इसे प्राप्त करने के बेहतर तरीके के साथ अन्य उपयोगकर्ताओं और आगे के जवाबों की मदद करने के लिए यहां छोड़ रहा हूं


9

देर से कभी भी बेहतर नहीं है :) पेजिनेटर के साथ पिछला उत्तर वास्तव में अच्छा है। हालांकि यह पुनरावर्ती है, और आप पायथन की पुनरावृत्ति सीमा को समाप्त कर सकते हैं। यहाँ कुछ अतिरिक्त जाँच के साथ एक वैकल्पिक तरीका है।

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

1
मिल गया KeyError: 'Contents'। इनपुट पथ '/arch/R/storeincomelogs/, पूर्ण पथ /arch/R/storeincomelogs/201901/01/xxx.parquet
मिथिला २

3

मेरे पास इसके लिए एक वर्कअराउंड है जो उसी प्रक्रिया में AWS CLI चलाता है।

awscliअजगर लिब के रूप में स्थापित करें :

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

मैंने एक ही विचार का उपयोग किया sync, लेकिन कमांड का उपयोग किए बिना , और केवल कमांड को निष्पादित करने के बिना aws s3 cp s3://{bucket}/{folder} {local_folder} --recursive। टाइम्स मिनट (लगभग 1h) से सचमुच सेकंड तक कम हो गया
acruci

मैं इस कोड का उपयोग कर रहा हूं, लेकिन एक मुद्दा है जहां सभी डिबग लॉग दिखा रहे हैं। मैंने इसे विश्व स्तर पर घोषित किया है: logging.basicConfig(format='%(levelname)s: %(message)s', level=logging.WARNING) logger = logging.getLogger()और केवल लॉग को रूट से आउटपुट किया जाना चाहते हैं। कोई विचार?
अप्रैल पोलुबेक

1

सभी फ़ाइलों को एक बार में प्राप्त करना बहुत बुरा विचार है, आपको इसे बैचों में लाना चाहिए।

एक कार्यान्वयन जिसे मैं 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 के माध्यम से पूरी बाल्टी का उपयोग करना चाहते हैं तो नीचे दिए गए @Jon Rotenstein के रूप में उल्लेख किया गया है,

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

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

यह कोड /tmp/निर्देशिका में सामग्री डाउनलोड करेगा । आप चाहें तो डायरेक्टरी बदल सकते हैं।


0

यदि आप अजगर का उपयोग करके एक बैश स्क्रिप्ट को कॉल करना चाहते हैं, तो यहां S3 बाल्टी में एक फ़ोल्डर से एक स्थानीय फ़ोल्डर (एक लिनक्स मशीन में) में एक फ़ाइल लोड करने की एक सरल विधि है:

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

0

मुझे इसी तरह की आवश्यकता मिली और उपरोक्त कुछ समाधानों और अन्य वेबसाइटों को पढ़ने से मुझे मदद मिली, मैं नीचे स्क्रिप्ट के साथ आया हूं, अगर यह किसी की मदद कर सकता है तो साझा करना चाहता था।

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)

0

ओएस त्रुटि 20 से बचने के लिए अंत में एक शर्त के साथ @glefait का उत्तर देना। इसे प्राप्त करने वाली पहली कुंजी फ़ोल्डर नाम ही है जिसे गंतव्य पथ में नहीं लिखा जा सकता है।

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

0

मैं थोड़ी देर के लिए इस समस्या में चला गया और सभी विभिन्न मंचों के माध्यम से मैं के माध्यम से किया गया है मैं क्या काम करता है की एक पूर्ण अंत करने के लिए अंत नहीं देखा है। तो, मैंने आगे बढ़कर सभी टुकड़ों को ले लिया (अपने दम पर कुछ सामान जोड़ें) और एक पूर्ण एंड-टू-एंड S3 डाउनलोडर बनाया है!

यह न केवल फ़ाइलों को स्वचालित रूप से डाउनलोड करेगा बल्कि यदि S3 फाइलें उपनिर्देशिकाओं में हैं, तो यह उन्हें स्थानीय संग्रहण पर बनाएगी। मेरे आवेदन के उदाहरण में, मुझे अनुमतियाँ और स्वामी सेट करने की आवश्यकता है इसलिए मैंने इसे भी जोड़ा है (यदि आवश्यक नहीं है तो टिप्पणी की जा सकती है)।

इसका परीक्षण किया गया है और एक डॉक पर्यावरण (K8) में काम करता है, लेकिन मैंने स्क्रिप्ट में पर्यावरण चर को केवल उसी स्थिति में जोड़ा है जब आप इसे स्थानीय रूप से परीक्षण / चलाना चाहते हैं।

मुझे आशा है कि यह S3 डाउनलोड स्वचालन खोजने की उनकी खोज में किसी को मदद करता है। मैं किसी भी सलाह, सूचना आदि का स्वागत करता हूं कि जरूरत पड़ने पर इसे बेहतर तरीके से कैसे अनुकूलित किया जा सकता है।

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

0

AWS S3 डॉक्स से (मैं S3 बाल्टी में फ़ोल्डर का उपयोग कैसे करूँ?):

अमेज़ॅन एस 3 में, बाल्टी और ऑब्जेक्ट प्राथमिक संसाधन हैं, और ऑब्जेक्ट को बाल्टी में संग्रहीत किया जाता है। अमेज़ॅन S3 में एक पदानुक्रम के बजाय एक सपाट संरचना है जैसे आप एक फ़ाइल सिस्टम में देखेंगे। हालांकि, संगठनात्मक सादगी के लिए, अमेज़ॅन एस 3 कंसोल ऑब्जेक्ट्स को समूहीकृत करने के साधन के रूप में फ़ोल्डर अवधारणा का समर्थन करता है। अमेज़ॅन S3 वस्तुओं के लिए एक साझा नाम उपसर्ग का उपयोग करके ऐसा करता है (अर्थात, वस्तुओं में ऐसे नाम हैं जो एक सामान्य स्ट्रिंग से शुरू होते हैं)। ऑब्जेक्ट नामों को मुख्य नामों के रूप में भी जाना जाता है।

उदाहरण के लिए, आप फ़ोटो नाम के कंसोल पर एक फ़ोल्डर बना सकते हैं और उसमें myphoto.jpg नाम की एक वस्तु संग्रहीत कर सकते हैं। ऑब्जेक्ट को तब कुंजी नाम के फोटो / myphoto.jpg के साथ संग्रहीत किया जाता है, जहां फोटो / उपसर्ग होता है।

"Mybucket" से सभी फ़ाइलों को वर्तमान निर्देशिका में बाल्टी के उत्सर्जित निर्देशिका संरचना का सम्मान करते हुए डाउनलोड करने के लिए (यदि वे पहले से ही स्थानीय रूप से मौजूद नहीं हैं तो बाल्टी से फ़ोल्डर बनाना):

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)

यदि आप अपने कोड का कुछ स्पष्टीकरण शामिल कर सकते हैं तो बेहतर होगा।
जोहान

1
@johan, प्रतिक्रिया के लिए धन्यवाद! मैंने प्रासंगिक स्पष्टीकरण जोड़ा
डारिया
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.