| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181 |
- 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"))
|