You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中Azure存储账户完整结构复制报错及解决方案咨询

问题描述

场景需求:

  • 两个Azure存储账户(源/目标)
  • 源账户包含多个容器、虚拟文件夹、Blob等资源
  • 需要将源账户所有内容按原结构完整复制到目标账户
  • 若目标账户中已存在同名元素且版本比源账户旧,则覆盖该元素

编写的Python代码运行时抛出错误:AttributeError: 'BlobProperties' object has no attribute 'url'

错误原因

source_container_client.list_blobs()返回的是BlobProperties对象,该对象仅存储Blob的属性元数据(如名称、最后修改时间、大小等),并不包含url属性。原代码中直接访问source_blob.url,这是触发报错的核心原因。

解决方法

要获取源Blob的可访问URL,需通过源容器客户端构造对应的BlobClient实例,再从中提取URL。同时补充以下优化逻辑,让脚本更健壮:

  • 过滤虚拟文件夹(BlobPrefix对象):避免对非Blob资源执行复制操作
  • 等待异步复制完成:start_copy_from_url是异步操作,需等待复制状态完成再继续
  • 基础异常捕获:防止单个Blob复制失败导致整个脚本中断

修改后的完整代码:

from azure.storage.blob import BlobServiceClient, BlobPrefix
import time

# 配置存储账户连接字符串
SOURCE_CONNECTION_STRING = "你的源存储账户连接字符串"
DESTINATION_CONNECTION_STRING = "你的目标存储账户连接字符串"

# 初始化Blob服务客户端
source_blob_service_client = BlobServiceClient.from_connection_string(SOURCE_CONNECTION_STRING)
destination_blob_service_client = BlobServiceClient.from_connection_string(DESTINATION_CONNECTION_STRING)

# 遍历源账户所有容器
for source_container in source_blob_service_client.list_containers():
    container_name = source_container.name
    print(f"正在处理容器: '{container_name}'")

    # 创建目标容器(不存在则创建)
    dest_container_client = destination_blob_service_client.get_container_client(container_name)
    if not dest_container_client.exists():
        print(f"在目标账户创建容器: '{container_name}'")
        dest_container_client.create_container()

    # 获取源容器客户端
    source_container_client = source_blob_service_client.get_container_client(container_name)
    # 遍历容器内所有资源(包括虚拟文件夹)
    for item in source_container_client.list_blobs():
        # 跳过虚拟文件夹(BlobPrefix对象)
        if isinstance(item, BlobPrefix):
            continue
        
        blob_name = item.name
        dest_blob_client = dest_container_client.get_blob_client(blob_name)
        
        # 判断是否需要复制:目标不存在 或 源Blob更新
        need_copy = False
        if not dest_blob_client.exists():
            need_copy = True
        else:
            dest_props = dest_blob_client.get_blob_properties()
            if item.last_modified > dest_props.last_modified:
                need_copy = True
        
        if need_copy:
            # 构造源Blob客户端并获取URL
            source_blob_client = source_container_client.get_blob_client(blob_name)
            source_blob_url = source_blob_client.url
            
            # 启动复制操作
            copy_result = dest_blob_client.start_copy_from_url(source_blob_url)
            copy_id = copy_result['copy_id']
            
            # 等待复制完成,轮询状态
            while True:
                dest_props = dest_blob_client.get_blob_properties()
                copy_status = dest_props.copy.status
                if copy_status == 'success':
                    print(f"已复制Blob: '{blob_name}' 到容器 '{container_name}'")
                    break
                elif copy_status == 'failed':
                    print(f"复制Blob '{blob_name}' 失败: {dest_props.copy.status_description}")
                    break
                time.sleep(1)
关键修改说明
  1. 获取源Blob URL:通过source_container_client.get_blob_client(blob_name).url生成正确的Blob访问URL,替代原代码中错误的source_blob.url调用
  2. 过滤虚拟文件夹:通过isinstance(item, BlobPrefix)判断并跳过虚拟文件夹,避免无效操作
  3. 等待复制完成:添加循环轮询复制状态,确保异步复制操作完成后再处理下一个Blob
  4. 逻辑优化:整理客户端实例的获取逻辑,提升代码可读性和维护性

内容的提问来源于stack exchange,提问作者Thanatos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 22:55:18