test_api_simple.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. """
  2. 腾讯广告平台 API 简化测试脚本
  3. 不依赖 agent 框架,直接测试腾讯广告 API
  4. 使用方法:
  5. python3 examples/auto_put_ad_mini/test_api_simple.py
  6. """
  7. import json
  8. import os
  9. import sys
  10. import time
  11. import uuid
  12. from pathlib import Path
  13. from urllib.parse import urlencode
  14. # 加载 .env 文件
  15. try:
  16. from dotenv import load_dotenv
  17. # 加载项目根目录的 .env
  18. root_dir = Path(__file__).parent.parent.parent
  19. env_path = root_dir / ".env"
  20. if env_path.exists():
  21. load_dotenv(env_path)
  22. print(f"✅ 已加载配置文件: {env_path}\n")
  23. except ImportError:
  24. print("⚠️ 未安装 python-dotenv, 将尝试从系统环境变量读取\n")
  25. # 禁用代理 (测试时直连腾讯广告 API)
  26. for proxy_var in ['HTTP_PROXY', 'HTTPS_PROXY', 'http_proxy', 'https_proxy']:
  27. if proxy_var in os.environ:
  28. del os.environ[proxy_var]
  29. print(f"⚠️ 已禁用代理: {proxy_var}")
  30. try:
  31. import httpx
  32. except ImportError:
  33. print("❌ 缺少 httpx 库,请安装: pip3 install httpx")
  34. exit(1)
  35. # 配置
  36. BASE_URL = os.getenv("TENCENT_AD_BASE_URL", "https://api.e.qq.com/v3.0")
  37. ACCESS_TOKEN = os.getenv("TENCENT_AD_ACCESS_TOKEN", "")
  38. ACCOUNT_ID = os.getenv("TENCENT_AD_ACCOUNT_ID", "")
  39. TIMEOUT = 30
  40. def check_env_vars():
  41. """检查环境变量"""
  42. print("=" * 70)
  43. print("【1/4】环境变量检查")
  44. print("=" * 70)
  45. # 检查 ACCESS_TOKEN
  46. if ACCESS_TOKEN:
  47. display_token = ACCESS_TOKEN[:10] + "..." if len(ACCESS_TOKEN) > 10 else "***"
  48. print(f"✅ TENCENT_AD_ACCESS_TOKEN: {display_token}")
  49. else:
  50. print(f"❌ TENCENT_AD_ACCESS_TOKEN: 未设置")
  51. print("\n请设置环境变量:")
  52. print(" export TENCENT_AD_ACCESS_TOKEN='your_access_token'")
  53. print(" export TENCENT_AD_ACCOUNT_ID='your_account_id'")
  54. return False
  55. # 检查 ACCOUNT_ID
  56. if ACCOUNT_ID:
  57. print(f"✅ TENCENT_AD_ACCOUNT_ID: {ACCOUNT_ID}")
  58. else:
  59. print(f"❌ TENCENT_AD_ACCOUNT_ID: 未设置")
  60. return False
  61. # 检查 BASE_URL
  62. print(f"✅ TENCENT_AD_BASE_URL: {BASE_URL}")
  63. print("\n✅ 环境变量检查通过\n")
  64. return True
  65. def _common_params():
  66. """公共查询参数"""
  67. return {
  68. "access_token": ACCESS_TOKEN,
  69. "timestamp": str(int(time.time())),
  70. "nonce": uuid.uuid4().hex,
  71. }
  72. def test_account_info():
  73. """测试获取账户信息"""
  74. print("=" * 70)
  75. print("【2/4】账户信息查询测试")
  76. print("=" * 70)
  77. try:
  78. # 构建请求
  79. params = _common_params()
  80. params["account_id"] = ACCOUNT_ID
  81. params["fields"] = json.dumps(["balance", "daily_budget", "configured_status"])
  82. url = f"{BASE_URL}/accounts/get?{urlencode(params)}"
  83. print(f"请求 URL: {BASE_URL}/accounts/get")
  84. print(f"请求参数: account_id={ACCOUNT_ID}")
  85. # 发送请求
  86. resp = httpx.get(url, timeout=TIMEOUT)
  87. print(f"响应状态码: {resp.status_code}")
  88. if resp.status_code != 200:
  89. print(f"❌ HTTP 错误: {resp.status_code}")
  90. print(f"响应内容: {resp.text[:500]}")
  91. return False
  92. # 解析响应
  93. data = resp.json()
  94. print(f"响应内容: {json.dumps(data, ensure_ascii=False, indent=2)}")
  95. # 检查 API 错误码
  96. code = data.get("code", -1)
  97. if code != 0:
  98. msg = data.get("message_cn") or data.get("message", "未知错误")
  99. print(f"❌ API 错误 (code={code}): {msg}")
  100. return False
  101. # 成功
  102. account_data = data.get("data", {})
  103. if isinstance(account_data, dict) and "list" in account_data:
  104. account_data = account_data["list"][0] if account_data["list"] else {}
  105. balance = account_data.get("balance", 0)
  106. daily_budget = account_data.get("daily_budget", 0)
  107. status = account_data.get("configured_status", "未知")
  108. print(f"\n✅ 测试通过")
  109. print(f"账户信息:")
  110. print(f" - 账户 ID: {ACCOUNT_ID}")
  111. print(f" - 余额: {balance/100:.2f} 元")
  112. print(f" - 日限额: {daily_budget/100:.0f} 元")
  113. print(f" - 状态: {status}")
  114. return True
  115. except httpx.RequestError as e:
  116. print(f"❌ 网络请求错误: {e}")
  117. return False
  118. except Exception as e:
  119. print(f"❌ 测试异常: {e}")
  120. import traceback
  121. traceback.print_exc()
  122. return False
  123. def test_ad_list():
  124. """测试查询广告列表"""
  125. print("\n" + "=" * 70)
  126. print("【3/4】广告列表查询测试")
  127. print("=" * 70)
  128. try:
  129. # 构建请求
  130. params = _common_params()
  131. params["account_id"] = ACCOUNT_ID
  132. params["page"] = "1"
  133. params["page_size"] = "5"
  134. url = f"{BASE_URL}/adgroups/get?{urlencode(params)}"
  135. print(f"请求 URL: {BASE_URL}/adgroups/get")
  136. print(f"请求参数: account_id={ACCOUNT_ID}, page=1, page_size=5")
  137. # 发送请求
  138. resp = httpx.get(url, timeout=TIMEOUT)
  139. print(f"响应状态码: {resp.status_code}")
  140. if resp.status_code != 200:
  141. print(f"❌ HTTP 错误: {resp.status_code}")
  142. print(f"响应内容: {resp.text[:500]}")
  143. return False
  144. # 解析响应
  145. data = resp.json()
  146. # 检查 API 错误码
  147. code = data.get("code", -1)
  148. if code != 0:
  149. msg = data.get("message_cn") or data.get("message", "未知错误")
  150. print(f"❌ API 错误 (code={code}): {msg}")
  151. return False
  152. # 成功
  153. result_data = data.get("data", {})
  154. ads = result_data.get("list", [])
  155. page_info = result_data.get("page_info", {})
  156. print(f"\n✅ 测试通过")
  157. print(f"广告列表:")
  158. print(f" - 总数量: {page_info.get('total_number', len(ads))}")
  159. print(f" - 当前页: {len(ads)} 个广告")
  160. # 显示前几个广告
  161. for i, ad in enumerate(ads[:5], 1):
  162. print(f"\n [{i}] 广告 ID: {ad.get('adgroup_id')}")
  163. print(f" 名称: {ad.get('adgroup_name')}")
  164. print(f" 状态: {ad.get('configured_status')}")
  165. print(f" 出价: {ad.get('bid_amount', 0)/100:.2f} 元")
  166. print(f" 日预算: {ad.get('daily_budget', 0)/100:.0f} 元")
  167. # 统计状态分布
  168. if ads:
  169. statuses = {}
  170. for ad in ads:
  171. status = ad.get("configured_status", "UNKNOWN")
  172. statuses[status] = statuses.get(status, 0) + 1
  173. print(f"\n 状态分布: {statuses}")
  174. return True
  175. except httpx.RequestError as e:
  176. print(f"❌ 网络请求错误: {e}")
  177. return False
  178. except Exception as e:
  179. print(f"❌ 测试异常: {e}")
  180. import traceback
  181. traceback.print_exc()
  182. return False
  183. def test_report():
  184. """测试查询数据报表"""
  185. print("\n" + "=" * 70)
  186. print("【4/4】数据报表查询测试")
  187. print("=" * 70)
  188. try:
  189. from datetime import datetime, timedelta
  190. # 查询最近 7 天
  191. end_date = datetime.now()
  192. start_date = end_date - timedelta(days=6)
  193. date_range = {
  194. "start_date": start_date.strftime("%Y-%m-%d"),
  195. "end_date": end_date.strftime("%Y-%m-%d"),
  196. }
  197. # 构建请求
  198. params = _common_params()
  199. params["account_id"] = ACCOUNT_ID
  200. params["level"] = "ADGROUP"
  201. params["date_range"] = json.dumps(date_range)
  202. params["fields"] = json.dumps(["cost", "impression", "click", "ctr", "conversion"])
  203. params["page"] = "1"
  204. params["page_size"] = "5"
  205. url = f"{BASE_URL}/daily_reports/adgroups/get?{urlencode(params)}"
  206. print(f"请求 URL: {BASE_URL}/daily_reports/adgroups/get")
  207. print(f"日期范围: {date_range['start_date']} ~ {date_range['end_date']}")
  208. # 发送请求
  209. resp = httpx.get(url, timeout=TIMEOUT)
  210. print(f"响应状态码: {resp.status_code}")
  211. if resp.status_code != 200:
  212. print(f"❌ HTTP 错误: {resp.status_code}")
  213. print(f"响应内容: {resp.text[:500]}")
  214. return False
  215. # 解析响应
  216. data = resp.json()
  217. # 检查 API 错误码
  218. code = data.get("code", -1)
  219. if code != 0:
  220. msg = data.get("message_cn") or data.get("message", "未知错误")
  221. print(f"❌ API 错误 (code={code}): {msg}")
  222. return False
  223. # 成功
  224. result_data = data.get("data", {})
  225. reports = result_data.get("list", [])
  226. if not reports:
  227. print(f"\n⚠️ 该时间段内无数据")
  228. return True
  229. print(f"\n✅ 测试通过")
  230. print(f"数据报表:")
  231. print(f" - 记录数: {len(reports)}")
  232. # 显示前几条
  233. for i, report in enumerate(reports[:5], 1):
  234. cost = report.get("cost", 0)
  235. impression = report.get("impression", 0)
  236. click = report.get("click", 0)
  237. ctr = report.get("ctr", 0)
  238. conversion = report.get("conversion", 0)
  239. print(f"\n [{i}] 广告 ID: {report.get('adgroup_id', '-')}")
  240. if "date" in report:
  241. print(f" 日期: {report['date']}")
  242. print(f" 消耗: {cost/100:.2f} 元")
  243. print(f" 展示: {impression:,}")
  244. print(f" 点击: {click:,}")
  245. print(f" CTR: {ctr:.2%}")
  246. print(f" 转化: {conversion}")
  247. return True
  248. except httpx.RequestError as e:
  249. print(f"❌ 网络请求错误: {e}")
  250. return False
  251. except Exception as e:
  252. print(f"❌ 测试异常: {e}")
  253. import traceback
  254. traceback.print_exc()
  255. return False
  256. def main():
  257. """主测试流程"""
  258. print("\n" + "=" * 70)
  259. print("腾讯广告平台 API 接口测试 (简化版)")
  260. print("=" * 70)
  261. print()
  262. # 1. 检查环境变量
  263. if not check_env_vars():
  264. print("\n❌ 测试中止: 环境变量未配置")
  265. print("\n配置方法:")
  266. print("1. 在终端中设置环境变量:")
  267. print(" export TENCENT_AD_ACCESS_TOKEN='your_access_token'")
  268. print(" export TENCENT_AD_ACCOUNT_ID='your_account_id'")
  269. print("\n2. 或者创建 .env 文件:")
  270. print(" TENCENT_AD_ACCESS_TOKEN=your_access_token")
  271. print(" TENCENT_AD_ACCOUNT_ID=your_account_id")
  272. return
  273. # 2-4. 依次测试
  274. test1 = test_account_info()
  275. test2 = test_ad_list()
  276. test3 = test_report()
  277. # 总结
  278. print("\n" + "=" * 70)
  279. print("测试结果汇总")
  280. print("=" * 70)
  281. results = [
  282. ("环境变量检查", True),
  283. ("账户信息查询", test1),
  284. ("广告列表查询", test2),
  285. ("数据报表查询", test3),
  286. ]
  287. for test_name, passed in results:
  288. status = "✅ 通过" if passed else "❌ 失败"
  289. print(f"{status} {test_name}")
  290. all_passed = all([test1, test2, test3])
  291. if all_passed:
  292. print("\n🎉 所有测试通过! 腾讯广告平台接口可用")
  293. else:
  294. print("\n⚠️ 部分测试失败,请检查:")
  295. print(" 1. ACCESS_TOKEN 是否有效 (是否过期)")
  296. print(" 2. ACCOUNT_ID 是否正确")
  297. print(" 3. 网络连接是否正常")
  298. print(" 4. 账户权限是否充足")
  299. print(" 5. API 版本是否为 v3.0")
  300. if __name__ == "__main__":
  301. main()