Spaces:
Sleeping
Sleeping
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__) | |
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) | |
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()) |