S3 urls - получить имя и путь в bucket

У меня есть переменная, которая имеет aws s3 url

s3://bucket_name/folder1/folder2/file1.json

Я хочу получить bucket_name в переменных и оставить i.e/folder1/folder2/file1.json в другой переменной. Я попробовал регулярные выражения и мог получить bucket_name, как показано ниже, но не уверен, есть ли лучший способ.

m = re.search('(?<=s3:\/\/)[^\/]+', 's3://bucket_name/folder1/folder2/file1.json')
print(m.group(0))

Как я могу получить остальные i.e - folder1/folder2/file1.json?

Я проверил, есть ли функция boto3 для извлечения bucket_name и ключа из URL-адреса, но не смог найти его.

Ответ 1

Так как это обычный URL, вы можете использовать urlparse для получения всех частей URL.

>>> from urlparse import urlparse
>>> o = urlparse('s3://bucket_name/folder1/folder2/file1.json', allow_fragments=False)
>>> o
ParseResult(scheme='s3', netloc='bucket_name', path='/folder1/folder2/file1.json', params='', query='', fragment='')
>>> o.netloc
'bucket_name'
>>> o.path
'/folder1/folder2/file1.json'

Возможно, вам придется удалить начальную косую черту с ключа, как предполагает следующий ответ.

o.path.lstrip('/')

В Python 3 urlparse перемещен в urllib.parse поэтому используйте:

from urllib.parse import urlparse

Здесь класс, который заботится обо всех деталях.

try:
    from urlparse import urlparse
except ImportError:
    from urllib.parse import urlparse


class S3Url(object):
    """
    >>> s = S3Url("s3://bucket/hello/world")
    >>> s.bucket
    'bucket'
    >>> s.key
    'hello/world'
    >>> s.url
    's3://bucket/hello/world'

    >>> s = S3Url("s3://bucket/hello/world?qwe1=3#ddd")
    >>> s.bucket
    'bucket'
    >>> s.key
    'hello/world?qwe1=3#ddd'
    >>> s.url
    's3://bucket/hello/world?qwe1=3#ddd'

    >>> s = S3Url("s3://bucket/hello/world#foo?bar=2")
    >>> s.key
    'hello/world#foo?bar=2'
    >>> s.url
    's3://bucket/hello/world#foo?bar=2'
    """

    def __init__(self, url):
        self._parsed = urlparse(url, allow_fragments=False)

    @property
    def bucket(self):
        return self._parsed.netloc

    @property
    def key(self):
        if self._parsed.query:
            return self._parsed.path.lstrip('/') + '?' + self._parsed.query
        else:
            return self._parsed.path.lstrip('/')

    @property
    def url(self):
        return self._parsed.geturl()

Ответ 2

Для тех, кто, как я, пытался использовать urlparse для извлечения ключа и корзины, чтобы создать объект с помощью boto3. Там одна важная деталь: убрать косую черту с начала ключа

from urlparse import urlparse
o = urlparse('s3://bucket_name/folder1/folder2/file1.json')
bucket = o.netloc
key = o.path
boto3.client('s3')
client.put_object(Body='test', Bucket=bucket, Key=key.lstrip('/'))

Потребовалось время, чтобы понять это, потому что boto3 не выдает никаких исключений.

Ответ 3

Решение, которое работает без urllib или re (также обрабатывает предшествующий слеш):

def split_s3_path(s3_path):
    path_parts=s3_path.replace("s3://","").split("/")
    bucket=path_parts.pop(0)
    key="/".join(path_parts)
    return bucket, key

Бежать:

bucket, key = split_s3_path("s3://my-bucket/some_folder/another_folder/my_file.txt")

Возвращает:

bucket: my-bucket
key: some_folder/another_folder/my_file.txt

Ответ 4

Если вы хотите сделать это с помощью регулярных выражений, вы можете сделать следующее:

>>> import re
>>> uri = 's3://my-bucket/my-folder/my-object.png'
>>> match = re.match(r's3:\/\/(.+?)\/(.+)', uri)
>>> match.group(1)
'my-bucket'
>>> match.group(2)
'my-folder/my-object.png'

Это имеет то преимущество, что вы можете проверить схему s3, а не разрешать что-либо там.