test_jw_cx_api.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. 教务同步只读 API 联调脚本(Python 3.7+,仅标准库)
  5. 调用两个业务接口并打印成功结果:
  6. - GET /api/v1/students 学生基本信息(第 1 页)
  7. - GET /api/v1/student-changes 学生异动(按年)
  8. 用法:
  9. python test_jw_cx_api.py --prod
  10. python test_jw_cx_api.py --base-url http://web.hzdyjsxy.cn:18081/jw-cx-api --year 2026
  11. 环境变量:JW_CX_BASE_URL、JW_CX_API_KEY
  12. """
  13. from __future__ import print_function
  14. import argparse
  15. import json
  16. import os
  17. import sys
  18. import time
  19. import urllib.error
  20. import urllib.parse
  21. import urllib.request
  22. HEADER_API_KEY = "X-Jw-Cx-Key"
  23. DEFAULT_BASE_URL = "http://127.0.0.1:5050"
  24. PROD_BASE_URL = "http://web.hzdyjsxy.cn:18081"
  25. DEFAULT_API_KEY = "JWCX001"
  26. def _get_json(url, api_key, timeout=120):
  27. req = urllib.request.Request(url, method="GET")
  28. req.add_header(HEADER_API_KEY, api_key)
  29. with urllib.request.urlopen(req, timeout=timeout) as resp:
  30. body = resp.read().decode("utf-8")
  31. return resp.status, json.loads(body)
  32. def _join_url(base, path):
  33. return base.rstrip("/") + "/" + path.lstrip("/")
  34. def fetch_students(base_url, api_key, page=1, page_size=10):
  35. qs = urllib.parse.urlencode({"page": page, "page_size": page_size})
  36. url = _join_url(base_url, "/api/v1/students?" + qs)
  37. status, data = _get_json(url, api_key)
  38. if status != 200 or data.get("code") != 200:
  39. raise RuntimeError("学生基本信息接口失败: status=%s body=%s" % (status, data))
  40. return data
  41. def fetch_student_changes(base_url, api_key, year):
  42. qs = urllib.parse.urlencode({"year": year})
  43. url = _join_url(base_url, "/api/v1/student-changes?" + qs)
  44. status, data = _get_json(url, api_key)
  45. if status != 200 or data.get("code") != 200:
  46. raise RuntimeError("学生异动接口失败: status=%s body=%s" % (status, data))
  47. return data
  48. def main():
  49. parser = argparse.ArgumentParser(description="教务同步 API:获取学生信息与学生异动")
  50. parser.add_argument("--base-url", default=None, help="API 根地址")
  51. parser.add_argument("--prod", action="store_true", help="使用 %s" % PROD_BASE_URL)
  52. parser.add_argument(
  53. "--api-key",
  54. default=os.environ.get("JW_CX_API_KEY", DEFAULT_API_KEY),
  55. help="请求头 %s" % HEADER_API_KEY,
  56. )
  57. parser.add_argument(
  58. "--year",
  59. type=int,
  60. default=None,
  61. help="异动筛选年份,默认当前自然年",
  62. )
  63. parser.add_argument(
  64. "--page-size",
  65. type=int,
  66. default=10,
  67. help="学生基本信息每页条数,默认 10",
  68. )
  69. args = parser.parse_args()
  70. if args.base_url:
  71. base_url = args.base_url
  72. elif args.prod:
  73. base_url = PROD_BASE_URL
  74. else:
  75. base_url = os.environ.get("JW_CX_BASE_URL", DEFAULT_BASE_URL)
  76. year = args.year if args.year is not None else time.localtime().tm_year
  77. print("BASE_URL: %s" % base_url)
  78. print("")
  79. try:
  80. students = fetch_students(base_url, args.api_key, page=1, page_size=args.page_size)
  81. print("=== 学生基本信息 GET /api/v1/students ===")
  82. print(
  83. "total=%s page=%s/%s 本页=%s条"
  84. % (
  85. students.get("total"),
  86. students.get("page"),
  87. students.get("total_pages"),
  88. len(students.get("data") or []),
  89. )
  90. )
  91. if students.get("data"):
  92. print("首条:", json.dumps(students["data"][0], ensure_ascii=False, indent=2))
  93. print("")
  94. changes = fetch_student_changes(base_url, args.api_key, year)
  95. print("=== 学生异动 GET /api/v1/student-changes?year=%s ===" % year)
  96. print("total=%s filter_year=%s" % (changes.get("total"), changes.get("filter_year")))
  97. if changes.get("data"):
  98. print("首条:", json.dumps(changes["data"][0], ensure_ascii=False, indent=2))
  99. elif changes.get("total") == 0:
  100. print("(当年无异动记录)")
  101. except (urllib.error.URLError, urllib.error.HTTPError, RuntimeError, ValueError) as e:
  102. print("调用失败: %s" % e, file=sys.stderr)
  103. sys.exit(1)
  104. print("")
  105. print("调用成功")
  106. sys.exit(0)
  107. if __name__ == "__main__":
  108. main()