如何使用Python SDK从Azure获取月度成本数据?
问题背景
我正尝试用Azure Python SDK获取月度成本数据,用于在Azure门户制作月度成本趋势图表,但微软文档混乱过时,缺少可用示例。先后试过BillingManagementClient类、ConsumptionManagementClient.balances.get_for_billing_period_by_billing_account方法,目前尝试ConsumptionManagementClient.usage_details.list时,得到了重复的成本数据:
测试代码
consumption_client = ConsumptionManagementClient(self.credential, self.subscription_id) start_date = "2022-11-19T00:00:00.0000000Z" end_date = "2022-11-20T00:00:00.0000000Z" filters = f"properties/usageStart eq '{start_date}' and properties/usageEnd eq '{end_date}'" consumption_list = consumption_client.usage_details.list(f"/subscriptions/{subscription_id}", None, filters) for consumption_data in consumption_list: print(f"日期: {consumption_data.date} \n计费周期开始: {consumption_data.billing_period_start_date} \n计费周期结束: {consumption_data.billing_period_end_date}\n成本: {consumption_data.cost} \n")
输出结果
日期: 2022-11-20 00:00:00+00:00
计费周期开始: 2022-11-11 00:00:00+00:00
计费周期结束: 2022-12-10 00:00:00+00:00
成本: 0.658392日期: 2022-11-19 00:00:00+00:00
计费周期开始: 2022-11-11 00:00:00+00:00
计费周期结束: 2022-12-10 00:00:00+00:00
成本: 0.658392日期: 2022-11-19 00:00:00+00:00
计费周期开始: 2022-11-11 00:00:00+00:00
计费周期结束: 2022-12-10 00:00:00+00:00
成本: 0.67425593616日期: 2022-11-20 00:00:00+00:00
计费周期开始: 2022-11-11 00:00:00+00:00
计费周期结束: 2022-12-10 00:00:00+00:00
成本: 0.67425593616
解决方案
为什么会出现重复数据
usage_details.list返回的是计费明细数据,同一资源的费用可能会拆分多条记录(比如按小时计费、不同计费维度),或者同时包含预估费用和实际结算费用,所以你看到的是不同维度/状态的条目,并非真正的重复数据。
正确获取月度成本的两种方式
方式一:使用成本查询接口(推荐)
直接通过ConsumptionManagementClient.query接口,按月份聚合成本数据,适合快速生成趋势图所需的月度汇总数据:
from azure.mgmt.consumption import ConsumptionManagementClient from azure.identity import DefaultAzureCredential subscription_id = "你的订阅ID" credential = DefaultAzureCredential() consumption_client = ConsumptionManagementClient(credential, subscription_id) # 构造查询:按月份聚合总成本 query = { "type": "Usage", "timeframe": "Custom", "timePeriod": { "from": "2022-10-01T00:00:00Z", "to": "2022-12-31T23:59:59Z" }, "dataset": { "granularity": "Monthly", "aggregation": { "totalCost": { "name": "PreTaxCost", "function": "Sum" } }, "grouping": [ { "type": "Dimension", "name": "BillingPeriod" } ] } } # 执行查询 result = consumption_client.query(f"/subscriptions/{subscription_id}", query) # 处理结果 for row in result.rows: billing_period = row[0] total_cost = row[1] print(f"计费周期: {billing_period}, 月度总成本: {total_cost}")
方式二:对明细数据进行聚合
如果需要基于明细数据做自定义处理,可以先获取所有明细,再按日期/月份分组求和:
from collections import defaultdict consumption_client = ConsumptionManagementClient(credential, subscription_id) start_date = "2022-11-01T00:00:00Z" end_date = "2022-11-30T23:59:59Z" # 获取指定时间范围内的所有明细(注意分页,这里简化处理) usage_details = list(consumption_client.usage_details.list( scope=f"/subscriptions/{subscription_id}", filter=f"properties/usageStart ge '{start_date}' and properties/usageStart le '{end_date}'" )) # 按日期分组求和 daily_cost = defaultdict(float) for item in usage_details: # 提取日期部分(忽略时区) date_str = item.date.strftime("%Y-%m-%d") daily_cost[date_str] += item.cost # 输出每日成本,可进一步聚合为月度 for date, cost in sorted(daily_cost.items()): print(f"日期: {date}, 当日成本: {cost:.6f}") # 月度汇总 monthly_total = sum(daily_cost.values()) print(f"11月总成本: {monthly_total:.6f}")
注意事项
- 确保你的服务主体具备Cost Management Reader或Billing Reader权限,否则会出现权限不足的错误。
- 如果是EA订阅,需要使用计费账户/计费范围而非订阅ID作为scope。
内容的提问来源于stack exchange,提问作者Yuri

