#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 批量创建学生信息脚本 为每个班级创建30个学生的测试数据 """ import requests import json import random import time from datetime import datetime, timedelta import logging # 配置日志 logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class SimpleDataGenerator: """简单的数据生成器,替代faker""" def __init__(self): # 姓氏 self.surnames = ['李', '王', '张', '刘', '陈', '杨', '黄', '赵', '周', '吴', '徐', '孙', '朱', '马', '胡', '郭', '林', '何', '高', '梁'] # 男性名字 self.male_names = ['伟', '强', '磊', '军', '勇', '涛', '明', '超', '辉', '华', '建', '文', '健', '云', '峰', '浩', '鹏', '飞', '宇', '杰'] # 女性名字 self.female_names = ['丽', '娜', '敏', '静', '佳', '雅', '莉', '萍', '红', '梅', '芳', '燕', '玲', '霞', '琳', '晶', '欣', '宁', '蕾', '洁'] # 省份 self.provinces = ['北京市', '上海市', '天津市', '重庆市', '河北省', '山西省', '辽宁省', '吉林省', '黑龙江省', '江苏省', '浙江省', '安徽省', '福建省', '江西省', '山东省', '河南省', '湖北省', '湖南省', '广东省', '海南省', '四川省', '贵州省', '云南省', '陕西省', '甘肃省', '青海省', '台湾省', '内蒙古自治区', '广西壮族自治区', '西藏自治区', '宁夏回族自治区', '新疆维吾尔自治区'] def generate_name(self, gender): """生成姓名""" surname = random.choice(self.surnames) if gender == '0': # 男性 given_name = random.choice(self.male_names) else: # 女性 given_name = random.choice(self.female_names) # 有时候生成双字名 if random.random() < 0.3: if gender == '0': given_name += random.choice(self.male_names) else: given_name += random.choice(self.female_names) return surname + given_name def generate_phone(self): """生成手机号""" prefixes = ['130', '131', '132', '133', '134', '135', '136', '137', '138', '139', '150', '151', '152', '153', '155', '156', '157', '158', '159', '180', '181', '182', '183', '184', '185', '186', '187', '188', '189'] prefix = random.choice(prefixes) suffix = ''.join([str(random.randint(0, 9)) for _ in range(8)]) return prefix + suffix def generate_id_card(self, birth_date): """生成身份证号""" # 地区代码(简化版) area_codes = ['110101', '110102', '110105', '110106', '110107', '110108', '310101', '310104', '310105', '310106', '310107', '310109', '440101', '440103', '440104', '440105', '440106', '440111'] area_code = random.choice(area_codes) # 出生日期(YYYYMMDD格式) birth_str = birth_date.replace('-', '') # 顺序码(3位)+ 校验码(1位) sequence = str(random.randint(100, 999)) check_digit = str(random.randint(0, 9)) return area_code + birth_str + sequence + check_digit def generate_address(self): """生成地址""" province = random.choice(self.provinces) cities = ['市', '县'] city = f"某{random.choice(cities)}" district = f"某区某街道{random.randint(1, 999)}号" return province + city + district def generate_province(self): """生成省份""" return random.choice(self.provinces) class StudentBatchCreator: def __init__(self, base_url="http://localhost:8080", token=None): """ 初始化学生批量创建器 Args: base_url: 后端API基础URL token: 认证token """ self.base_url = base_url self.token = token self.session = requests.Session() self.data_gen = SimpleDataGenerator() # 设置请求头 if token: self.session.headers.update({ 'Authorization': f'Bearer {token}', 'Content-Type': 'application/json' }) def set_token(self, token): """设置认证token""" self.token = token self.session.headers.update({ 'Authorization': f'Bearer {token}' }) def get_class_list(self): """获取班级列表""" try: url = f"{self.base_url}/classMsg/classMsg/list" params = { 'pageNum': 1, 'pageSize': 1000 # 获取所有班级 } response = self.session.get(url, params=params) response.raise_for_status() data = response.json() if data.get('code') == 200: classes = data.get('rows', []) logger.info(f"获取到 {len(classes)} 个班级") return classes else: logger.error(f"获取班级列表失败: {data.get('msg')}") return [] except Exception as e: logger.error(f"获取班级列表异常: {str(e)}") return [] def generate_birth_date(self): """生成出生日期(18-22岁)""" today = datetime.now() min_age = 18 max_age = 22 # 计算出生年份范围 birth_year = today.year - random.randint(min_age, max_age) birth_month = random.randint(1, 12) birth_day = random.randint(1, 28) # 使用28避免月份天数问题 return f"{birth_year:04d}-{birth_month:02d}-{birth_day:02d}" def generate_student_data(self, class_info, student_index): """ 生成单个学生的测试数据 Args: class_info: 班级信息 student_index: 学生编号(1-30) Returns: dict: 学生数据 """ # 生成基础信息 gender = random.choice(['0', '1']) # 0-男,1-女 name = self.data_gen.generate_name(gender) # 生成学号:班级代码 + 学生编号 class_code = class_info.get('classCode', class_info.get('class_code', '')) if not class_code: # 如果没有班级代码,使用班级ID class_code = f"CLS{class_info.get('id', '')}" student_no = f"{class_code}{student_index:02d}" # 生成出生日期 birth_date = self.generate_birth_date() # 生成身份证号 id_card = self.data_gen.generate_id_card(birth_date) # 生成手机号 phone = self.data_gen.generate_phone() # 民族选择 nations = ['01', '02', '03', '04', '05'] # 汉族、蒙古族、回族、藏族、维吾尔族等 nationality = random.choice(nations) # 政治面貌选择 political_statuses = ['01', '02', '03', '13'] # 群众、团员、党员等 political_status = random.choice(political_statuses) # 构建学生数据 student_data = { # 基础信息 "studentNo": student_no, "idCard": id_card, "name": name, "gender": gender, "birthDate": birth_date, "nationality": nationality, "politicalStatus": political_status, "phone": phone, "email": f"{student_no}@student.edu.cn", # 学籍信息(从班级信息继承) "classId": class_info.get('id'), "className": class_info.get('className', class_info.get('class_name', '')), "majorId": class_info.get('majorId', class_info.get('major_id')), "majorName": class_info.get('majorName', class_info.get('major_name', '')), "collegeId": class_info.get('collegeId', class_info.get('college_id')), "collegeName": class_info.get('collegeName', class_info.get('college_name', '')), "grade": class_info.get('grade', ''), "enrollmentYear": class_info.get('enrollmentYear', class_info.get('enrollment_year')), "academicLevel": class_info.get('classType', class_info.get('class_type', 1)), "classTeacherId": class_info.get('classTeacherId', class_info.get('class_teacher_id')), "classTeacherName": class_info.get('classTeacherName', class_info.get('class_teacher_name', '')), "schoolSystem": class_info.get('schoolSystem', class_info.get('school_system', 3)), # 默认状态 "studentStatus": "1", # 在籍 "trainingType": "全日制", "admissionCategory": "统招", "householdRegisterType": "非农业", "educationLevel": "2", # 高中 "maritalStatus": "1", # 未婚 # 地址信息 "nativePlace": self.data_gen.generate_province(), "sourceRegion": self.data_gen.generate_province(), "homeAddress": self.data_gen.generate_address(), "currentAddress": "学校宿舍", # 家庭信息 "fatherName": self.data_gen.generate_name('0'), "fatherPhone": self.data_gen.generate_phone(), "motherName": self.data_gen.generate_name('1'), "motherPhone": self.data_gen.generate_phone(), # 健康信息 "height": random.randint(155, 185), "weight": random.randint(45, 80), "bloodType": random.choice(['A', 'B', 'AB', 'O']), "healthStatus": "良好", # 布尔字段 "isBoarder": 1, # 住校 "isPoorStudent": random.randint(0, 1), "isMinority": 1 if nationality != '01' else 0, # 非汉族为少数民族 "isDisabled": 0, "isOrphan": 0, "isLeftBehindChild": 0, "isSingleChild": random.randint(0, 1), "isLowIncome": 0, "hasLoan": random.randint(0, 1), # 其他字段 "remark": f"批量生成的测试学生数据 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}" } return student_data def create_student(self, student_data): """ 创建单个学生 Args: student_data: 学生数据 Returns: tuple: (success, result) """ try: url = f"{self.base_url}/studentMsg/studentMsg" response = self.session.post(url, json=student_data) response.raise_for_status() result = response.json() if result.get('code') == 200: logger.info(f"成功创建学生: {student_data['name']} ({student_data['studentNo']})") return True, result else: logger.error(f"创建学生失败: {student_data['name']} - {result.get('msg')}") return False, result except Exception as e: logger.error(f"创建学生异常: {student_data['name']} - {str(e)}") return False, str(e) def batch_create_students_for_class(self, class_info, student_count=30): """ 为指定班级批量创建学生 Args: class_info: 班级信息 student_count: 要创建的学生数量 Returns: dict: 创建结果统计 """ class_name = class_info.get('className', class_info.get('class_name', f"班级{class_info.get('id')}")) logger.info(f"开始为班级 [{class_name}] 创建 {student_count} 个学生...") success_count = 0 failed_count = 0 failed_students = [] for i in range(1, student_count + 1): try: # 生成学生数据 student_data = self.generate_student_data(class_info, i) # 创建学生 success, result = self.create_student(student_data) if success: success_count += 1 else: failed_count += 1 failed_students.append({ 'student_no': student_data['studentNo'], 'name': student_data['name'], 'error': result }) # 添加短暂延迟,避免请求过于频繁 time.sleep(0.1) except Exception as e: failed_count += 1 logger.error(f"处理第 {i} 个学生时发生异常: {str(e)}") failed_students.append({ 'student_no': f"未知_{i}", 'name': '未知', 'error': str(e) }) result = { 'class_name': class_name, 'total': student_count, 'success': success_count, 'failed': failed_count, 'failed_students': failed_students } logger.info(f"班级 [{class_name}] 学生创建完成: 成功 {success_count},失败 {failed_count}") return result def batch_create_students_for_all_classes(self, student_count_per_class=30): """ 为所有班级批量创建学生 Args: student_count_per_class: 每个班级创建的学生数量 Returns: list: 所有班级的创建结果 """ # 获取班级列表 classes = self.get_class_list() if not classes: logger.error("没有获取到班级信息,无法创建学生") return [] logger.info(f"开始为 {len(classes)} 个班级批量创建学生,每个班级 {student_count_per_class} 个学生") all_results = [] total_success = 0 total_failed = 0 for class_info in classes: try: result = self.batch_create_students_for_class(class_info, student_count_per_class) all_results.append(result) total_success += result['success'] total_failed += result['failed'] # 班级间添加延迟 time.sleep(0.5) except Exception as e: logger.error(f"处理班级 {class_info} 时发生异常: {str(e)}") all_results.append({ 'class_name': f"班级{class_info.get('id', '未知')}", 'total': student_count_per_class, 'success': 0, 'failed': student_count_per_class, 'error': str(e) }) total_failed += student_count_per_class # 输出总结 logger.info("="*50) logger.info("批量创建学生完成!") logger.info(f"总班级数: {len(classes)}") logger.info(f"总学生数: {len(classes) * student_count_per_class}") logger.info(f"成功创建: {total_success}") logger.info(f"创建失败: {total_failed}") logger.info("="*50) return all_results def main(): """主函数""" print("学生批量创建工具") print("="*50) # 配置参数 base_url = input("请输入后端API地址 (默认: http://localhost:8080): ").strip() if not base_url: base_url = "http://localhost:8080" token = input("请输入认证Token (可为空): ").strip() student_count = input("请输入每个班级创建的学生数量 (默认: 30): ").strip() if not student_count: student_count = 30 else: try: student_count = int(student_count) except ValueError: print("输入的学生数量无效,使用默认值 30") student_count = 30 # 创建批量创建器 creator = StudentBatchCreator(base_url, token) # 确认操作 print(f"\n配置信息:") print(f"API地址: {base_url}") print(f"每个班级学生数: {student_count}") confirm = input("\n确认开始批量创建学生?(y/N): ").strip().lower() if confirm not in ['y', 'yes']: print("操作已取消") return # 开始批量创建 start_time = time.time() results = creator.batch_create_students_for_all_classes(student_count) end_time = time.time() # 保存结果到文件 timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') result_file = f"student_creation_result_{timestamp}.json" with open(result_file, 'w', encoding='utf-8') as f: json.dump(results, f, ensure_ascii=False, indent=2) print(f"\n创建结果已保存到: {result_file}") print(f"总耗时: {end_time - start_time:.2f} 秒") if __name__ == "__main__": main()