{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "07a56b94",
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "import requests\n",
    "from queue import Queue\n",
    "from time import time,sleep\n",
    "import os\n",
    "\n",
    "# 配置信息\n",
    "ip = \"http://localhost:8080\"\n",
    "resource_paths = [\n",
    "    \"/static/index.2da1efab.css\",\n",
    "    \"/static/js/chunk-vendors.js\",\n",
    "    \"/static/js/index.js\",\n",
    "    \"/static/js/pages-login-index.js\"\n",
    "]\n",
    "\n",
    "# 创建下载结果队列\n",
    "download_results = Queue()\n",
    "\n",
    "def download_resource(path, thread_name):\n",
    "    \"\"\"下载单个资源的线程函数\"\"\"\n",
    "    try:\n",
    "        url = ip + path\n",
    "        start_time = time()\n",
    "        response = requests.get(url)\n",
    "        \n",
    "        # 模拟浏览器行为：检查状态码和内容类型\n",
    "        if response.status_code != 200:\n",
    "            result = f\"线程 {thread_name}: {path} 下载失败, 状态码 {response.status_code}\"\n",
    "        else:\n",
    "            # 简略显示内容（实际应用中应保存文件）\n",
    "            content_preview = response.text[:50].replace('\\n', ' ') + \"...\" if len(response.text) > 50 else response.text\n",
    "            \n",
    "            # 模拟浏览器解析CSS/JS的时间延迟\n",
    "            process_time = 0.1 if any(ext in path for ext in ['.css', '.js']) else 0.0\n",
    "            \n",
    "            result = (\n",
    "                f\"线程 {thread_name}: 成功下载 {path}\\n\"\n",
    "                f\"类型: {'CSS' if '.css' in path else 'JS' if '.js' in path else '其他'}\\n\"\n",
    "                f\"大小: {len(response.text)/1024:.1f} KB\\n\"\n",
    "                f\"耗时: {time()-start_time:.3f}秒\\n\"\n",
    "                f\"内容预览: {content_preview}\"\n",
    "            )\n",
    "        \n",
    "        # 添加处理延迟，模拟浏览器执行\n",
    "        sleep(process_time)\n",
    "        \n",
    "    except Exception as e:\n",
    "        result = f\"线程 {thread_name}: {path} 下载异常 - {str(e)}\"\n",
    "    \n",
    "    download_results.put(result)\n",
    "\n",
    "def simulate_browser_download(max_workers=6):\n",
    "    \"\"\"模拟浏览器并发下载行为\"\"\"\n",
    "    print(f\"模拟浏览器行为 - 并发下载线程数: {max_workers}\")\n",
    "    print(\"=\" * 60)\n",
    "    \n",
    "    threads = []\n",
    "    for i, path in enumerate(resource_paths):\n",
    "        # 使用线程名标识资源类型\n",
    "        thread_name = f\"资源#{i+1}\"\n",
    "        \n",
    "        # 创建并启动线程\n",
    "        t = threading.Thread(\n",
    "            target=download_resource,\n",
    "            args=(path, thread_name),\n",
    "            name=thread_name\n",
    "        )\n",
    "        t.start()\n",
    "        threads.append(t)\n",
    "        \n",
    "        # 控制最大并发数，模拟浏览器的连接限制\n",
    "        if len(threads) >= max_workers:\n",
    "            for t in threads:\n",
    "                t.join()\n",
    "            threads = []\n",
    "    \n",
    "    # 等待剩余的线程完成\n",
    "    for t in threads:\n",
    "        t.join()\n",
    "    \n",
    "    # 打印结果\n",
    "        while not download_results.empty():\n",
    "            print(download_results.get())\n",
    "            print(\"-\" * 60)\n",
    "\n",
    "    print(\"完成\")\n",
    "if __name__ == \"__main__\":\n",
    "    print(\"浏览器静态资源请求模拟器\")\n",
    "    print(\"=\" * 60)\n",
    "    simulate_browser_download()\n",
    "    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "73d41e7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from faker import Faker\n",
    "import random\n",
    "import json\n",
    "from datetime import datetime\n",
    "\n",
    "# 初始化Faker生成器（简体中文）\n",
    "fake = Faker('zh_CN')\n",
    "\n",
    "# 定义固定值\n",
    "TEAM_ID = 106\n",
    "PLAN_ID = 131\n",
    "\n",
    "# 常见民族列表\n",
    "ETHNIC_GROUPS = [\"汉\", \"壮\", \"满\", \"回\", \"苗\", \"维吾尔\", \"土家\", \"彝\", \"蒙古\", \"藏\", \"布依\", \n",
    "                \"侗\", \"瑶\", \"朝鲜\", \"白\", \"哈尼\", \"哈萨克\", \"黎\", \"傣\", \"畲\", \"傈僳\", \"仡佬\",\n",
    "                \"东乡\", \"高山\", \"拉祜\", \"水\", \"佤\", \"纳西\", \"羌\", \"土\", \"仫佬\", \"锡伯\", \"柯尔克孜\",\n",
    "                \"达斡尔\", \"景颇\", \"毛南\", \"撒拉\", \"布朗\", \"塔吉克\", \"阿昌\", \"普米\", \"鄂温克\", \"怒\",\n",
    "                \"京\", \"基诺\", \"德昂\", \"保安\", \"俄罗斯\", \"裕固\", \"乌兹别克\", \"门巴\", \"鄂伦春\", \"独龙\",\n",
    "                \"塔塔尔\", \"赫哲\", \"珞巴\"]\n",
    "\n",
    "# 疾病列表（健康状态）\n",
    "HEALTH_CONDITIONS = [\n",
    "    \"无\", \"近视\", \"弱视\", \"鼻炎\", \"哮喘\", \"过敏体质\", \"蛀牙\", \n",
    "    \"肥胖\", \"发育迟缓\", \"ADHD\", \"缺铁性贫血\", \"维生素缺乏\",\n",
    "    \"易感冒体质\", \"偏瘦\", \"过敏(花粉)\", \"过敏(尘螨)\", \"过敏(牛奶)\", \n",
    "    \"消化不良\", \"多动症\", \"抽动症\", \"癫痫\", \"小儿麻痹\", \"乙肝病毒携带\"\n",
    "]\n",
    "\n",
    "# 艺术特长\n",
    "ART_TALENTS = [\"无\", \"钢琴\", \"小提琴\", \"绘画\", \"书法\", \"舞蹈\", \"声乐\", \"戏剧表演\", \n",
    "             \"摄影\", \"编程\", \"动画制作\", \"模型制作\", \"手工艺术\"]\n",
    "\n",
    "# 体育特长\n",
    "SPORTS_TALENTS = [\"无\", \"游泳\", \"篮球\", \"足球\", \"乒乓球\", \"羽毛球\", \"田径\", \n",
    "                \"武术\", \"跆拳道\", \"空手道\", \"轮滑\", \"滑板\", \"自行车\", \"健美操\"]\n",
    "\n",
    "# 科技特长\n",
    "TECH_TALENTS = [\"无\", \"机器人编程\", \"电子制作\", \"3D打印\", \"人工智能\", \"网页设计\", \n",
    "              \"科学实验\", \"天文观测\", \"植物培养\", \"动物观察\", \"航模制作\"]\n",
    "\n",
    "# 职业列表\n",
    "OCCUPATIONS = [\"医生\", \"教师\", \"工程师\", \"程序员\", \"设计师\", \"建筑师\", \"销售经理\",\n",
    "              \"会计\", \"律师\", \"公务员\", \"记者\", \"警察\", \"消防员\", \"厨师\", \"商人\",\n",
    "              \"自由职业\", \"个体经营者\", \"银行职员\", \"人力资源\", \"市场营销\"]\n",
    "\n",
    "# 公司类型\n",
    "WORKPLACES = [\n",
    "    \"国有企业\", \"民营企业\", \"外资企业\", \"合资企业\", \"政府机关\", \n",
    "    \"事业单位\", \"学校\", \"医院\", \"设计事务所\", \"律师事务所\",\n",
    "    \"科技公司\", \"互联网公司\", \"金融机构\", \"建筑公司\", \"零售企业\"\n",
    "]\n",
    "\n",
    "# 小学名称\n",
    "PRIMARY_SCHOOLS = [\n",
    "    \"第一实验小学\", \"第二实验小学\", \"育才小学\", \"阳光小学\", \"希望小学\", \"和平小学\", \n",
    "    \"实验小学分校\", \"新世纪小学\", \"东方小学\", \"先锋小学\", \"星光小学\", \"明德小学\"\n",
    "]\n",
    "\n",
    "def generate_id_num(birthday):\n",
    "    \"\"\"生成符合规则的身份证号\"\"\"\n",
    "    # 生成前6位（地区码，使用真实的地区码）\n",
    "    region_codes = [\"110101\", \"110105\", \"110106\", \"110107\", \"310112\", \"330102\", \"440106\", \"440304\"]\n",
    "    \n",
    "    # 出生日期码（8位）\n",
    "    birth_code = birthday.replace(\"-\", \"\")\n",
    "    \n",
    "    # 顺序码（3位）\n",
    "    sequence_code = str(random.randint(101, 998))\n",
    "    \n",
    "    # 生成校验码（1位）\n",
    "    base = region_codes[random.randint(0, len(region_codes)-1)] + birth_code + sequence_code\n",
    "    weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]\n",
    "    checksum_map = {0: '1', 1: '0', 2: 'X', 3: '9', 4: '8', 5: '7', 6: '6', 7: '5', 8: '4', 9: '3', 10: '2'}\n",
    "    \n",
    "    total = 0\n",
    "    for i in range(17):\n",
    "        total += int(base[i]) * weight[i]\n",
    "    checksum = checksum_map[total % 11]\n",
    "    \n",
    "    return base + checksum\n",
    "\n",
    "def generate_student_data():\n",
    "    \"\"\"生成单个学生数据\"\"\"\n",
    "    # 基础信息\n",
    "    sex = random.choice([\"男\", \"女\"])\n",
    "    \n",
    "    # 生日 (2010-2015年出生)\n",
    "    birthday = fake.date_between(start_date=\"-15y\", end_date=\"-8y\").strftime(\"%Y-%m-%d\")\n",
    "    \n",
    "    # 生成符合规则的身份证号\n",
    "    id_num = generate_id_num(birthday)\n",
    "    \n",
    "    # 计算年龄（仅用于展示）\n",
    "    birth_year = int(birthday[:4])\n",
    "    current_year = datetime.now().year\n",
    "    age = current_year - birth_year\n",
    "    \n",
    "    # 生成学生信息\n",
    "    data = {\n",
    "        \"teamId\": TEAM_ID,\n",
    "        \"stuName\": fake.name(),  # 学生姓名\n",
    "        \"idNum\": id_num,  # 身份证号\n",
    "        \"formerName\": random.choices([\"无\", fake.last_name() + fake.first_name()], weights=[0.8, 0.2])[0],  # 曾用名\n",
    "        \"sex\": sex,  # 性别\n",
    "        \"nation\": random.choice(ETHNIC_GROUPS),  # 民族\n",
    "        \"birthday\": birthday,  # 生日\n",
    "        \"finishSchool\": random.choice(PRIMARY_SCHOOLS),  # 毕业学校\n",
    "        \"file\": None,  # 文件\n",
    "        \"hkadr\": fake.province() + \"/\" + fake.city() + \"/\" + fake.district(),  # 户口所在地\n",
    "        \"homeAddress\": fake.address(),  # 家庭住址\n",
    "        \"health\": random.choice(HEALTH_CONDITIONS),  # 健康状况\n",
    "        \"artisticSpecialty\": random.choice(ART_TALENTS),  # 艺术特长\n",
    "        \"artisticAchievements\": \"无\",  # 艺术成就\n",
    "        \"technologicalSpecialty\": random.choice(TECH_TALENTS),  # 科技特长\n",
    "        \"technologicalAchievements\": \"无\",  # 科技成就\n",
    "        \"sportsSpecialty\": random.choice(SPORTS_TALENTS),  # 体育特长\n",
    "        \"sportsAchievements\": \"无\",  # 体育成就\n",
    "        \"planId\": PLAN_ID,  # 计划ID\n",
    "        \"imageUrl\": \"\",  # 图片URL\n",
    "        \"schoolCode\": \"G\" + id_num[:-1],  # 学籍号\n",
    "        \"age\": age,  # 年龄（仅用于展示）\n",
    "        \"email\": fake.email() if random.random() > 0.7 else \"\",  # 邮箱\n",
    "        \"height\": str(random.randint(130, 170)),  # 身高\n",
    "        \"weight\": str(random.randint(25, 60)),  # 体重\n",
    "        \"measurements\": f\"{random.randint(60, 90)},{random.randint(60, 90)},{random.randint(60, 90)}\"  # 三围\n",
    "    }\n",
    "    \n",
    "    # 生成监护人信息\n",
    "    guardian_prefix = fake.last_name()\n",
    "    \n",
    "    # 监护人1 - 通常为父母之一\n",
    "    relationship_choices = [\"父亲\", \"母亲\", \"爷爷\", \"奶奶\", \"外公\", \"外婆\"]\n",
    "    relationship = random.choice(relationship_choices[:2])  # 主要选择父母\n",
    "    \n",
    "    data.update({\n",
    "        \"guardian1Name\": guardian_prefix + (\"先生\" if relationship == \"父亲\" else \"女士\"),  # 监护人1姓名\n",
    "        \"guardian1Relationship\": relationship,  # 关系\n",
    "        \"guardian1IdCardNumber\": generate_id_num(fake.date_between(start_date=\"-55y\", end_date=\"-25y\").strftime(\"%Y-%m-%d\")),  # 身份证号\n",
    "        \"guardian1Contact\": fake.phone_number(),  # 联系方式\n",
    "        \"guardian1Occupation\": random.choice(OCCUPATIONS),  # 职业\n",
    "        \"guardian1Workplace\": random.choice(WORKPLACES)  # 工作单位\n",
    "    })\n",
    "    \n",
    "    # 监护人2 - 可能是另一位家长或其他人\n",
    "    if relationship == \"父亲\":\n",
    "        guardian2_relationship = \"母亲\"\n",
    "    else:\n",
    "        guardian2_relationship = random.choices(\n",
    "            [\"父亲\", \"爷爷\", \"奶奶\", \"外公\", \"外婆\", \"其他亲属\"], \n",
    "            weights=[0.7, 0.1, 0.1, 0.05, 0.05, 0.1]\n",
    "        )[0]\n",
    "    \n",
    "    data.update({\n",
    "        \"guardian2Name\": guardian_prefix + (\n",
    "            \"先生\" if guardian2_relationship in [\"父亲\", \"爷爷\", \"外公\"] else \"女士\"\n",
    "        ),  # 监护人2姓名\n",
    "        \"guardian2Relationship\": guardian2_relationship,  # 关系\n",
    "        \"guardian2IdCardNumber\": generate_id_num(fake.date_between(start_date=\"-55y\", end_date=\"-25y\").strftime(\"%Y-%m-%d\")),  # 身份证号\n",
    "        \"guardian2Contact\": fake.phone_number() if guardian2_relationship != \"无\" else \"\",  # 联系方式\n",
    "        \"guardian2Occupation\": random.choice(OCCUPATIONS) if guardian2_relationship != \"无\" else \"\",  # 职业\n",
    "        \"guardian2Workplace\": random.choice(WORKPLACES) if guardian2_relationship != \"无\" else \"\"  # 工作单位\n",
    "    })\n",
    "    \n",
    "    return data\n",
    "\n",
    "def generate_students():\n",
    "    student = generate_student_data()\n",
    "    return student"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "018a3c24",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "🎬 开始模拟 10 个用户并发访问...\n",
      "======================================================================\n",
      "👤 用户 1 开始会话, Session ID: 679e3877-56ac-4791-a1e5-880468dc1d87\n",
      "👤 用户 2 开始会话, Session ID: 96acf953-61d0-4499-900e-482f75112453\n",
      "👤 用户 3 开始会话, Session ID: 588c0b3d-05ec-438e-a327-bc51fbc3927a\n",
      "👤 用户 4 开始会话, Session ID: 52eb7ae8-d1b7-48ae-a0f2-8b1bd384d5b8\n",
      "👤 用户 5 开始会话, Session ID: 42561435-6a9c-4eac-8282-ce4dd7d11547\n",
      "👤 用户 6 开始会话, Session ID: ee1daae1-584b-409c-affe-d14ad170d309\n",
      "👤 用户 7 开始会话, Session ID: 43901a21-0c91-45a5-9c98-b6fddd2dcb50\n",
      "👤 用户 8 开始会话, Session ID: e8ad6873-751f-4f81-8409-cf1c34ee50ee\n",
      "👤 用户 9 开始会话, Session ID: ae1d258d-545e-4c45-8b81-d9a8ba3d94e8\n",
      "👤 用户 10 开始会话, Session ID: fed2a8aa-a697-4e4b-b433-11a9edbe1640\n",
      "✅ 用户 5 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.032秒\n",
      "✅ 用户 2 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.040秒\n",
      "✅ 用户 4 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.040秒\n",
      "✅ 用户 2 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.057秒\n",
      "✅ 用户 9 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.038秒\n",
      "✅ 用户 4 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.044秒\n",
      "✅ 用户 6 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.034秒\n",
      "✅ 用户 1 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.036秒\n",
      "✅ 用户 9 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.029秒\n",
      "✅ 用户 10 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.037秒\n",
      "✅ 用户 1 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.033秒\n",
      "✅ 用户 6 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.040秒\n",
      "✅ 用户 4 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.040秒\n",
      "✅ 用户 10 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.040秒\n",
      "✅ 用户 8 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.051秒\n",
      "✅ 用户 8 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.032秒\n",
      "✅ 用户 2 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.038秒\n",
      "✅ 用户 10 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.077秒\n",
      "✅ 用户 7 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.053秒\n",
      "✅ 用户 10 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.047秒\n",
      "📊 用户 10 加载所有静态资源耗时: 2.305秒\n",
      "🚀 用户 10 开始看表单\n",
      "✅ 用户 5 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.066秒\n",
      "✅ 用户 6 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.046秒\n",
      "✅ 用户 4 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.069秒\n",
      "📊 用户 4 加载所有静态资源耗时: 2.348秒\n",
      "🚀 用户 4 开始看表单\n",
      "✅ 用户 7 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.055秒\n",
      "✅ 用户 7 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.055秒\n",
      "✅ 用户 6 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.069秒\n",
      "📊 用户 6 加载所有静态资源耗时: 2.391秒\n",
      "🚀 用户 6 开始看表单\n",
      "✅ 用户 3 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.043秒\n",
      "✅ 用户 9 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.057秒\n",
      "✅ 用户 1 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.055秒\n",
      "✅ 用户 8 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.057秒\n",
      "✅ 用户 3 资源 /static/index.2da1efab.css 加载完成: 文件: index.2da1efab.css | 大小: 93.7KB | 耗时: 2.063秒\n",
      "✅ 用户 7 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.085秒\n",
      "📊 用户 7 加载所有静态资源耗时: 2.434秒\n",
      "🚀 用户 7 开始看表单\n",
      "✅ 用户 1 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.073秒\n",
      "📊 用户 1 加载所有静态资源耗时: 2.450秒\n",
      "🚀 用户 1 开始看表单\n",
      "✅ 用户 3 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.037秒\n",
      "✅ 用户 3 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.059秒\n",
      "📊 用户 3 加载所有静态资源耗时: 2.487秒\n",
      "🚀 用户 3 开始看表单\n",
      "✅ 用户 2 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.049秒\n",
      "📊 用户 2 加载所有静态资源耗时: 2.507秒\n",
      "🚀 用户 2 开始看表单\n",
      "✅ 用户 9 资源 /static/js/chunk-vendors.js 加载完成: 文件: chunk-vendors.js | 大小: 2655.9KB | 耗时: 2.051秒\n",
      "📊 用户 9 加载所有静态资源耗时: 2.519秒\n",
      "🚀 用户 9 开始看表单\n",
      "✅ 用户 8 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.040秒\n",
      "📊 用户 8 加载所有静态资源耗时: 2.527秒\n",
      "🚀 用户 8 开始看表单\n",
      "✅ 用户 5 资源 /static/js/index.js 加载完成: 文件: index.js | 大小: 100.2KB | 耗时: 2.043秒\n",
      "✅ 用户 5 资源 /static/js/pages-login-index.js 加载完成: 文件: pages-login-index.js | 大小: 79.8KB | 耗时: 2.035秒\n",
      "📊 用户 5 加载所有静态资源耗时: 2.542秒\n",
      "🚀 用户 5 开始看表单\n"
     ]
    }
   ],
   "source": [
    "from faker import Faker\n",
    "import random\n",
    "import json\n",
    "from datetime import datetime\n",
    "import threading\n",
    "import requests\n",
    "from time import time, sleep\n",
    "import uuid\n",
    "from concurrent.futures import ThreadPoolExecutor, as_completed\n",
    "# 初始化Faker生成器（简体中文）\n",
    "fake = Faker('zh_CN')\n",
    "\n",
    "# 定义固定值\n",
    "TEAM_ID = 106\n",
    "PLAN_ID = 131\n",
    "\n",
    "# 常见民族列表\n",
    "ETHNIC_GROUPS = [\"汉\", \"壮\", \"满\", \"回\", \"苗\", \"维吾尔\", \"土家\", \"彝\", \"蒙古\", \"藏\", \"布依\", \n",
    "                \"侗\", \"瑶\", \"朝鲜\", \"白\", \"哈尼\", \"哈萨克\", \"黎\", \"傣\", \"畲\", \"傈僳\", \"仡佬\",\n",
    "                \"东乡\", \"高山\", \"拉祜\", \"水\", \"佤\", \"纳西\", \"羌\", \"土\", \"仫佬\", \"锡伯\", \"柯尔克孜\",\n",
    "                \"达斡尔\", \"景颇\", \"毛南\", \"撒拉\", \"布朗\", \"塔吉克\", \"阿昌\", \"普米\", \"鄂温克\", \"怒\",\n",
    "                \"京\", \"基诺\", \"德昂\", \"保安\", \"俄罗斯\", \"裕固\", \"乌兹别克\", \"门巴\", \"鄂伦春\", \"独龙\",\n",
    "                \"塔塔尔\", \"赫哲\", \"珞巴\"]\n",
    "\n",
    "# 疾病列表（健康状态）\n",
    "HEALTH_CONDITIONS = [\n",
    "    \"无\", \"近视\", \"弱视\", \"鼻炎\", \"哮喘\", \"过敏体质\", \"蛀牙\", \n",
    "    \"肥胖\", \"发育迟缓\", \"ADHD\", \"缺铁性贫血\", \"维生素缺乏\",\n",
    "    \"易感冒体质\", \"偏瘦\", \"过敏(花粉)\", \"过敏(尘螨)\", \"过敏(牛奶)\", \n",
    "    \"消化不良\", \"多动症\", \"抽动症\", \"癫痫\", \"小儿麻痹\", \"乙肝病毒携带\"\n",
    "]\n",
    "\n",
    "# 艺术特长\n",
    "ART_TALENTS = [\"无\", \"钢琴\", \"小提琴\", \"绘画\", \"书法\", \"舞蹈\", \"声乐\", \"戏剧表演\", \n",
    "             \"摄影\", \"编程\", \"动画制作\", \"模型制作\", \"手工艺术\"]\n",
    "\n",
    "# 体育特长\n",
    "SPORTS_TALENTS = [\"无\", \"游泳\", \"篮球\", \"足球\", \"乒乓球\", \"羽毛球\", \"田径\", \n",
    "                \"武术\", \"跆拳道\", \"空手道\", \"轮滑\", \"滑板\", \"自行车\", \"健美操\"]\n",
    "\n",
    "# 科技特长\n",
    "TECH_TALENTS = [\"无\", \"机器人编程\", \"电子制作\", \"3D打印\", \"人工智能\", \"网页设计\", \n",
    "              \"科学实验\", \"天文观测\", \"植物培养\", \"动物观察\", \"航模制作\"]\n",
    "\n",
    "# 职业列表\n",
    "OCCUPATIONS = [\"医生\", \"教师\", \"工程师\", \"程序员\", \"设计师\", \"建筑师\", \"销售经理\",\n",
    "              \"会计\", \"律师\", \"公务员\", \"记者\", \"警察\", \"消防员\", \"厨师\", \"商人\",\n",
    "              \"自由职业\", \"个体经营者\", \"银行职员\", \"人力资源\", \"市场营销\"]\n",
    "\n",
    "# 公司类型\n",
    "WORKPLACES = [\n",
    "    \"国有企业\", \"民营企业\", \"外资企业\", \"合资企业\", \"政府机关\", \n",
    "    \"事业单位\", \"学校\", \"医院\", \"设计事务所\", \"律师事务所\",\n",
    "    \"科技公司\", \"互联网公司\", \"金融机构\", \"建筑公司\", \"零售企业\"\n",
    "]\n",
    "\n",
    "# 小学名称\n",
    "PRIMARY_SCHOOLS = [\n",
    "    \"第一实验小学\", \"第二实验小学\", \"育才小学\", \"阳光小学\", \"希望小学\", \"和平小学\", \n",
    "    \"实验小学分校\", \"新世纪小学\", \"东方小学\", \"先锋小学\", \"星光小学\", \"明德小学\"\n",
    "]\n",
    "\n",
    "def generate_id_num(birthday):\n",
    "    \"\"\"生成符合规则的身份证号\"\"\"\n",
    "    # 生成前6位（地区码，使用真实的地区码）\n",
    "    region_codes = [\"110101\", \"110105\", \"110106\", \"110107\", \"310112\", \"330102\", \"440106\", \"440304\"]\n",
    "    \n",
    "    # 出生日期码（8位）\n",
    "    birth_code = birthday.replace(\"-\", \"\")\n",
    "    \n",
    "    # 顺序码（3位）\n",
    "    sequence_code = str(random.randint(101, 998))\n",
    "    \n",
    "    # 生成校验码（1位）\n",
    "    base = region_codes[random.randint(0, len(region_codes)-1)] + birth_code + sequence_code\n",
    "    weight = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]\n",
    "    checksum_map = {0: '1', 1: '0', 2: 'X', 3: '9', 4: '8', 5: '7', 6: '6', 7: '5', 8: '4', 9: '3', 10: '2'}\n",
    "    \n",
    "    total = 0\n",
    "    for i in range(17):\n",
    "        total += int(base[i]) * weight[i]\n",
    "    checksum = checksum_map[total % 11]\n",
    "    \n",
    "    return base + checksum\n",
    "\n",
    "def generate_student_data():\n",
    "    \"\"\"生成单个学生数据\"\"\"\n",
    "    # 基础信息\n",
    "    sex = random.choice([\"男\", \"女\"])\n",
    "    \n",
    "    # 生日 (2010-2015年出生)\n",
    "    birthday = fake.date_between(start_date=\"-15y\", end_date=\"-8y\").strftime(\"%Y-%m-%d\")\n",
    "    \n",
    "    # 生成符合规则的身份证号\n",
    "    id_num = generate_id_num(birthday)\n",
    "    \n",
    "    # 计算年龄（仅用于展示）\n",
    "    birth_year = int(birthday[:4])\n",
    "    current_year = datetime.now().year\n",
    "    age = current_year - birth_year\n",
    "    \n",
    "    # 生成学生信息\n",
    "    data = {\n",
    "        \"teamId\": TEAM_ID,\n",
    "        \"stuName\": fake.name(),  # 学生姓名\n",
    "        \"idNum\": id_num,  # 身份证号\n",
    "        \"formerName\": random.choices([\"无\", fake.last_name() + fake.first_name()], weights=[0.8, 0.2])[0],  # 曾用名\n",
    "        \"sex\": sex,  # 性别\n",
    "        \"nation\": random.choice(ETHNIC_GROUPS),  # 民族\n",
    "        \"birthday\": birthday,  # 生日\n",
    "        \"finishSchool\": random.choice(PRIMARY_SCHOOLS),  # 毕业学校\n",
    "        \"file\": None,  # 文件\n",
    "        \"hkadr\": fake.province() + \"/\" + fake.city() + \"/\" + fake.district(),  # 户口所在地\n",
    "        \"homeAddress\": fake.address(),  # 家庭住址\n",
    "        \"health\": random.choice(HEALTH_CONDITIONS),  # 健康状况\n",
    "        \"artisticSpecialty\": random.choice(ART_TALENTS),  # 艺术特长\n",
    "        \"artisticAchievements\": \"无\",  # 艺术成就\n",
    "        \"technologicalSpecialty\": random.choice(TECH_TALENTS),  # 科技特长\n",
    "        \"technologicalAchievements\": \"无\",  # 科技成就\n",
    "        \"sportsSpecialty\": random.choice(SPORTS_TALENTS),  # 体育特长\n",
    "        \"sportsAchievements\": \"无\",  # 体育成就\n",
    "        \"planId\": PLAN_ID,  # 计划ID\n",
    "        \"imageUrl\": \"\",  # 图片URL\n",
    "        \"schoolCode\": \"G\" + id_num[:-1],  # 学籍号\n",
    "        \"age\": age,  # 年龄（仅用于展示）\n",
    "        \"email\": fake.email() if random.random() > 0.7 else \"\",  # 邮箱\n",
    "        \"height\": str(random.randint(130, 170)),  # 身高\n",
    "        \"weight\": str(random.randint(25, 60)),  # 体重\n",
    "        \"measurements\": f\"{random.randint(60, 90)},{random.randint(60, 90)},{random.randint(60, 90)}\"  # 三围\n",
    "    }\n",
    "    \n",
    "    # 生成监护人信息\n",
    "    guardian_prefix = fake.last_name()\n",
    "    \n",
    "    # 监护人1 - 通常为父母之一\n",
    "    relationship_choices = [\"父亲\", \"母亲\", \"爷爷\", \"奶奶\", \"外公\", \"外婆\"]\n",
    "    relationship = random.choice(relationship_choices[:2])  # 主要选择父母\n",
    "    \n",
    "    data.update({\n",
    "        \"guardian1Name\": guardian_prefix + (\"先生\" if relationship == \"父亲\" else \"女士\"),  # 监护人1姓名\n",
    "        \"guardian1Relationship\": relationship,  # 关系\n",
    "        \"guardian1IdCardNumber\": generate_id_num(fake.date_between(start_date=\"-55y\", end_date=\"-25y\").strftime(\"%Y-%m-%d\")),  # 身份证号\n",
    "        \"guardian1Contact\": fake.phone_number(),  # 联系方式\n",
    "        \"guardian1Occupation\": random.choice(OCCUPATIONS),  # 职业\n",
    "        \"guardian1Workplace\": random.choice(WORKPLACES)  # 工作单位\n",
    "    })\n",
    "    \n",
    "    # 监护人2 - 可能是另一位家长或其他人\n",
    "    if relationship == \"父亲\":\n",
    "        guardian2_relationship = \"母亲\"\n",
    "    else:\n",
    "        guardian2_relationship = random.choices(\n",
    "            [\"父亲\", \"爷爷\", \"奶奶\", \"外公\", \"外婆\", \"其他亲属\"], \n",
    "            weights=[0.7, 0.1, 0.1, 0.05, 0.05, 0.1]\n",
    "        )[0]\n",
    "    \n",
    "    data.update({\n",
    "        \"guardian2Name\": guardian_prefix + (\n",
    "            \"先生\" if guardian2_relationship in [\"父亲\", \"爷爷\", \"外公\"] else \"女士\"\n",
    "        ),  # 监护人2姓名\n",
    "        \"guardian2Relationship\": guardian2_relationship,  # 关系\n",
    "        \"guardian2IdCardNumber\": generate_id_num(fake.date_between(start_date=\"-55y\", end_date=\"-25y\").strftime(\"%Y-%m-%d\")),  # 身份证号\n",
    "        \"guardian2Contact\": fake.phone_number() if guardian2_relationship != \"无\" else \"\",  # 联系方式\n",
    "        \"guardian2Occupation\": random.choice(OCCUPATIONS) if guardian2_relationship != \"无\" else \"\",  # 职业\n",
    "        \"guardian2Workplace\": random.choice(WORKPLACES) if guardian2_relationship != \"无\" else \"\"  # 工作单位\n",
    "    })\n",
    "    \n",
    "    return data\n",
    "\n",
    "def generate_students():\n",
    "    student = generate_student_data()\n",
    "    return student\n",
    "\n",
    "\n",
    "# 配置信息\n",
    "BASE_URL = \"http://localhost:8080\"\n",
    "STATIC_PATHS = [\n",
    "    \"/static/index.2da1efab.css\",\n",
    "    \"/static/js/chunk-vendors.js\",\n",
    "    \"/static/js/index.js\",\n",
    "    \"/static/js/pages-login-index.js\"\n",
    "]\n",
    "\n",
    "# 用户数据生成\n",
    "USER_AGENTS = [\n",
    "    \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\",\n",
    "    \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15\",\n",
    "    \"Mozilla/5.0 (iPhone; CPU iPhone OS 15_5 like Mac OS X) AppleWebKit/605.1.15\",\n",
    "    \"Mozilla/5.0 (Linux; Android 12; SM-G991B) AppleWebKit/537.36\",\n",
    "    \"Mozilla/5.0 (iPad; CPU OS 15_5 like Mac OS X) AppleWebKit/605.1.15\"\n",
    "]\n",
    "\n",
    "def generate_user_data(user_id):\n",
    "    \"\"\"生成模拟用户数据\"\"\"\n",
    "    return {\n",
    "        \"id\": user_id,\n",
    "        \"session_id\": str(uuid.uuid4()),\n",
    "        \"user_agent\": random.choice(USER_AGENTS),\n",
    "        \"request_count\": 0,\n",
    "        \"start_time\": time()\n",
    "    }\n",
    "\n",
    "def simulate_user_session(user_id):\n",
    "    \"\"\"模拟一个用户的完整会话\"\"\"\n",
    "    user_data = generate_user_data(user_id)\n",
    "    print(f\"👤 用户 {user_id} 开始会话, Session ID: {user_data['session_id']}\")\n",
    "    start = time()\n",
    "    # 使用线程池请求所有静态资源\n",
    "    with ThreadPoolExecutor(max_workers=len(STATIC_PATHS)) as executor:\n",
    "        futures = {}\n",
    "        \n",
    "        # 提交所有静态资源请求任务\n",
    "        for path in STATIC_PATHS:\n",
    "            url = BASE_URL + path\n",
    "            future = executor.submit(\n",
    "                fetch_resource, \n",
    "                url, \n",
    "                user_data\n",
    "            )\n",
    "            futures[future] = path\n",
    "            \n",
    "        # 等待所有静态资源加载完成\n",
    "        for future in as_completed(futures):\n",
    "            path = futures[future]\n",
    "            try:\n",
    "                result = future.result()\n",
    "                print(f\"✅ 用户 {user_id} 资源 {path} 加载完成: {result}\")\n",
    "            except Exception as e:\n",
    "                print(f\"❌ 用户 {user_id} 资源加载失败: {str(e)}\")\n",
    "    end = time()\n",
    "    # 所有静态资源加载完成后访问百度提交数据\n",
    "    print(f\"📊 用户 {user_id} 加载所有静态资源耗时: {end - start:.3f}秒\")\n",
    "    print(f\"🚀 用户 {user_id} 开始看表单\")\n",
    "    submit_to_baidu(user_data)\n",
    "    \n",
    "    return user_data\n",
    "\n",
    "def fetch_resource(url, user_data):\n",
    "    \"\"\"模拟用户获取单个资源\"\"\"\n",
    "    # 更新用户请求计数\n",
    "    user_data[\"request_count\"] += 1\n",
    "    \n",
    "    # 生成请求头\n",
    "    headers = {\n",
    "        \"User-Agent\": user_data[\"user_agent\"],\n",
    "        \"X-Session-Id\": user_data[\"session_id\"],\n",
    "        \"X-Request-Count\": str(user_data[\"request_count\"]),\n",
    "        \"Accept-Encoding\": \"gzip, deflate\"\n",
    "    }\n",
    "    \n",
    "    # 添加随机延迟(0.1-0.5秒)模拟网络波动\n",
    "    sleep(random.uniform(0.1, 0.5))\n",
    "    \n",
    "    try:\n",
    "        # 执行资源请求\n",
    "        start_time = time()\n",
    "        response = requests.get(url, headers=headers)\n",
    "        elapsed_time = time() - start_time\n",
    "        \n",
    "        if response.status_code != 200:\n",
    "            return f\"错误状态码: {response.status_code} | 耗时: {elapsed_time:.3f}秒\"\n",
    "        \n",
    "        # 提取文件名\n",
    "        file_name = url.split('/')[-1]\n",
    "        \n",
    "        return f\"文件: {file_name} | 大小: {len(response.text)/1024:.1f}KB | 耗时: {elapsed_time:.3f}秒\"\n",
    "    \n",
    "    except Exception as e:\n",
    "        return f\"请求异常: {str(e)}\"\n",
    "\n",
    "def submit_to_baidu(user_data):\n",
    "    \"\"\"提交数据到百度\"\"\"\n",
    "    # 构造提交数据\n",
    "    payload = generate_students()\n",
    "    sleep(random.uniform(5, 20))\n",
    "    print(f\"🎉 用户 {user_data['id']} 提交数据 \")\n",
    "    try:\n",
    "        # 提交到百度\n",
    "        start_time = time()\n",
    "        response = requests.post(\n",
    "            \"http://band.hxzhxy.cn/register/student/add\",  # 模拟的百度提交API\n",
    "            json=payload,\n",
    "            headers={\n",
    "                \"User-Agent\": user_data[\"user_agent\"],\n",
    "                \"X-Session-Id\": user_data[\"session_id\"],\n",
    "                \"Content-Type\": \"application/json\"\n",
    "            }\n",
    "        )\n",
    "        elapsed_time = time() - start_time\n",
    "        \n",
    "        # 记录用户总用时\n",
    "        total_time = time() - user_data[\"start_time\"]\n",
    "        \n",
    "        if response.status_code == 200:\n",
    "            print(f\"🎉 用户 {user_data['id']} 数据提交成功! | 提交耗时: {elapsed_time:.3f}秒 | 总用时: {total_time:.3f}秒\")\n",
    "            return True\n",
    "        else:\n",
    "            print(f\"⚠️ 用户 {user_data['id']} 提交失败: 状态码 {response.status_code} | 总用时: {total_time:.3f}秒\")\n",
    "            return False\n",
    "    \n",
    "    except Exception as e:\n",
    "        print(f\"‼️ 用户 {user_data['id']} 提交异常: {str(e)}\")\n",
    "        return False\n",
    "\n",
    "def simulate_multiple_users(num_users=10):\n",
    "    \"\"\"模拟多个用户并发访问\"\"\"\n",
    "    print(f\"🎬 开始模拟 {num_users} 个用户并发访问...\")\n",
    "    print(\"=\" * 70)\n",
    "    \n",
    "    with ThreadPoolExecutor(max_workers=num_users) as executor:\n",
    "        # 提交所有用户会话任务\n",
    "        futures = [executor.submit(simulate_user_session, i+1) for i in range(5)]\n",
    "        \n",
    "        # 等待所有用户完成并收集结果\n",
    "        results = []\n",
    "        for future in as_completed(futures):\n",
    "            try:\n",
    "                user_data = future.result()\n",
    "                results.append(user_data)\n",
    "            except Exception as e:\n",
    "                print(f\"用户会话异常: {str(e)}\")\n",
    "    \n",
    "    # 生成性能报告\n",
    "    print(\"\\n\" + \"=\" * 70)\n",
    "    print(\"🏁 所有用户已完成操作! 性能摘要:\")\n",
    "    print(\"-\" * 70)\n",
    "    \n",
    "    total_time = 0\n",
    "    total_requests = 0\n",
    "    completed_submissions = 0\n",
    "    \n",
    "    for user in results:\n",
    "        session_time = time() - user[\"start_time\"]\n",
    "        total_time += session_time\n",
    "        total_requests += user[\"request_count\"]\n",
    "        \n",
    "        print(f\"用户 {user['id']:2d} | 用时: {session_time:.3f}秒 | 请求数: {user['request_count']}\")\n",
    "    \n",
    "    print(\"\\n汇总统计:\")\n",
    "    print(f\"- 平均用时: {total_time/len(results):.3f}秒/用户\")\n",
    "    print(f\"- 总请求数: {total_requests}次\")\n",
    "    print(f\"- 用户提交率: {completed_submissions}/{len(results)}\")\n",
    "    print(\"=\" * 70)\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    simulate_multiple_users(num_users=10)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
