jzyg123 commited on
Commit
4514b82
·
verified ·
1 Parent(s): ec809eb

Update src/script.py

Browse files
Files changed (1) hide show
  1. src/script.py +107 -27
src/script.py CHANGED
@@ -13,7 +13,7 @@ app = Flask(__name__)
13
  STUDENTS_DATA = []
14
  STUDENTS_FILE = "students.json"
15
  DOT_NOTIFY_URL = "https://dot.mindreset.tech/api/open/text"
16
- DOT_AUTH_TOKEN = os.environ.get("DOT_AUTH_TOKEN", "").strip()
17
  DOT_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAEj0lEQVR4nO2YXYhVVRTHf/fOTI2Og2apo6IDpZNFZkUfplRYPURRCX0oigZWlPQgEUlRhhVBUA+h9ZAWRBJFX2IPfuLLJGlFYkb6YGWNIPYxpKmYOjO3h/Vfs/c9c+49Z65jQcyCyz37Y/33f6+99lrrHBiU/7kUBgijmILVo99/JgWgLmNOMceczEVqkSLBOk3AlcBUoBnoBg4AO4EfUuafdXGLDAeWA38ApQq/zcDNml9gYFwqF7kZwH6R+AZYAkwHLsIsOQf4ICK6guCnZ41kUf83AieBY8DcDJ2pwOcYyTUEvx1wkr77FuBX7Fgvi8bqtXCRcDHqNX4usFYkn1XfGV2cNHHANVpoltrnZOg5yWHAPuBv4EL1FVM1ahAHmiByn6rdkFPfSd4n/VcS/WcsDdjxPqoFbiJfDHTxizEE+B34WeTSgnsfqWTmAsGvukXsWqAL2C29Uk6CJeGcAr4AWoGRhLhYR5WLk0awTqBdIue7n4BdkD/VX0k/Da9HOt8JuxUL8CX1uxEy8XxCM/AgsAn4Ddt9CQstq7FQExOoRg6gEZgH7CLExi6gA3gfuCMPnpObj/lKSf/rgVWE3ftvI9BWBdT77gR+ifROCW81duTe/xUW7PvgxQ7/qibvAm6n/KbO0dgi4EU9H8EuTRLUn5/UvD3AvUAnsDexkRbgmYjowiSePyzXhJWJxer1GwWcwCwKcAtwGDhKCNp1ke5jwntP7XvUXqY5jZT73OWE9HlrkuR1GnhXbb/FhcTElwlWBPPFbqxyiUPHFM3bpHljMOsdAUYTakhfy0+qTZs+iBUjvTd7mwCaCOkqFgdsAr4Xqbs0tkxk5kYbWYf52jDgPIKvPZC0TCSelR7W3KU+cCnB9FA5wjvpydjtKwFPAedjuXm7xkcSMsbVWE1YAl6oQg6CERqAQ8CPPvdxAVxCuemrkWwF2qV3ELP+aeAG4Gn1/6T/k8AjGeRc3DirpHsxwDtYEh8a7aSaxL6zEKsHT2PBOI5xncAbWI0Y62UR9LTag0USPsaOKF44S5KLPSfAJ4CPRHhsNJ43b7sF52EbnV3EUtdw7ALklR5sI42U3/jXgS3RQl4XdqdgVJICFtIAjhWBrwXSRrYPxuJZwSucLj0f0PhV9P9FyV3kerX3AUwkvDdA/jrNw9E4Ed2s/gvU/qSfeG6cZuAvzLd73W0tdtvG9wPU49ab2AZvi8beUt+0GvCel+6CmHkbdkTthKjeQHrAjt837hfYBrW9rhuPWWEvMCKBF19Cx/M1ZxHeFD0z9d6whwjvsi0JYmnV7yJCvBtLOCLH89y7EwvuWXizsVPsRPGPyEAOuligR7FKZGICZChWJKwnVCmTkmAR3gKC47+E5eiYWCMwE/hQczqwyj2JVwY6A9gRAXcAX2L14PGo/zUsPKWCRXhXYKHH9Q5htd+3mBt4/9tYURHr9jGzv4OApa27taMxWLbZD2wFPsOKUCdXKZzEeNdgBcZ0rKLxbzjtWHGR+ztO3jiY9wtBrre3SnjVFF3Bc2y8WC3f/hzPj9TXrxVvUAblX5F/AN1tJCuIaUiQAAAAAElFTkSuQmCC"
18
 
19
  def load_students_data():
@@ -38,10 +38,13 @@ class DingTalkFormQueryClient:
38
 
39
  # 字段映射表
40
  self.field_mapping = {
41
- 'radioField_ts1jbr0': '姓名',
 
 
42
  'textField_lqrf9fj': '学号',
43
  'textField_sm64ysf': '考试名称',
44
- 'radioField_8a4voiy': '身份证号',
 
45
 
46
  # 语文
47
  'textField_4ecclpd': '语文',
@@ -84,6 +87,11 @@ class DingTalkFormQueryClient:
84
  'textField_y4uc1lx': '组合排名',
85
  'textField_a2l7vuc': '大类排名',
86
  }
 
 
 
 
 
87
 
88
  def load_cookies_from_file(self):
89
  """从文件加载cookies"""
@@ -127,9 +135,11 @@ class DingTalkFormQueryClient:
127
  return False
128
  return True
129
 
130
- def build_request_url(self, id_number, csrf_token):
131
  """构建请求URL"""
132
- search_json = json.dumps({"radioField_8a4voiy": id_number})
 
 
133
 
134
  params = {
135
  'formUuid': self.form_uuid,
@@ -158,8 +168,6 @@ class DingTalkFormQueryClient:
158
  if not csrf_token:
159
  return {"success": False, "error": "无法提取CSRF令牌,请检查cookie中的tianshu_csrf_token"}
160
 
161
- # 构建请求
162
- url = self.build_request_url(id_number, csrf_token)
163
  headers = {
164
  'Accept': 'application/json, text/json',
165
  'Accept-Encoding': 'gzip, deflate, br, zstd',
@@ -169,22 +177,45 @@ class DingTalkFormQueryClient:
169
  'X-Requested-With': 'XMLHttpRequest'
170
  }
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  try:
173
- student_name = None
174
- for s in STUDENTS_DATA:
175
- if s.get('学号') == id_number:
176
- student_name = s.get('学生姓名')
177
- break
178
- print(f"🔍 正在查询: {student_name} {id_number}")
179
 
 
 
180
  response = requests.get(
181
- url,
182
- headers=headers,
183
  cookies=cookies,
184
  timeout=(10, 30)
185
  )
186
-
187
- # print(f"📡 HTTP状态码: {response.status_code}") # 控制台日志
188
 
189
  if response.status_code != 200:
190
  return {"success": False, "error": f"HTTP请求失败,状态码: {response.status_code}"}
@@ -194,9 +225,12 @@ class DingTalkFormQueryClient:
194
  print(f"📦 收到响应数据") # 控制台日志
195
  except json.JSONDecodeError as e:
196
  print(f"❌ JSON解析失败: {e}") # 控制台日志
197
- return {"success": False, "error": f"服务器返回的不是有效的JSON格式"}
198
 
199
- return self._parse_response(data)
 
 
 
200
 
201
  except requests.exceptions.Timeout:
202
  return {"success": False, "error": "请求超时,请检查网络连接"}
@@ -211,7 +245,7 @@ class DingTalkFormQueryClient:
211
  if not isinstance(data, dict):
212
  return {"success": False, "error": "服务器返回的数据格式错误:不是字典类型"}
213
 
214
- # print(f"📋 响应字段: {list(data.keys())}") # 控制台日志
215
 
216
  success = data.get('success')
217
  if success is False:
@@ -236,7 +270,7 @@ class DingTalkFormQueryClient:
236
  if len(records) == 0:
237
  return {"success": True, "data": [], "message": "未找到相关成绩记录"}
238
 
239
- # print(f"📊 找到 {len(records)} 条成绩记录") # 控制台日志
240
  processed_data = self.process_score_data(records)
241
  return {"success": True, "data": processed_data}
242
 
@@ -350,6 +384,48 @@ class DingTalkFormQueryClient:
350
  except Exception:
351
  return "计算错误"
352
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
353
  def send_dot_notification(self, title, message, signature, icon=None):
354
  """发送到 dot.mindreset.tech 的通知请求。"""
355
  try:
@@ -358,6 +434,8 @@ class DingTalkFormQueryClient:
358
  "Authorization": f"Bearer {DOT_AUTH_TOKEN}",
359
  "Content-Type": "application/json"
360
  }
 
 
361
 
362
  data = {
363
  "refreshNow": False,
@@ -366,7 +444,7 @@ class DingTalkFormQueryClient:
366
  "message": message,
367
  "signature": signature,
368
  "icon": icon or DOT_ICON,
369
- "link": "https://jzyg123-grade-query.hf.space"
370
  }
371
  resp = requests.post(url, json=data, headers=headers, timeout=10)
372
  try:
@@ -414,8 +492,8 @@ def search_student():
414
  return jsonify({"success": False, "message": "未找到匹配的学生"})
415
 
416
  # 添加调试信息
417
- # print(f"🔍 搜索姓名: {name}")
418
- # print(f"📋 找到 {len(matched_students)} 个匹配的学生")
419
 
420
  return jsonify({"success": True, "students": matched_students})
421
 
@@ -443,15 +521,17 @@ def query():
443
  else:
444
  result = client.query_scores(id_number)
445
 
 
446
  try:
 
447
  student_name = None
448
  for s in STUDENTS_DATA:
449
  if s.get('学号') == id_number:
450
  student_name = s.get('学生姓名')
451
  break
452
 
453
- if student_name == os.environ.get("NAME", "").strip() and result.get('success') and result.get('data'):
454
- print("✅ 准备发送通知...")
455
  trend = client.compute_rank_trend(result.get('data'))
456
  # 取最新考试名称
457
  latest_exam = result.get('data')[0].get('考试名称', '') if result.get('data') else ''
@@ -501,7 +581,7 @@ def main():
501
  print("3. 服务器日志会显示在此控制台")
502
  print("=" * 60)
503
 
504
- app.run(host='0.0.0.0', port=7860, debug=False)
505
 
506
  if __name__ == "__main__":
507
  main()
 
13
  STUDENTS_DATA = []
14
  STUDENTS_FILE = "students.json"
15
  DOT_NOTIFY_URL = "https://dot.mindreset.tech/api/open/text"
16
+ DOT_AUTH_TOKEN = "dot_app_XdfKhLlhOiyNWfSepKUytXlxwBfERNkiFZzYYkRrLOeXVjOIacBEjhqJDedXNKkw"
17
  DOT_ICON = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAEj0lEQVR4nO2YXYhVVRTHf/fOTI2Og2apo6IDpZNFZkUfplRYPURRCX0oigZWlPQgEUlRhhVBUA+h9ZAWRBJFX2IPfuLLJGlFYkb6YGWNIPYxpKmYOjO3h/Vfs/c9c+49Z65jQcyCyz37Y/33f6+99lrrHBiU/7kUBgijmILVo99/JgWgLmNOMceczEVqkSLBOk3AlcBUoBnoBg4AO4EfUuafdXGLDAeWA38ApQq/zcDNml9gYFwqF7kZwH6R+AZYAkwHLsIsOQf4ICK6guCnZ41kUf83AieBY8DcDJ2pwOcYyTUEvx1wkr77FuBX7Fgvi8bqtXCRcDHqNX4usFYkn1XfGV2cNHHANVpoltrnZOg5yWHAPuBv4EL1FVM1ahAHmiByn6rdkFPfSd4n/VcS/WcsDdjxPqoFbiJfDHTxizEE+B34WeTSgnsfqWTmAsGvukXsWqAL2C29Uk6CJeGcAr4AWoGRhLhYR5WLk0awTqBdIue7n4BdkD/VX0k/Da9HOt8JuxUL8CX1uxEy8XxCM/AgsAn4Ddt9CQstq7FQExOoRg6gEZgH7CLExi6gA3gfuCMPnpObj/lKSf/rgVWE3ftvI9BWBdT77gR+ifROCW81duTe/xUW7PvgxQ7/qibvAm6n/KbO0dgi4EU9H8EuTRLUn5/UvD3AvUAnsDexkRbgmYjowiSePyzXhJWJxer1GwWcwCwKcAtwGDhKCNp1ke5jwntP7XvUXqY5jZT73OWE9HlrkuR1GnhXbb/FhcTElwlWBPPFbqxyiUPHFM3bpHljMOsdAUYTakhfy0+qTZs+iBUjvTd7mwCaCOkqFgdsAr4Xqbs0tkxk5kYbWYf52jDgPIKvPZC0TCSelR7W3KU+cCnB9FA5wjvpydjtKwFPAedjuXm7xkcSMsbVWE1YAl6oQg6CERqAQ8CPPvdxAVxCuemrkWwF2qV3ELP+aeAG4Gn1/6T/k8AjGeRc3DirpHsxwDtYEh8a7aSaxL6zEKsHT2PBOI5xncAbWI0Y62UR9LTag0USPsaOKF44S5KLPSfAJ4CPRHhsNJ43b7sF52EbnV3EUtdw7ALklR5sI42U3/jXgS3RQl4XdqdgVJICFtIAjhWBrwXSRrYPxuJZwSucLj0f0PhV9P9FyV3kerX3AUwkvDdA/jrNw9E4Ed2s/gvU/qSfeG6cZuAvzLd73W0tdtvG9wPU49ab2AZvi8beUt+0GvCel+6CmHkbdkTthKjeQHrAjt837hfYBrW9rhuPWWEvMCKBF19Cx/M1ZxHeFD0z9d6whwjvsi0JYmnV7yJCvBtLOCLH89y7EwvuWXizsVPsRPGPyEAOuligR7FKZGICZChWJKwnVCmTkmAR3gKC47+E5eiYWCMwE/hQczqwyj2JVwY6A9gRAXcAX2L14PGo/zUsPKWCRXhXYKHH9Q5htd+3mBt4/9tYURHr9jGzv4OApa27taMxWLbZD2wFPsOKUCdXKZzEeNdgBcZ0rKLxbzjtWHGR+ztO3jiY9wtBrre3SnjVFF3Bc2y8WC3f/hzPj9TXrxVvUAblX5F/AN1tJCuIaUiQAAAAAElFTkSuQmCC"
18
 
19
  def load_students_data():
 
38
 
39
  # 字段映射表
40
  self.field_mapping = {
41
+ # 基本信息
42
+ 'textField_mhsv4lgl': '姓名', # 新版表单
43
+ 'radioField_ts1jbr0': '姓名', # 旧版表单
44
  'textField_lqrf9fj': '学号',
45
  'textField_sm64ysf': '考试名称',
46
+ 'textField_mhsv4lgk': '身份证号', # 新版表单
47
+ 'radioField_8a4voiy': '身份证号', # 旧版表单
48
 
49
  # 语文
50
  'textField_4ecclpd': '语文',
 
87
  'textField_y4uc1lx': '组合排名',
88
  'textField_a2l7vuc': '大类排名',
89
  }
90
+ # 查询身份证号时优先尝试的字段顺序(兼容新旧表单)
91
+ self.id_field_priority = [
92
+ 'textField_mhsv4lgk', # 新版
93
+ 'radioField_8a4voiy', # 旧版
94
+ ]
95
 
96
  def load_cookies_from_file(self):
97
  """从文件加载cookies"""
 
135
  return False
136
  return True
137
 
138
+ def build_request_url(self, id_number, csrf_token, search_field_id):
139
  """构建请求URL"""
140
+ if not search_field_id:
141
+ raise ValueError("search_field_id 不能为空")
142
+ search_json = json.dumps({search_field_id: id_number})
143
 
144
  params = {
145
  'formUuid': self.form_uuid,
 
168
  if not csrf_token:
169
  return {"success": False, "error": "无法提取CSRF令牌,请检查cookie中的tianshu_csrf_token"}
170
 
 
 
171
  headers = {
172
  'Accept': 'application/json, text/json',
173
  'Accept-Encoding': 'gzip, deflate, br, zstd',
 
177
  'X-Requested-With': 'XMLHttpRequest'
178
  }
179
 
180
+ last_success_empty = None
181
+ for search_field in self.id_field_priority:
182
+ result = self._perform_query(
183
+ id_number=id_number,
184
+ cookies=cookies,
185
+ csrf_token=csrf_token,
186
+ headers=headers,
187
+ search_field=search_field
188
+ )
189
+ if not result.get("success", False):
190
+ # 直接返回错误信息
191
+ return result
192
+ if result.get("data"):
193
+ if search_field != self.id_field_priority[0]:
194
+ print(f"ℹ️ 通过备用字段 {search_field} 匹配到成绩数据")
195
+ return result
196
+ last_success_empty = result
197
+
198
+ # 所有字段都无数据,返回最后一次成功但无记录的结果或通用提示
199
+ if last_success_empty:
200
+ return last_success_empty
201
+ return {"success": True, "data": [], "message": "未找到相关成绩记录"}
202
+
203
+ def _perform_query(self, id_number, cookies, csrf_token, headers, search_field):
204
+ """执行实际的HTTP查询,并统一处理异常"""
205
  try:
206
+ url = self.build_request_url(id_number, csrf_token, search_field)
207
+ except ValueError as e:
208
+ return {"success": False, "error": str(e)}
 
 
 
209
 
210
+ try:
211
+ print(f"🔍 正在使用字段 {search_field} 查询身份证号: {id_number}") # 控制台日志
212
  response = requests.get(
213
+ url,
214
+ headers=headers,
215
  cookies=cookies,
216
  timeout=(10, 30)
217
  )
218
+ print(f"📡 HTTP状态码: {response.status_code}") # 控制台日志
 
219
 
220
  if response.status_code != 200:
221
  return {"success": False, "error": f"HTTP请求失败,状态码: {response.status_code}"}
 
225
  print(f"📦 收到响应数据") # 控制台日志
226
  except json.JSONDecodeError as e:
227
  print(f"❌ JSON解析失败: {e}") # 控制台日志
228
+ return {"success": False, "error": "服务器返回的不是有效的JSON格式"}
229
 
230
+ parsed = self._parse_response(data)
231
+ if parsed.get("success") and not parsed.get("data"):
232
+ parsed.setdefault("message", "未找到相关成绩记录")
233
+ return parsed
234
 
235
  except requests.exceptions.Timeout:
236
  return {"success": False, "error": "请求超时,请检查网络连接"}
 
245
  if not isinstance(data, dict):
246
  return {"success": False, "error": "服务器返回的数据格式错误:不是字典类型"}
247
 
248
+ print(f"📋 响应字段: {list(data.keys())}") # 控制台日志
249
 
250
  success = data.get('success')
251
  if success is False:
 
270
  if len(records) == 0:
271
  return {"success": True, "data": [], "message": "未找到相关成绩记录"}
272
 
273
+ print(f"📊 找到 {len(records)} 条成绩记录") # 控制台日志
274
  processed_data = self.process_score_data(records)
275
  return {"success": True, "data": processed_data}
276
 
 
384
  except Exception:
385
  return "计算错误"
386
 
387
+ def _get_local_ip(self):
388
+ """获取本机局域网IP地址"""
389
+ try:
390
+ import subprocess
391
+ # 使用ifconfig获取所有IP地址
392
+ result = subprocess.run(['ifconfig'], capture_output=True, text=True)
393
+ if result.returncode == 0:
394
+ ips = []
395
+ lines = result.stdout.split('\n')
396
+ for line in lines:
397
+ if 'inet ' in line and '127.0.0.1' not in line and 'inet 169.254.' not in line:
398
+ parts = line.strip().split()
399
+ for i, part in enumerate(parts):
400
+ if part == 'inet' and i + 1 < len(parts):
401
+ ip = parts[i + 1]
402
+ ips.append(ip)
403
+
404
+ # 优先级:192.168.x.x > 10.x.x.x > 172.x.x.x > 其他
405
+ for ip in ips:
406
+ if ip.startswith('192.168.'):
407
+ return ip
408
+ for ip in ips:
409
+ if ip.startswith('10.'):
410
+ return ip
411
+ for ip in ips:
412
+ if ip.startswith('172.'):
413
+ return ip
414
+ if ips:
415
+ return ips[0]
416
+ except Exception:
417
+ # 备用方法
418
+ try:
419
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
420
+ s.connect(("8.8.8.8", 80))
421
+ local_ip = s.getsockname()[0]
422
+ s.close()
423
+ return local_ip
424
+ except Exception:
425
+ pass
426
+
427
+ return "127.0.0.1"
428
+
429
  def send_dot_notification(self, title, message, signature, icon=None):
430
  """发送到 dot.mindreset.tech 的通知请求。"""
431
  try:
 
434
  "Authorization": f"Bearer {DOT_AUTH_TOKEN}",
435
  "Content-Type": "application/json"
436
  }
437
+ # 获取本机局域网IP
438
+ local_ip = self._get_local_ip()
439
 
440
  data = {
441
  "refreshNow": False,
 
444
  "message": message,
445
  "signature": signature,
446
  "icon": icon or DOT_ICON,
447
+ "link": f"https://{local_ip}:1111"
448
  }
449
  resp = requests.post(url, json=data, headers=headers, timeout=10)
450
  try:
 
492
  return jsonify({"success": False, "message": "未找到匹配的学生"})
493
 
494
  # 添加调试信息
495
+ print(f"🔍 搜索姓名: {name}")
496
+ print(f"📋 找到 {len(matched_students)} 个匹配的学生")
497
 
498
  return jsonify({"success": True, "students": matched_students})
499
 
 
521
  else:
522
  result = client.query_scores(id_number)
523
 
524
+ # 如果返回成功且检测到周洋光,则计算趋势并发送通知
525
  try:
526
+ # 查询学生姓名是否为周洋光:在 students.json 中查找
527
  student_name = None
528
  for s in STUDENTS_DATA:
529
  if s.get('学号') == id_number:
530
  student_name = s.get('学生姓名')
531
  break
532
 
533
+ if student_name == '周洋光' and result.get('success') and result.get('data'):
534
+ print("✅ 检测到周洋光,准备发送通知...")
535
  trend = client.compute_rank_trend(result.get('data'))
536
  # 取最新考试名称
537
  latest_exam = result.get('data')[0].get('考试名称', '') if result.get('data') else ''
 
581
  print("3. 服务器日志会显示在此控制台")
582
  print("=" * 60)
583
 
584
+ app.run(host='0.0.0.0', port=1111, debug=True)
585
 
586
  if __name__ == "__main__":
587
  main()