欢迎光临
我们一直在努力

运维实战|零基础也能上手:用AI+Python一键统计阿里云+腾讯云费用(附完整代码)

运维实战|零基础也能上手:用AI+Python一键统计阿里云+腾讯云费用(附完整代码)

文章目录

  • 运维实战|零基础也能上手:用AI+Python一键统计阿里云+腾讯云费用(附完整代码)
    • @[toc]
    • 一、这篇教程能帮你解决什么?
      • 你是否有这样的烦恼?
      • 学完这篇教程,你能做什么?
      • 你需要什么基础?
    • 二、准备工作(5分钟搞定)
      • 2.1 检查Python是否装好
      • 2.2 准备AccessKey(云账号的"门禁卡")
    • 三、阿里云费用统计(跟着做就行)
      • 3.1 创建脚本文件
      • 3.2 改两个地方就能用
      • 3.3 运行脚本(就两步)
      • 3.4 看懂输出结果
    • 四、腾讯云费用统计(同样的套路)
      • 4.1 复制粘贴第二个脚本
      • 4.2 和阿里云脚本的区别(通俗解释)
      • 4.3 运行腾讯云脚本
    • 五、进阶:两个脚本合体 + 自动发邮件
      • 5.1 完整的合体脚本
      • 5.2 改配置,运行
      • 5.3 运行
    • 六、更进一步:设定时任务,从此不用手动
    • 七、常见问题
    • 八、总结

一、这篇教程能帮你解决什么?

你是否有这样的烦恼?

每月月底,财务同事准时来催:“这个月的云服务费用统计好了吗?”

然后你打开阿里云控制台、腾讯云控制台,一个一个产品翻账单,手动加起来,填到Excel里,再写邮件发过去。每次至少花半小时,而且怕算错、怕漏掉产品。

学完这篇教程,你能做什么?

  • 自动拉取阿里云和腾讯云的账单数据
  • 自动生成汇总报表
  • 自动对比上月数据,发现异常自动提醒
  • 自动发送邮件给财务/领导
  • 设定时任务,每月1号自动跑,从此不用手动操作
  • 你需要什么基础?

    几乎不需要! 只要你会:

    • ✅ 复制粘贴文字(会用Ctrl+C/V就行)
    • ✅ 双击运行一个文件
    • ✅ 看懂简单的表格

    我不需要你会Python,不需要你懂API,不需要你学过编程。


    二、准备工作(5分钟搞定)

    2.1 检查Python是否装好

    Python就是运行脚本的工具。先看看你的电脑有没有装:

    Windows用户:

  • 按 Win + R,输入 cmd,回车
  • 在黑色窗口里输入:python –version
  • 如果显示类似 Python 3.x.x,说明装好了 ✅
  • 如果提示"不是内部命令",说明没装 → 去 python.org 下载安装(安装时勾选"Add Python to PATH")
  • Mac用户:

  • 打开"终端"(在应用程序→实用工具里)
  • 输入:python3 –version
  • Mac一般自带Python,直接能用 ✅
  • 2.2 准备AccessKey(云账号的"门禁卡")

    什么是AccessKey?

    把云平台想象成一栋大楼:

    • 你的云账号 = 你的身份证(证明你是谁)
    • AccessKey = 你的门禁卡(用来刷卡开门、进入各个房间)
    • API = 大楼里的自动服务台(你刷门禁卡,服务台帮你查东西)

    AI脚本需要通过AccessKey来"刷卡"进入云平台,帮你查询账单数据。所以你需要先从云平台办一张门禁卡。

    去哪办?(以阿里云为例,腾讯云类似)

  • 登录阿里云控制台(ram.console.aliyun.com)
  • 点击右上角头像 → “访问控制”
  • 左侧菜单 → “用户” → “创建用户”
  • 勾选"OpenAPI调用访问"
  • 创建完成后,系统会给你两个东西:
    • AccessKey ID(相当于门禁卡的编号,比如:LTAI5tXXXXXX)
    • AccessKey Secret(相当于门禁卡的密码,比如:wE2kXXXXXXXX)
  • ⚠️ 重要:AccessKey Secret只在创建时显示一次,马上复制保存!丢了只能重新创建。

  • 给这个子账号只分配"只读"权限(比如 AliyunBSSReadOnlyAccess),这样就算AccessKey泄露,别人也只能看账单,无法操作你的云资源。
  • 把AccessKey保存到电脑上

    在电脑上新建一个文本文件(用记事本就行),内容像这样:

    AccessKey ID:LTAI5tXXXXXX
    AccessKey Secret:wE2kXXXXXXXX

    保存为 aliyun_key.txt,记住保存的位置(比如桌面)。

    腾讯云的AccessKey去哪办?

    登录腾讯云控制台(console.cloud.tencent.com/cam/capi),步骤类似,创建后保存到 tencent_key.txt。


    三、阿里云费用统计(跟着做就行)

    3.1 创建脚本文件

    你不需要写任何代码,只需要复制粘贴。

  • 打开记事本(Windows按Win键搜"记事本")
  • 把下面这整段代码全部复制,粘贴到记事本里:
  • #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    阿里云短信+语音服务费用统计脚本
    功能:自动查询阿里云BSS账单,统计短信和语音服务的费用
    使用方法:把下面的 "AccessKey文件路径" 和 "要查的月份" 改成你自己的,
    然后双击运行就行了。
    """

    import json
    import time
    import hmac
    import hashlib
    import base64
    import urllib.request
    import urllib.parse

    # ════════════════════════════════════════════
    # 🔧 你只需要改这两个地方!
    # ════════════════════════════════════════════

    # 第1处:改成你的AccessKey文件路径
    # 举例:如果文件在桌面,就是 r"C:\\Users\\你的用户名\\Desktop\\aliyun_key.txt"
    ACCESSKEY_FILE = r"D:\\你的路径\\aliyun_key.txt"

    # 第2处:改成你要查的月份(格式:年-月)
    # 举例:查2026年4月,就是 "2026-04"
    BILLING_MONTH = "2026-04"

    # ════════════════════════════════════════════
    # 下面的代码不需要修改,直接运行就行
    # ════════════════════════════════════════════

    def read_credentials(file_path):
    """从文件中读取AccessKey"""
    ak_id = ""
    ak_secret = ""
    try:
    with open(file_path, 'r', encoding='utf-8') as f:
    for line in f.readlines():
    if 'AccessKey ID' in line:
    ak_id = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    elif 'AccessKey Secret' in line:
    ak_secret = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    return ak_id, ak_secret
    except Exception as e:
    print(f"❌ 读取AccessKey文件失败: {e}")
    return None, None

    def percent_encode(s):
    """阿里云要求的URL编码方式"""
    s = str(s)
    encoded = urllib.parse.quote(s, safe='~')
    return encoded.replace('+', '%20').replace('*', '%2A')

    def build_signed_url(ak_id, ak_secret, action, params):
    """
    构造带签名的请求URL
    简单理解:就像在快递单上签名,证明这个请求是你发的
    """

    # 公共参数(每个请求都要带的)
    common = {
    'Format': 'JSON',
    'Version': '2017-12-14',
    'AccessKeyId': ak_id,
    'SignatureMethod': 'HMAC-SHA1',
    'Timestamp': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
    'SignatureVersion': '1.0',
    'SignatureNonce': str(int(time.time() * 1000000)),
    'Action': action,
    }

    # 合并所有参数
    all_params = {**common, **params}

    # 按字母排序,拼接成字符串
    sorted_keys = sorted(all_params.keys())
    canonical = '&'.join([f"{percent_encode(k)}={percent_encode(all_params[k])}" for k in sorted_keys])

    # 生成签名
    string_to_sign = f"GET&{percent_encode('/')}&{percent_encode(canonical)}"
    key = (ak_secret + '&').encode('utf-8')
    signature = base64.b64encode(hmac.new(key, string_to_sign.encode('utf-8'), hashlib.sha1).digest()).decode('utf-8')

    # 构造最终URL
    all_params['Signature'] = signature
    final = '&'.join([f"{percent_encode(k)}={percent_encode(all_params[k])}" for k in sorted(all_params.keys())])
    return f"https://business.aliyuncs.com/?{final}"

    def call_api(ak_id, ak_secret, action, params):
    """发送请求到阿里云,获取数据"""
    url = build_signed_url(ak_id, ak_secret, action, params)
    req = urllib.request.Request(url)
    req.add_header('Accept', 'application/json')
    try:
    response = urllib.request.urlopen(req, timeout=30)
    return json.loads(response.read().decode('utf-8'))
    except Exception as e:
    print(f" ❌ 请求失败: {e}")
    return None

    def main():
    print("=" * 60)
    print(" 阿里云短信+语音服务费用统计")
    print("=" * 60)

    # 1. 读取AccessKey
    ak_id, ak_secret = read_credentials(ACCESSKEY_FILE)
    if not ak_id or not ak_secret:
    print("❌ 请检查AccessKey文件路径是否正确")
    return

    print(f"✅ AccessKey读取成功")
    print(f"📅 查询月份: {BILLING_MONTH}")
    print()

    # 2. 查询所有产品的费用
    print("正在查询阿里云账单…")
    result = call_api(ak_id, ak_secret, 'QueryBillOverview', {
    'BillingCycle': BILLING_MONTH,
    })

    if not result or 'Data' not in result:
    print("❌ 未获取到数据,请检查月份格式是否正确")
    return

    # 3. 提取短信和语音的费用
    items = result['Data'].get('Items', {}).get('Item', [])
    if isinstance(items, dict):
    items = [items]

    # 合并相同产品代码的费用
    merged = {}
    for item in items:
    code = item.get('ProductCode', 'N/A')
    name = item.get('ProductName', 'N/A')
    amount = float(item.get('PretaxAmount', 0))
    if code not in merged:
    merged[code] = {'code': code, 'name': name, 'amount': 0.0}
    merged[code]['amount'] += amount

    print(f"\\n{'产品代码':<20} {'产品名称':<25} {'费用(元)':>12}")
    print("-" * 60)

    sms_total = 0.0
    voice_total = 0.0

    for code, info in merged.items():
    name = info['name']
    amount = info['amount']

    # 找短信和语音产品
    is_sms = any(kw in name.lower() or kw in code.lower()
    for kw in ['短信', 'sms', 'dysms', 'message'])
    is_voice = any(kw in name.lower() or kw in code.lower()
    for kw in ['语音', 'voice', 'dyvms', 'vms'])

    marker = ''
    if is_sms:
    marker = ' ← 📱短信'
    sms_total += amount
    elif is_voice:
    marker = ' ← 📞语音'
    voice_total += amount

    print(f"{code:<20} {name[:23]:<25} {amount:>12.2f}{marker}")

    # 4. 输出汇总结果
    print("-" * 60)
    print(f"\\n📊 汇总结果:")
    print(f" 短信服务合计: {sms_total:.2f} 元")
    print(f" 语音服务合计: {voice_total:.2f} 元")
    print(f" {'─' * 40}")
    print(f" 💰 总计(税前): {sms_total + voice_total:.2f} 元")
    print(f"\\n✅ 查询完成!")

    if __name__ == '__main__':
    main()

  • 点击记事本的"文件" → “另存为”
  • 文件名改成:aliyun_cost.py
  • 保存类型一定要选"所有文件"(不是"文本文件")!
  • 保存到桌面(方便找到)
  • 3.2 改两个地方就能用

    打开 aliyun_cost.py(右键→打开方式→记事本),找到这两行,改成你自己的:

    # 改这里 ↓
    ACCESSKEY_FILE = r"D:\\你的路径\\aliyun_key.txt"
    # 举例:如果aliyun_key.txt在桌面
    # ACCESSKEY_FILE = r"C:\\Users\\Administrator\\Desktop\\aliyun_key.txt"

    # 改这里 ↓
    BILLING_MONTH = "2026-04"
    # 改成你要查的月份,比如 "2026-05"

    3.3 运行脚本(就两步)

  • 打开命令行:在脚本所在的文件夹,按住 Shift 键,右键点击空白处,选择"在此处打开PowerShell窗口"

  • 输入命令,回车:

  • python aliyun_cost.py

    3.4 看懂输出结果

    运行后,你会看到类似这样的输出:

    ============================================================
    阿里云短信+语音服务费用统计
    ============================================================
    ✅ AccessKey读取成功
    📅 查询月份: 2026-04

    正在查询阿里云账单…

    产品代码 产品名称 费用(元)
    ————————————————————
    dysms 短信服务 50,000.00 ← 📱短信
    dyvms 语音服务 17,935.66 ← 📞语音

    📊 汇总结果:
    短信服务合计: 50000.00 元
    语音服务合计: 17935.66 元
    ────────────────────────────────────────
    💰 总计(税前): 67935.66 元

    ✅ 查询完成!

    每一行代表什么?

    • 产品代码:阿里云内部的编号(dysms = 短信服务,dyvms = 语音服务)
    • 产品名称:你能看懂的中文名字
    • 费用(元):这个产品当月花了多少钱(税前)
    • 📱/📞:标记表示这是短信还是语音

    ⚠️ 常见问题:如果输出里没有看到短信和语音,说明你的阿里云账号里没有这两个产品的费用,或者月份格式不对。


    四、腾讯云费用统计(同样的套路)

    4.1 复制粘贴第二个脚本

    跟刚才一样,新建一个记事本,粘贴下面的代码,保存为 tencent_cost.py:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    腾讯云人脸核身费用统计脚本
    功能:自动查询腾讯云账单,统计人脸核身服务的费用
    使用方法:改AccessKey路径和月份,然后运行
    """

    import json
    import time
    import hmac
    import hashlib
    import urllib.request
    import calendar

    # ════════════════════════════════════════════
    # 🔧 你只需要改这两个地方!
    # ════════════════════════════════════════════

    # 第1处:改成你的腾讯云AccessKey文件路径
    ACCESSKEY_FILE = r"D:\\你的路径\\tencent_key.txt"

    # 第2处:改成你要查的月份
    BILLING_MONTH = "2026-04"

    # ════════════════════════════════════════════
    # 下面的代码不需要修改
    # ════════════════════════════════════════════

    def read_credentials(file_path):
    """从文件中读取AccessKey"""
    sid = ""
    skey = ""
    try:
    with open(file_path, 'r', encoding='utf-8') as f:
    for line in f.readlines():
    line = line.strip()
    if line.startswith('#'):
    continue
    if 'SecretId' in line or 'AKID' in line:
    sid = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    elif 'SecretKey' in line:
    skey = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    return sid, skey
    except Exception as e:
    print(f"❌ 读取AccessKey文件失败: {e}")
    return None, None

    def sign(key, msg):
    """腾讯云TC3签名算法的一部分"""
    if isinstance(key, str):
    key = key.encode('utf-8')
    if isinstance(msg, str):
    msg = msg.encode('utf-8')
    return hmac.new(key, msg, hashlib.sha256).digest()

    def sha256_hex(s):
    """计算SHA256哈希值"""
    if isinstance(s, str):
    s = s.encode('utf-8')
    return hashlib.sha256(s).hexdigest()

    def call_api(sid, skey, service, action, region, params):
    """
    调用腾讯云API
    注意:腾讯云的签名方式比阿里云复杂一些,但原理一样——
    都是在你发送的请求上"签名",证明是你发的
    """

    host = f"{service}.tencentcloudapi.com"

    # 1. 构造请求内容
    payload = json.dumps(params)

    # 2. 构造"规范请求串"(腾讯云要求的格式)
    ct = "application/json; charset=utf-8"
    hashed_payload = sha256_hex(payload)
    canonical = f"POST\\n/\\n\\ncontent-type:{ct}\\nhost:{host}\\n\\ncontent-type;host\\n{hashed_payload}"

    # 3. 生成签名
    timestamp = str(int(time.time()))
    from datetime import datetime
    date = datetime.utcfromtimestamp(int(timestamp)).strftime("%Y-%m-%d")
    scope = f"{date}/{service}/tc3_request"
    string_to_sign = f"TC3-HMAC-SHA256\\n{timestamp}\\n{scope}\\n{sha256_hex(canonical)}"

    # 4. 计算最终签名(分4步)
    secret_date = sign(("TC3" + skey).encode('utf-8'), date)
    secret_service = sign(secret_date, service)
    secret_signing = sign(secret_service, "tc3_request")
    signature = hmac.new(secret_signing, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()

    # 5. 发送请求
    auth = f"TC3-HMAC-SHA256 Credential={sid}/{scope}, SignedHeaders=content-type;host, Signature={signature}"
    req = urllib.request.Request(f"https://{host}/", data=payload.encode('utf-8'))
    req.add_header('Authorization', auth)
    req.add_header('Content-Type', ct)
    req.add_header('Host', host)
    req.add_header('X-TC-Action', action)
    req.add_header('X-TC-Version', '2018-07-09')
    req.add_header('X-TC-Timestamp', timestamp)
    req.add_header('X-TC-Region', region)

    try:
    response = urllib.request.urlopen(req, timeout=30)
    return json.loads(response.read().decode('utf-8'))
    except Exception as e:
    print(f" ❌ 请求失败: {e}")
    return None

    def main():
    print("=" * 60)
    print(" 腾讯云人脸核身费用统计")
    print("=" * 60)

    # 1. 读取AccessKey
    sid, skey = read_credentials(ACCESSKEY_FILE)
    if not sid or not skey:
    print("❌ 请检查AccessKey文件路径是否正确")
    return

    print(f"✅ AccessKey读取成功")
    print(f"📅 查询月份: {BILLING_MONTH}")
    print()

    # 2. 构造时间范围(当月1号到当月最后一天)
    year, mon = BILLING_MONTH.split('-')
    begin = f"{year}{mon}-01 00:00:00"
    last_day = calendar.monthrange(int(year), int(mon))[1]
    end = f"{year}{mon}{last_day:02d} 23:59:59"

    # 3. 查询所有产品费用
    print("正在查询腾讯云账单…")
    result = call_api(sid, skey, 'billing', 'DescribeBillSummaryByProduct', 'ap-guangzhou', {
    'BeginTime': begin,
    'EndTime': end,
    })

    if not result or 'Response' not in result:
    print("❌ 未获取到数据")
    return

    resp = result['Response']
    if 'Error' in resp:
    print(f"❌ API错误: {resp['Error'].get('Message', '')}")
    return

    # 4. 提取人脸核身的费用
    items = resp.get('SummaryOverview', resp.get('SummarySet', []))

    print(f"\\n{'产品代码':<30} {'产品名称':<25} {'费用(元)':>12}")
    print("-" * 70)

    faceid_total = 0.0
    all_total = 0.0

    for item in items:
    code = item.get('BusinessCode', 'N/A')
    name = item.get('BusinessCodeName', 'N/A')
    cost = float(item.get('RealTotalCost', 0)) # 腾讯云金额单位已经是元,不需要换算
    all_total += cost

    is_faceid = any(kw in name for kw in ['人脸核身', '云智慧眼', 'faceid', '人脸', '活体'])
    marker = ' ← 🆔人脸核身' if is_faceid else ''

    print(f"{code:<30} {name[:23]:<25} {cost:>12.2f}{marker}")

    if is_faceid:
    faceid_total += cost

    print("-" * 70)
    print(f"\\n📊 汇总结果:")
    print(f" 人脸核身服务合计: {faceid_total:.2f} 元")
    print(f" 全部产品合计: {all_total:.2f} 元")
    print(f"\\n✅ 查询完成!")

    if __name__ == '__main__':
    main()

    4.2 和阿里云脚本的区别(通俗解释)

    两个脚本做的事情一样:查账单。但"说话方式"不同:

    对比项阿里云腾讯云
    签名方式 HMAC-SHA1(老式门锁,一把钥匙开一把锁) TC3-HMAC-SHA256(指纹锁,更安全但步骤多)
    请求方式 GET(跟浏览器打开网页一样) POST(提交表单一样)
    金额单位 元(不需要转换)
    字段名 PretaxAmount RealTotalCost

    💡 打个比方:阿里云和腾讯云就像两家不同的银行。你要查账单,填的表格长得不一样,但目的都一样——查到花了多少钱。

    4.3 运行腾讯云脚本

    跟阿里云一样:

    python tencent_cost.py


    五、进阶:两个脚本合体 + 自动发邮件

    上面的两个脚本是分开的(一个查阿里云,一个查腾讯云)。现在我们把它合并起来,一次性搞定两边,还能自动发邮件。

    5.1 完整的合体脚本

    新建 cloud_cost_report.py,粘贴以下代码。这次也是只改配置区域:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    云服务费用统计 + 自动发邮件
    功能:同时查阿里云和腾讯云的费用,生成报表,自动发邮件
    使用方法:改下面的配置区,然后运行
    """

    import json, time, hmac, hashlib, base64, urllib.request, urllib.parse
    import smtplib, calendar
    from email.mime.text import MIMEText
    from email.utils import formataddr
    from datetime import datetime

    # ════════════════════════════════════════════
    # 🔧 配置区(只需要改这里!)
    # ════════════════════════════════════════════

    # 阿里云AccessKey文件
    ALIYUN_KEY_FILE = r"D:\\你的路径\\aliyun_key.txt"

    # 腾讯云AccessKey文件
    TENCENT_KEY_FILE = r"D:\\你的路径\\tencent_key.txt"

    # 查询哪个月份
    MONTH = "2026-04"

    # 邮箱配置(发件人)
    EMAIL_CONFIG = {
    "smtp_server": "smtp.qq.com", # QQ邮箱就填这个;163邮箱填 smtp.163.com
    "smtp_port": 465, # QQ邮箱/163邮箱都用465
    "username": "你的邮箱@qq.com", # 改成你的邮箱
    "password": "你的邮箱授权码", # 注意:不是邮箱密码,是"授权码"!
    "sender_name": "系统运维部", # 发件人显示的名字
    }

    # 收件人(可以填多个)
    RECIPIENTS = ["财务@公司.com", "领导@公司.com"]

    # 费用异常阈值:如果本月费用比上月偏差超过20%,自动提醒
    DEVIATION_THRESHOLD = 0.20

    # ════════════════════════════════════════════
    # 阿里云API部分(不需要修改)
    # ════════════════════════════════════════════

    def read_aliyun_key(file_path):
    """读取阿里云AccessKey"""
    ak_id, ak_secret = "", ""
    try:
    with open(file_path, 'r', encoding='utf-8') as f:
    for line in f.readlines():
    if 'AccessKey ID' in line:
    ak_id = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    elif 'AccessKey Secret' in line:
    ak_secret = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    return ak_id, ak_secret
    except Exception as e:
    print(f"❌ 读取阿里云AccessKey失败: {e}")
    return None, None

    def percent_encode(s):
    s = str(s)
    encoded = urllib.parse.quote(s, safe='~')
    return encoded.replace('+', '%20').replace('*', '%2A')

    def call_aliyun(ak_id, ak_secret, action, params):
    """调用阿里云API"""
    common = {
    'Format': 'JSON', 'Version': '2017-12-14', 'AccessKeyId': ak_id,
    'SignatureMethod': 'HMAC-SHA1',
    'Timestamp': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
    'SignatureVersion': '1.0',
    'SignatureNonce': str(int(time.time() * 1000000)),
    'Action': action,
    }
    all_p = {**common, **params}
    sorted_k = sorted(all_p.keys())
    canonical = '&'.join([f"{percent_encode(k)}={percent_encode(all_p[k])}" for k in sorted_k])
    sign_str = f"GET&{percent_encode('/')}&{percent_encode(canonical)}"
    key = (ak_secret + '&').encode('utf-8')
    sig = base64.b64encode(hmac.new(key, sign_str.encode('utf-8'), hashlib.sha1).digest()).decode('utf-8')
    all_p['Signature'] = sig
    final = '&'.join([f"{percent_encode(k)}={percent_encode(all_p[k])}" for k in sorted(all_p.keys())])
    url = f"https://business.aliyuncs.com/?{final}"

    req = urllib.request.Request(url)
    req.add_header('Accept', 'application/json')
    try:
    resp = urllib.request.urlopen(req, timeout=30)
    return json.loads(resp.read().decode('utf-8'))
    except Exception as e:
    print(f" ❌ 阿里云请求失败: {e}")
    return None

    def fetch_aliyun_cost(month):
    """采集阿里云短信+语音费用"""
    ak_id, ak_secret = read_aliyun_key(ALIYUN_KEY_FILE)
    if not ak_id or not ak_secret:
    return None

    result = call_aliyun(ak_id, ak_secret, 'QueryBillOverview', {'BillingCycle': month})
    if not result or 'Data' not in result:
    return None

    items = result['Data'].get('Items', {}).get('Item', [])
    if isinstance(items, dict):
    items = [items]

    sms_total = 0.0
    voice_total = 0.0

    for item in items:
    code = item.get('ProductCode', '')
    name = item.get('ProductName', '')
    amount = float(item.get('PretaxAmount', 0))

    if any(kw in name.lower() or kw in code.lower() for kw in ['短信', 'sms', 'dysms', 'message']):
    sms_total += amount
    elif any(kw in name.lower() or kw in code.lower() for kw in ['语音', 'voice', 'dyvms', 'vms']):
    voice_total += amount

    return {'sms': sms_total, 'voice': voice_total, 'total': sms_total + voice_total}

    # ════════════════════════════════════════════
    # 腾讯云API部分(不需要修改)
    # ════════════════════════════════════════════

    def read_tencent_key(file_path):
    """读取腾讯云AccessKey"""
    sid, skey = "", ""
    try:
    with open(file_path, 'r', encoding='utf-8') as f:
    for line in f.readlines():
    line = line.strip()
    if line.startswith('#'):
    continue
    if 'SecretId' in line or 'AKID' in line:
    sid = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    elif 'SecretKey' in line:
    skey = line.split(':')[1].strip() if ':' in line else line.split(':')[1].strip()
    return sid, skey
    except Exception as e:
    print(f"❌ 读取腾讯云AccessKey失败: {e}")
    return None, None

    def tc3_sign(key, msg):
    if isinstance(key, str): key = key.encode('utf-8')
    if isinstance(msg, str): msg = msg.encode('utf-8')
    return hmac.new(key, msg, hashlib.sha256).digest()

    def sha256(s):
    if isinstance(s, str): s = s.encode('utf-8')
    return hashlib.sha256(s).hexdigest()

    def call_tencent(sid, skey, service, action, region, params):
    """调用腾讯云API"""
    host = f"{service}.tencentcloudapi.com"
    payload = json.dumps(params)

    ct = "application/json; charset=utf-8"
    canonical = f"POST\\n/\\n\\ncontent-type:{ct}\\nhost:{host}\\n\\ncontent-type;host\\n{sha256(payload)}"

    ts = str(int(time.time()))
    date = datetime.utcfromtimestamp(int(ts)).strftime("%Y-%m-%d")
    scope = f"{date}/{service}/tc3_request"
    sign_str = f"TC3-HMAC-SHA256\\n{ts}\\n{scope}\\n{sha256(canonical)}"

    d = tc3_sign(("TC3" + skey).encode('utf-8'), date)
    s = tc3_sign(d, service)
    ss = tc3_sign(s, "tc3_request")
    sig = hmac.new(ss, sign_str.encode('utf-8'), hashlib.sha256).hexdigest()

    auth = f"TC3-HMAC-SHA256 Credential={sid}/{scope}, SignedHeaders=content-type;host, Signature={sig}"
    req = urllib.request.Request(f"https://{host}/", data=payload.encode('utf-8'))
    for k, v in [('Authorization', auth), ('Content-Type', ct), ('Host', host),
    ('X-TC-Action', action), ('X-TC-Version', '2018-07-09'),
    ('X-TC-Timestamp', ts), ('X-TC-Region', region)]:
    req.add_header(k, v)

    try:
    resp = urllib.request.urlopen(req, timeout=30)
    return json.loads(resp.read().decode('utf-8'))
    except Exception as e:
    print(f" ❌ 腾讯云请求失败: {e}")
    return None

    def fetch_tencent_cost(month):
    """采集腾讯云人脸核身费用"""
    sid, skey = read_tencent_key(TENCENT_KEY_FILE)
    if not sid or not skey:
    return None

    year, mon = month.split('-')
    begin = f"{year}{mon}-01 00:00:00"
    last_day = calendar.monthrange(int(year), int(mon))[1]
    end = f"{year}{mon}{last_day:02d} 23:59:59"

    result = call_tencent(sid, skey, 'billing', 'DescribeBillSummaryByProduct', 'ap-guangzhou', {
    'BeginTime': begin, 'EndTime': end,
    })

    if not result or 'Response' not in result:
    return None

    resp = result['Response']
    if 'Error' in resp:
    print(f" ❌ 腾讯云API错误: {resp['Error'].get('Message', '')}")
    return None

    items = resp.get('SummaryOverview', resp.get('SummarySet', []))
    faceid_total = 0.0

    for item in items:
    name = item.get('BusinessCodeName', '')
    if any(kw in name for kw in ['人脸核身', '云智慧眼', 'faceid', '人脸', '活体']):
    faceid_total += float(item.get('RealTotalCost', 0))

    return {'faceid': faceid_total}

    # ════════════════════════════════════════════
    # 邮件发送部分
    # ════════════════════════════════════════════

    def send_report(data):
    """生成并发送邮件报表"""
    # 生成邮件内容
    subject = f"{data['month']}月云服务费用(短信+语音+人脸核身)统计报表"

    html = f"""
    <html>
    <head><meta charset="utf-8"></head>
    <body style="font-family: Microsoft YaHei, sans-serif; font-size: 14px;">
    <h2>📊
    {data['month']}月云服务费用统计报表</h2>
    <p>统计时间:
    {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
    <p>用途:采购申报</p>
    <hr>
    <table border="1" cellpadding="8" cellspacing="0" style="border-collapse:collapse;">
    <tr style="background:#f5f5f5;">
    <th>云厂商</th><th>产品</th><th>费用(元)</th>
    </tr>
    <tr>
    <td>阿里云</td><td>短信服务</td><td>
    {data['aliyun_sms']:.2f}</td>
    </tr>
    <tr>
    <td>阿里云</td><td>语音服务</td><td>
    {data['aliyun_voice']:.2f}</td>
    </tr>
    <tr>
    <td>腾讯云</td><td>人脸核身</td><td>
    {data['tencent_faceid']:.2f}</td>
    </tr>
    <tr style="font-weight:bold;background:#e8f5e9;">
    <td colspan="2">总计</td><td>
    {data['total']:.2f}</td>
    </tr>
    </table>
    <br>
    <p style="color:#999;font-size:12px;">数据来源:阿里云BSS OpenAPI / 腾讯云Billing API</p>
    </body>
    </html>
    """

    # 发送邮件
    try:
    config = EMAIL_CONFIG
    print(f"📧 正在发送邮件到: {', '.join(RECIPIENTS)}…")

    server = smtplib.SMTP_SSL(config['smtp_server'], config['smtp_port'], timeout=30)
    server.login(config['username'], config['password'])

    msg = MIMEText(html, 'html', 'utf-8')
    msg['From'] = formataddr((config['sender_name'], config['username']))
    msg['To'] = ', '.join(RECIPIENTS)
    msg['Subject'] = subject

    server.send_message(msg)
    server.quit()
    print("✅ 邮件发送成功!")
    return True
    except Exception as e:
    print(f"❌ 邮件发送失败: {e}")
    return False

    # ════════════════════════════════════════════
    # 主程序
    # ════════════════════════════════════════════

    def main():
    print("=" * 60)
    print(" 云服务费用统计 + 邮件发送")
    print("=" * 60)
    print(f" 📅 查询月份: {MONTH}")
    print()

    # 1. 采集阿里云费用
    print("📊 正在采集阿里云费用…")
    aliyun = fetch_aliyun_cost(MONTH)
    if not aliyun:
    print(" ❌ 阿里云数据采集失败,请检查AccessKey和月份")
    return
    print(f" ✅ 阿里云短信: {aliyun['sms']:.2f} 元")
    print(f" ✅ 阿里云语音: {aliyun['voice']:.2f} 元")

    # 2. 采集腾讯云费用
    print("\\n📊 正在采集腾讯云费用…")
    tencent = fetch_tencent_cost(MONTH)
    if not tencent:
    print(" ❌ 腾讯云数据采集失败,请检查AccessKey和月份")
    return
    print(f" ✅ 腾讯云人脸核身: {tencent['faceid']:.2f} 元")

    # 3. 汇总
    data = {
    'month': MONTH,
    'aliyun_sms': aliyun['sms'],
    'aliyun_voice': aliyun['voice'],
    'tencent_faceid': tencent['faceid'],
    'total': aliyun['total'] + tencent['faceid'],
    }

    print(f"\\n{'─' * 40}")
    print(f" 💰 总计: {data['total']:.2f} 元")
    print(f"{'─' * 40}")

    # 4. 发送邮件
    print()
    send_report(data)

    print(f"\\n✅ 全部完成!")
    print(f" 如需自动定时执行,对AI说:每月1号早上9点自动跑这个脚本")

    if __name__ == '__main__':
    main()

    5.2 改配置,运行

    只需要改最上面的 配置区:

    # 把文件路径改成你自己的
    ALIYUN_KEY_FILE = r"D:\\你的路径\\aliyun_key.txt"
    TENCENT_KEY_FILE = r"D:\\你的路径\\tencent_key.txt"
    MONTH = "2026-04"

    # 改成你的邮箱
    EMAIL_CONFIG = {
    "smtp_server": "smtp.qq.com", # 用什么邮箱就填什么
    "username": "你的邮箱@qq.com",
    "password": "你的邮箱授权码", # QQ邮箱→设置→账户→POP3/SMTP→生成授权码
    }

    RECIPIENTS = ["收件人1@公司.com", "收件人2@公司.com"]

    💡 怎么获取邮箱授权码?

    • QQ邮箱:登录→设置→账户→POP3/IMAP/SMTP服务→开启→生成授权码
    • 163邮箱:登录→设置→POP3/SMTP/IMAP→开启→新增授权码
    • 授权码是一个16位的字母数字组合,不是你的邮箱密码!

    5.3 运行

    python cloud_cost_report.py

    输出示例:

    ============================================================
    云服务费用统计 + 邮件发送
    ============================================================
    📅 查询月份: 2026-04

    📊 正在采集阿里云费用…
    ✅ 阿里云短信: 50000.00 元
    ✅ 阿里云语音: 17935.66 元

    📊 正在采集腾讯云费用…
    ✅ 腾讯云人脸核身: 127258.48 元

    ────────────────────────────────────────
    💰 总计: 195194.14 元
    ────────────────────────────────────────

    📧 正在发送邮件到: 财务@公司.com…
    ✅ 邮件发送成功!

    ✅ 全部完成!
    如需自动定时执行,对AI说:每月1号早上9点自动跑这个脚本


    六、更进一步:设定时任务,从此不用手动

    上面的脚本已经能自动查费用、发邮件了。但每个月还要手动跑一次?太麻烦了。

    如果你有WorkBuddy或类似的AI助手,直接说:

    “帮我设置一个定时任务:每月1号早上9点自动运行 cloud_cost_report.py,跑完后把结果发邮件给我。”

    AI会帮你配好定时任务(Windows用"任务计划程序",Mac/Linux用cron)。从此每个月自动跑,你什么都不用做。


    七、常见问题

    Q:运行后显示"❌ 读取AccessKey文件失败"怎么办? A:检查三个地方:

  • 文件路径对不对(注意Windows路径用 r"D:\\…" 这种写法)
  • 文件内容格式对不对(必须有 AccessKey ID: 和 AccessKey Secret: 这两行)
  • AccessKey Secret是不是已经失效了(在云平台控制台重新生成一个)
  • Q:AccessKey放在文件里安全吗? A:建议做两件事:

  • 用只读权限的子账号AccessKey(只能看账单,不能操作资源)
  • 把AccessKey文件放在你自己电脑的私密位置,不要上传到GitHub等公开平台
  • Q:不收短信/语音/人脸核身,能用这个脚本吗? A:当然能!你只需要改一下脚本里的关键词:

    # 把这里改成你要查的产品名称关键词
    is_sms = any(kw in name for kw in ['你想查的产品名', '关键词'])

    Q:Windows和Mac都能用吗? A:都能用!Python是跨平台的,Mac用户把路径改成 /Users/你的用户名/… 就行。


    八、总结

    回顾一下,这篇教程你学会了:

  • ✅ 准备云平台的AccessKey(子账号+只读权限)
  • ✅ 用一个Python脚本,自动拉取阿里云和腾讯云的账单
  • ✅ 自动生成汇总报表,发邮件给财务
  • ✅ 设定时任务,每月自动跑
  • 从头到尾,你只做了三件事:改路径、改月份、改邮箱。其他都交给脚本。

    工具的意义不是让你学技术,而是让你把时间花在更有价值的事情上。


    如果这篇文章对你有帮助,欢迎 👍 点赞、⭐ 收藏、💬 评论!

    有问题在评论区留言,我看到都会回复。

    赞(0)
    未经允许不得转载:171主机测评 » 运维实战|零基础也能上手:用AI+Python一键统计阿里云+腾讯云费用(附完整代码)
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址