import random import re import requests from datetime import datetime, timedelta from typing import Dict, Any, Tuple # ========================================== # 1. 常量与国家配置区 # ========================================== DEFAULT_PASSWORD = "Visafly@111" VISA_TYPE = "Short stay (<90 days) - Tourism" TRAVEL_PURPOSE = "Tourism / Private visit" PASSPORT_TYPE = "Ordinary passport" # 国家专属配置字典,将差异化数据隔离,极大提升可维护性 COUNTRY_CONFIGS = { "CN": { "nat_code": None, # randomuser 不支持 CN,置为 None "pool_name": "tls.cn.sha.fr.sentinel", "location": "Shanghai", "province_residence": "Shanghai", "nationality": "China", "phone_country_code": "86", # --- 本地化生成规则(针对 API 不支持的国家) --- "local_first_names": ["Wei", "Fang", "Jian", "Hui", "Lei", "Ting", "Peng", "Xia", "Bin", "Jie", "San", "Ming"], "local_last_names": ["Wang", "Li", "Zhang", "Liu", "Chen", "Yang", "Huang", "Zhao", "Wu", "Zhou"], "phone_prefix": ["138", "139", "150", "151", "180", "189"], # 中国手机号前缀 "phone_length": 11, # ----------------------------------------------- "default_first_name": "San", "default_last_name": "Zhang", "default_phone": "13800000000" }, "GB": { "nat_code": "gb", # API 支持 GB,直接依赖 API 生成姓名 "pool_name": "tls.gb.lon.fr.sentinel", "location": "London", "province_residence": "London", "nationality": "United Kingdom", "phone_country_code": "44", "default_first_name": "James", "default_last_name": "Smith", "default_phone": "7400000000" } } # ========================================== # 2. 辅助生成函数 (单一职责) # ========================================== def _fetch_random_user_data(nat_code: str = None) -> Dict[str, Any]: """ 请求 randomuser API。 如果 nat_code 为空,则请求全局随机用户(仅用于借用其随机的出生日期和性别)。 """ url = f"https://randomuser.me/api/?nat={nat_code}" if nat_code else "https://randomuser.me/api/" try: resp = requests.get(url, timeout=10) resp.raise_for_status() raw = resp.json() results = raw.get("results") if results and isinstance(results, list): return results[0] except Exception: pass return {} def _generate_localized_name(config: Dict[str, Any], api_user: Dict[str, Any]) -> Tuple[str, str]: """生成姓名:优先使用本地词库,否则使用 API 返回值""" if "local_last_names" in config and "local_first_names" in config: return random.choice(config["local_first_names"]), random.choice(config["local_last_names"]) first = api_user.get("name", {}).get("first") or config["default_first_name"] last = api_user.get("name", {}).get("last") or config["default_last_name"] return first, last def _generate_localized_phone(config: Dict[str, Any], api_user: Dict[str, Any]) -> str: """生成手机号:优先使用本地规则,否则清洗 API 返回值""" if "phone_prefix" in config: prefix = random.choice(config["phone_prefix"]) suffix_len = config.get("phone_length", 11) - len(prefix) suffix = "".join(str(random.randint(0, 9)) for _ in range(suffix_len)) return f"{prefix}{suffix}" phone_raw = api_user.get("cell") or api_user.get("phone") or "" phone = re.sub(r"\D", "", phone_raw) return phone or config["default_phone"] def _generate_random_dates() -> Dict[str, str]: """生成合法的随机日期集合(出行、护照等)""" today = datetime.today() base_date = today + timedelta(days=random.randint(20, 90)) # 护照日期(避免闰年 replace 报错,采用天数计算) start_date = today - timedelta(days=5 * 365) passport_issue = start_date + timedelta(days=random.randint(0, (today - start_date).days)) passport_expiry = passport_issue + timedelta(days=10 * 365 + 2) - timedelta(days=1) return { "departure_origin_date": (base_date - timedelta(days=random.randint(0, 2))).strftime("%Y-%m-%d"), "arrival_schengen_area_date": base_date.strftime("%Y-%m-%d"), "departure_schengen_area_date": (base_date + timedelta(days=random.randint(2, 15))).strftime("%Y-%m-%d"), "passport_issue_date": passport_issue.strftime("%Y-%m-%d"), "passport_expiry_date": passport_expiry.strftime("%Y-%m-%d"), } def _generate_email(first_name: str, last_name: str) -> str: """基于姓名生成随机邮箱""" email_prefix = re.sub(r"[^a-z0-9]", "", f"{first_name}{last_name}".lower()) if not email_prefix: email_prefix = f"user{random.randint(100000, 999999)}" return f"{email_prefix}{random.randint(1000, 9999)}@gmail-app.com" # ========================================== # 3. 主函数 # ========================================== def generate_random_account_detail(country_code: str = "CN") -> Dict[str, Any]: """ 基于 randomuser 和指定国家配置生成随机账户信息。 """ config = COUNTRY_CONFIGS.get(country_code.upper()) if not config: raise ValueError(f"Unsupported country code: {country_code}") # 1. 抓取 API(即使不支持的国家,也可借用其随机返回的年龄/性别) api_user = _fetch_random_user_data(config.get("nat_code")) # 2. 解析基础数据(本地化拦截器) first_name, last_name = _generate_localized_name(config, api_user) phone_number = _generate_localized_phone(config, api_user) gender_raw = str(api_user.get("gender", "")).strip().lower() gender = "Male" if gender_raw == "male" else "Female" birthday_raw = api_user.get("dob", {}).get("date", "") birthday = birthday_raw[:10] if birthday_raw else "1990-01-01" # 3. 各种衍生计算 email = _generate_email(first_name, last_name) dates = _generate_random_dates() app_form_suffix = "".join(str(random.randint(0, 9)) for _ in range(11)) passport_no = "".join(random.choices("ABCDEFGHIJKLMNOPQRSTUVWXYZ", k=2)) + \ "".join(random.choices("0123456789", k=7)) # LO 伦敦 DB 都柏林 PB 北京 SH 上海 # 4. 组装组装并返回 return { "pool_name": config["pool_name"], "email": email, "pwd": DEFAULT_PASSWORD, "location": config["location"], "visa_type": VISA_TYPE, "travel_purpose": TRAVEL_PURPOSE, "application_form_id": f"FRA1SH{app_form_suffix}", "last_name": last_name, "first_name": first_name, "gender": gender, "birthday": birthday, "nationality": config["nationality"], "province_residence": config["province_residence"], "passport_type": PASSPORT_TYPE, "passport_no": passport_no, "passport_issue_date": dates["passport_issue_date"], "passport_expiry_date": dates["passport_expiry_date"], "phone_country_code": config["phone_country_code"], "phone_number": phone_number, "departure_origin_date": dates["departure_origin_date"], "arrival_schengen_area_date": dates["arrival_schengen_area_date"], "departure_schengen_area_date": dates["departure_schengen_area_date"], } # 测试代码 if __name__ == "__main__": print("--- 🇨🇳 中国数据 (借用API年龄性别 + 本地化姓名/手机) ---") print(generate_random_account_detail("CN")) print("\n--- 🇬🇧 英国数据 (完全依赖API生成) ---") print(generate_random_account_detail("GB"))