【问题标题】:Python requests.get() for Azure blobAzure blob 的 Python requests.get()
【发布时间】:2019-07-14 20:51:01
【问题描述】:

我正在尝试从 Azure 存储下载 blob,我更喜欢使用 Python 的 requests.get()。如果我用azure 中的get_blob_to_path() 尝试它,它可以工作,但不能用requests.get()

我是这样使用的:

requests.get('https://<account_name>.blob.core.windows.net/<container_name>/<blob_name>')

我也尝试从 Azure 存储资源管理器复制整个 URL。

我从一个帐户收到以下错误:

gaierror: [Errno -2] Name or service not known

以及来自另一个帐户的以下结果(未显示为错误):

<Response [404]>

什么可能导致此错误/&lt;Response [404]&gt; 以及如何解决?通过requests.get() 连接的权限是否存在问题?

【问题讨论】:

    标签: python azure python-requests azure-blob-storage


    【解决方案1】:

    错误是由于您没有指定访问 blob 存储的权限。

    除了@Martin 在他的帖子中提到的将公共访问级别更改为容器或 blob(截图如下)之外,您还有其他两种方式来解决权限问题。

    方法一:您可以为 blob 生成一个 SAS URL。导航到 azure 门户 -> 单击要下载的 blob 的“...”符号 -> 选择生成 SAS。生成 SAS URL 后,您可以使用 SAS URL 进行 Blob 下载。下面的截图展示了如何生成 SAS URL:

    然后你可以编写如下代码:

    #use the SAS URL
    r = requests.get('https://yy3.blob.core.windows.net/aa1/w2.JPG?xxxx')
    open("d:\\temp\\mytest222.jpg","wb").write(r.content)
    

    方法2:请使用Get Blob rest api,下面的示例代码对我有用。

    import requests
    import datetime
    import hmac
    import hashlib
    import base64
    
    storage_account_name = 'xxxx'
    storage_account_key = 'xxxxx'
    blob_name = 'your_blob_name,like w2.jpg, note it is case sensitive'
    container_name='the container name'
    api_version = '2018-03-28'
    request_time = datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    
    string_params = {
        'verb': 'GET',
        'Content-Encoding': '',
        'Content-Language': '',
        'Content-Length': '',
        'Content-MD5': '',
        'Content-Type': '',
        'Date': '',
        'If-Modified-Since': '',
        'If-Match': '',
        'If-None-Match': '',
        'If-Unmodified-Since': '',
        'Range': '',
        'CanonicalizedHeaders': 'x-ms-date:' + request_time + '\nx-ms-version:' + api_version + '\n',
        'CanonicalizedResource': '/' + storage_account_name + '/'+container_name + '/' + blob_name
    }
    
    string_to_sign = (string_params['verb'] + '\n' 
                      + string_params['Content-Encoding'] + '\n'
                      + string_params['Content-Language'] + '\n'
                      + string_params['Content-Length'] + '\n'
                      + string_params['Content-MD5'] + '\n' 
                      + string_params['Content-Type'] + '\n' 
                      + string_params['Date'] + '\n' 
                      + string_params['If-Modified-Since'] + '\n'
                      + string_params['If-Match'] + '\n'
                      + string_params['If-None-Match'] + '\n'
                      + string_params['If-Unmodified-Since'] + '\n'
                      + string_params['Range'] + '\n'
                      + string_params['CanonicalizedHeaders']
                      + string_params['CanonicalizedResource'])
    
    signed_string = base64.b64encode(hmac.new(base64.b64decode(storage_account_key), msg=string_to_sign.encode('utf-8'), digestmod=hashlib.sha256).digest()).decode()
    
    headers = {
        'x-ms-date' : request_time,
        'x-ms-version' : api_version,
        'Authorization' : ('SharedKey ' + storage_account_name + ':' + signed_string)
    }
    
    url = ('https://' + storage_account_name + '.blob.core.windows.net/'+container_name+'/'+blob_name)
    
    r = requests.get(url, headers = headers)
    
    #specify where to download and the new file name
    open("d:\\temp\\mytest111.jpg","wb").write(r.content)
    
    print("ok")
    

    【讨论】:

    • 对于第一种方法,是否会自动生成 SAS URL?我将不得不下载数百个 blob,手动按下按钮对我来说绝对不是一个好主意。或者对于第二种方法,是否可以在没有帐户密钥的情况下构造 Authorization 标头(而不是使用连接字符串)?我没有公开存储所需的权限/查看主/辅助键。
    • @Valeria,对于方法 1,您是否有权通过 ui(通过导航到 azure 门户->您的存储帐户->左窗格->共享访问签名)创建帐户级 SAS?如果是,那么您可以将此帐户级别的 SAS 用于所有 blob 下载。对于方法2,如果您有连接字符串(如果我理解正确的话),帐户密钥当然包含在连接字符串中(连接字符串应该是 DefaultEndpointsProtocol=https;AccountName=xx;AccountKey=xxx;EndpointSuffix=core.windows .net)。
    • 对于方法 2:我不确定详细信息,因为我是 Azure 新手,但有人告诉我这是“与 SAS 的连接字符串”。基本上,它是这种格式:docs.microsoft.com/en-us/azure/storage/common/…。它有SharedAccessSignaturesvsssig 等)和BlobEndpoint。我尝试将sig 用作代码中的signed_string,但我得到了与开头相同的错误([Errno -2] Name or service not known)。
    • 你能试试把这个 url("your_storage_account.blob.core.windows.net/your_container/…? + your_connection_string") 放在 requests.get(url) 中吗?看看是否有任何错误发生?或者如果发生错误,您介意将此连接字符串通过电子邮件发送给我吗?
    • @Valeria,你还有什么问题吗?
    【解决方案2】:

    您没有对此请求进行身份验证,因此我制作了一个公共 blob 存储容器来测试它,它可以正常工作,因此我认为这是权限问题。 blob 存储是否公开,如此处所示? https://docs.microsoft.com/en-us/azure/storage/blobs/storage-manage-access-to-resources

    这是我的代码,测试一下是否有效:

    import requests
    req = requests.get('https://publicstoragefallout.blob.core.windows.net/publiccont/icon.png')
    open('icon.png', 'wb').write(req.content)
    

    请注意,如果您使用 http 而不是 https,它也可以工作。

    希望这有帮助!

    【讨论】:

      猜你喜欢
      • 2021-04-27
      • 1970-01-01
      • 1970-01-01
      • 2017-02-08
      • 2018-07-30
      • 1970-01-01
      • 2018-10-04
      • 2015-03-24
      • 1970-01-01
      相关资源
      最近更新 更多