import asyncio import aiohttp import json import time import random from typing import Dict, Optional, List, Any from urllib.parse import urljoin from faker import Faker from concurrent.futures import ThreadPoolExecutor from asyncio import Semaphore from tqdm.asyncio import tqdm as tqdm_asyncio import logging from dataclasses import dataclass from aiohttp import ClientTimeout from contextlib import asynccontextmanager # Configuration du logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) @dataclass class AccountData: username: str password: str province_id: int ville_id: int registration_date: str = None class RateLimiter: def __init__(self, rate_limit: int, time_window: float = 1.0): self.rate_limit = rate_limit self.time_window = time_window self.tokens = rate_limit self.last_update = time.time() self._lock = asyncio.Lock() async def acquire(self): async with self._lock: now = time.time() time_passed = now - self.last_update self.tokens = min(self.rate_limit, self.tokens + time_passed * (self.rate_limit / self.time_window)) self.last_update = now if self.tokens < 1: wait_time = (1 - self.tokens) * (self.time_window / self.rate_limit) await asyncio.sleep(wait_time) self.tokens = 0 else: self.tokens -= 1 class AccountGenerator: def __init__(self): self.faker = Faker(['fr_FR']) self.locations = { 1: [1, 2, 3, 4, 5, 6], # Estuaire 2: [7, 8, 9, 10, 11], # Haut-Ogooué 3: [12, 13], # Moyen-Ogooué 4: [14, 15, 16, 17, 18],# Ngounié 5: [19, 20, 21], # Nyanga 6: [22, 23, 24], # Ogooué-Ivindo 7: [25, 26], # Ogooué-Lolo 8: [27, 28, 29], # Ogooué-Maritime 9: [30, 31, 32, 33, 34] # Woleu-Ntem } self._username_cache = set() self._lock = asyncio.Lock() async def generate_unique_username(self, min_length=10, max_length=20) -> str: async with self._lock: while True: username = self._generate_username(min_length, max_length) if username not in self._username_cache: self._username_cache.add(username) return username def _generate_username(self, min_length=10, max_length=20) -> str: patterns = [ lambda: self.faker.user_name()[:12], lambda: f"{self.faker.first_name().lower()}{random.randint(1, 999)}", lambda: f"{self.faker.last_name().lower()}{random.randint(1, 99)}", lambda: f"{self.faker.word()}{random.randint(1, 999)}" ] username = random.choice(patterns)() username = ''.join(c for c in username if c.isalnum()) if len(username) < min_length: username += str(random.randint(1000, 9999)) elif len(username) > max_length: username = username[:max_length] return username def generate_password(self, min_length=8, max_length=12) -> str: patterns = [ lambda: self.faker.password(length=random.randint(min_length, max_length)), lambda: f"{self.faker.word().capitalize()}{random.randint(100, 999)}!", lambda: f"{self.faker.color_name().capitalize()}{random.randint(100, 999)}@" ] return random.choice(patterns)() def generate_location(self) -> tuple: province_id = random.choice(list(self.locations.keys())) ville_id = random.choice(self.locations[province_id]) return province_id, ville_id async def generate_account_data(self) -> AccountData: province_id, ville_id = self.generate_location() return AccountData( username=await self.generate_unique_username(), password=self.generate_password(), province_id=province_id, ville_id=ville_id ) class AsyncGabaoHubAPI: def __init__(self, base_url: str, session: aiohttp.ClientSession, rate_limiter: RateLimiter): self.base_url = base_url.rstrip('/') self.session = session self.rate_limiter = rate_limiter self.timeout = ClientTimeout(total=30) self.headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3' } async def _make_request(self, endpoint: str, method: str = 'POST', data: Dict = None) -> Dict: await self.rate_limiter.acquire() url = urljoin(self.base_url, endpoint) try: async with self.session.request(method, url, data=data, timeout=self.timeout, headers=self.headers) as response: text = await response.text() return { 'success': response.status == 200, 'status_code': response.status, 'data': text } except asyncio.TimeoutError: logger.error(f"Timeout lors de la requête vers {endpoint}") return {'success': False, 'error': 'Timeout'} except Exception as e: logger.error(f"Erreur lors de la requête vers {endpoint}: {str(e)}") return {'success': False, 'error': str(e)} async def check_username_availability(self, username: str) -> bool: result = await self._make_request( '/assets/functions.php', data={'ajaxCall': 'isUsernameTaken', 'u': username} ) if not result['success']: raise ConnectionError(f"Erreur lors de la vérification du username: {result.get('error')}") return result['data'].strip() == "0" async def register_user(self, account_data: AccountData) -> Dict: if not 3 <= len(account_data.username) <= 32: return {'success': False, 'error': "Username length invalid"} if not account_data.username.isalnum(): return {'success': False, 'error': "Username must be alphanumeric"} if not 4 <= len(account_data.password) <= 32: return {'success': False, 'error': "Password length invalid"} init_result = await self._make_request('/register/index.php', method='GET') if not init_result['success']: return {'success': False, 'error': "Cannot access registration page"} if not await self.check_username_availability(account_data.username): return {'success': False, 'error': "Username already taken"} register_data = { 'username': account_data.username, 'password': account_data.password, 'password2': account_data.password, 'province': str(account_data.province_id), 'ville': str(account_data.ville_id), 'submit': "S'incrire" } result = await self._make_request('/register/register.php', data=register_data) if not result['success']: return {'success': False, 'error': f"Registration error: {result.get('error')}"} if "erreur" in result['data'].lower() or "error" in result['data'].lower(): return {'success': False, 'error': "Registration failed, check provided data"} return { 'success': True, 'message': "Registration successful", 'data': result['data'] } class AsyncAccountCreator: def __init__(self, base_url: str, max_concurrent: int = 3, rate_limit: int = 10): self.base_url = base_url self.generator = AccountGenerator() self.max_concurrent = max_concurrent self.rate_limiter = RateLimiter(rate_limit) self.successful_accounts: List[AccountData] = [] self.failed_accounts: List[Dict] = [] self._semaphore = Semaphore(max_concurrent) @asynccontextmanager async def _get_session(self): conn = aiohttp.TCPConnector(limit=self.max_concurrent) async with aiohttp.ClientSession(connector=conn) as session: yield session async def create_account(self, session: aiohttp.ClientSession) -> Dict: async with self._semaphore: api = AsyncGabaoHubAPI(self.base_url, session, self.rate_limiter) max_retries = 3 retry_count = 0 while retry_count < max_retries: try: account_data = await self.generator.generate_account_data() result = await api.register_user(account_data) if result['success']: account_data.registration_date = time.strftime('%Y-%m-%d %H:%M:%S') self.successful_accounts.append(account_data) return {'success': True, 'account': account_data} retry_count += 1 await asyncio.sleep(random.uniform(1, 3)) except Exception as e: logger.error(f"Error creating account: {str(e)}") retry_count += 1 await asyncio.sleep(random.uniform(1, 3)) self.failed_accounts.append({ 'error': f"Failed after {max_retries} attempts", 'last_attempt': account_data }) return {'success': False, 'error': f"Failed after {max_retries} attempts"} async def create_multiple_accounts(self, count: int) -> Dict: start_time = time.time() results = {'success': [], 'failed': []} async with self._get_session() as session: tasks = [self.create_account(session) for _ in range(count)] for result in tqdm_asyncio( asyncio.as_completed(tasks), total=count, desc="Creating accounts" ): try: completed_result = await result if completed_result['success']: results['success'].append(completed_result['account']) else: results['failed'].append(completed_result['error']) except Exception as e: logger.error(f"Task error: {str(e)}") results['failed'].append(str(e)) end_time = time.time() return { 'duration': end_time - start_time, 'total_attempts': count, 'successful': len(results['success']), 'failed': len(results['failed']), 'accounts': results['success'], 'errors': results['failed'] } async def save_accounts(accounts: List[AccountData], filename: str): with open(filename, 'w', encoding='utf-8') as f: json.dump([vars(account) for account in accounts], f, ensure_ascii=False, indent=2) async def main(): try: creator = AsyncAccountCreator( 'https://gabaohub.alwaysdata.net', max_concurrent=10, rate_limit=20 ) num_accounts = 20000 logger.info(f"Creating {num_accounts} accounts...") results = await creator.create_multiple_accounts(num_accounts) logger.info(f"\nResults after {results['duration']:.2f} seconds:") logger.info(f"✅ Successfully created accounts: {results['successful']}") logger.info(f"❌ Failed attempts: {results['failed']}") if results['accounts']: filename = f"accounts_{time.strftime('%Y%m%d_%H%M%S')}.json" await save_accounts(results['accounts'], filename) logger.info(f"\nAccounts saved to {filename}") except Exception as e: logger.error(f"Main error: {str(e)}") raise if __name__ == "__main__": asyncio.run(main())