Python调用Azure Graph API获取资源组标签的分页处理求助
解决Azure Resource Graph API分页获取全量资源组标签的问题
问题场景
在Azure门户Graph Explorer中执行以下Kusto查询可返回租户内2000+条资源组标签数据:
resourcecontainers | where type == 'microsoft.resources/subscriptions/resourcegroups' | extend dates=format_datetime(now(), "yyyy-MM-dd") | join kind=leftouter ( resourcecontainers | where type == 'microsoft.resources/subscriptions' | project SubscriptionName=name, subscriptionId) on subscriptionId | project SubscriptionName, subscriptionId, resourceGroup, financial_contact=tags.financial_contact, security_contact=tags.security_contact
但使用下方Python脚本调用时,仅返回530条结果,响应中skip_token为None,尝试skip/limit参数未解决分页问题,无法获取全量数据:
from azure.identity import DefaultAzureCredential from azure.mgmt.resourcegraph import ResourceGraphClient from azure.mgmt.resource import ResourceManagementClient from azure.mgmt.resourcegraph.models import * import json # Initialize Azure credentials credentials = DefaultAzureCredential() # Initialize Resource Graph client resource_graph_client = ResourceGraphClient(credentials) skip = 0 result = [] query_code = f""" resourcecontainers | where type == 'microsoft.resources/subscriptions/resourcegroups' | extend dates=format_datetime(now(), "yyyy-MM-dd") | join kind=leftouter ( resourcecontainers | where type == 'microsoft.resources/subscriptions' | project SubscriptionName=name, subscriptionId) on subscriptionId | project SubscriptionName, subscriptionId, resourceGroup, financial_contact=tags.financial_contact, security_contact=tags.security_contact, environment=tags.environment, version=tags.version, dates, type, location, id_prefix=id """ query = QueryRequest( query= query_code ) query_response = resource_graph_client.resources(query) query_response_str = str(query_response) json_data = json.dumps(query_response_str) json_data = json.loads(json_data) output_file = "resource_groups_tags.txt" with open(output_file, "w") as f: json.dump(json_data, f, indent=4)
响应示例:
{'additional_properties': {}, 'total_records': 530, 'count': 530, 'result_truncated': 'false', 'skip_token': None, 'data': [{'SubscriptionName': '...'}]}
问题原因
- 原代码未实现循环分页逻辑,仅发起一次请求,未利用
skip_token获取后续数据 - 错误地将
QueryResponse对象转成字符串再序列化,破坏了原有数据结构 - 未设置
QueryRequestOptions指定每页最大返回条数(默认值可能限制了单页数量)
修正后的代码
以下代码实现了完整的分页逻辑,通过循环检查skip_token获取全量数据:
from azure.identity import DefaultAzureCredential from azure.mgmt.resourcegraph import ResourceGraphClient from azure.mgmt.resourcegraph.models import QueryRequest, QueryRequestOptions import json # 初始化凭据和客户端 credentials = DefaultAzureCredential() resource_graph_client = ResourceGraphClient(credentials) # 定义查询语句 query_code = """ resourcecontainers | where type == 'microsoft.resources/subscriptions/resourcegroups' | extend dates=format_datetime(now(), "yyyy-MM-dd") | join kind=leftouter ( resourcecontainers | where type == 'microsoft.resources/subscriptions' | project SubscriptionName=name, subscriptionId) on subscriptionId | project SubscriptionName, subscriptionId, resourceGroup, financial_contact=tags.financial_contact, security_contact=tags.security_contact, environment=tags.environment, version=tags.version, dates, type, location, id_prefix=id """ # 初始化结果列表和分页参数 all_results = [] skip_token = None # 循环分页获取数据 while True: # 构造查询请求,设置每页最大返回1000条(Azure Resource Graph单页最大支持1000条) request_options = QueryRequestOptions( skip_token=skip_token, top=1000 ) query_request = QueryRequest( query=query_code, options=request_options ) # 发起查询请求 response = resource_graph_client.resources(query_request) # 将当前页数据加入结果列表 all_results.extend(response.data) # 检查是否还有后续数据 if not response.skip_token: break skip_token = response.skip_token # 将结果写入JSON文件 output_file = "resource_groups_tags_full.json" with open(output_file, "w", encoding="utf-8") as f: json.dump(all_results, f, indent=4, ensure_ascii=False) print(f"全量数据已写入文件,共{len(all_results)}条记录")
关键说明
- 分页逻辑:通过
while循环持续检查response.skip_token,只要存在就继续发起请求,直到skip_token为None - 单页条数设置:通过
QueryRequestOptions的top参数设置单页最大返回1000条(Azure Resource Graph的单页上限),减少请求次数 - 数据处理:直接访问
response.data获取结构化数据,避免原代码中字符串转义导致的数据损坏 - 权限验证:确保使用的
DefaultAzureCredential对应的账号拥有租户内所有订阅的Reader或更高权限,避免因权限不足导致部分资源组无法返回
内容的提问来源于stack exchange,提问作者Louey
相关产品推荐
相关产品推荐

