capture more capcha info

This commit is contained in:
Dobromir Popov
2025-07-03 02:20:21 +03:00
parent e4a611a0cc
commit 09ed86c8ae
4 changed files with 15742 additions and 100 deletions

View File

@ -66,86 +66,74 @@ class MEXCRequestInterceptor:
self.requests_file = f"mexc_requests_{self.timestamp}.json"
self.cookies_file = f"mexc_cookies_{self.timestamp}.json"
def setup_chrome_with_logging(self) -> webdriver.Chrome:
"""Setup Brave browser with performance logging enabled"""
logger.info("Setting up ChromeDriver with request interception for Brave browser...")
# Chrome options (used for Brave as it's Chromium-based)
chrome_options = Options()
# Set up Chrome options with a user data directory to persist session
user_data_dir = os.path.join(os.getcwd(), 'chrome_user_data')
os.makedirs(user_data_dir, exist_ok=True)
chrome_options.add_argument(f'--user-data-dir={user_data_dir}')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
def setup_browser(self):
"""Setup Chrome browser with necessary options"""
chrome_options = webdriver.ChromeOptions()
# Enable headless mode if needed
if self.headless:
chrome_options.add_argument('--headless')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--disable-extensions')
# Set the binary location for Brave
# brave_binary_path = "C:\\Program Files\\BraveSoftware\\Brave-Browser\\Application\\brave.exe"
# chrome_options.binary_location = brave_binary_path
# logger.info(f"Using Brave binary at: {brave_binary_path}")
# Set up Chrome options with a user data directory to persist session
user_data_base_dir = os.path.join(os.getcwd(), 'chrome_user_data')
os.makedirs(user_data_base_dir, exist_ok=True)
# Essential options for automation
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument("--disable-web-security")
chrome_options.add_argument("--allow-running-insecure-content")
chrome_options.add_argument("--disable-features=VizDisplayCompositor")
# Check for existing session directories
session_dirs = [d for d in os.listdir(user_data_base_dir) if d.startswith('session_')]
session_dirs.sort(reverse=True) # Sort descending to get the most recent first
# User agent to avoid detection
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
chrome_options.add_argument(f"--user-agent={user_agent}")
user_data_dir = None
if session_dirs:
use_existing = input(f"Found {len(session_dirs)} existing sessions. Use an existing session? (y/n): ").lower().strip() == 'y'
if use_existing:
print("Available sessions:")
for i, session in enumerate(session_dirs[:5], 1): # Show up to 5 most recent
print(f"{i}. {session}")
choice = input("Enter session number (default 1) or any other key for most recent: ")
if choice.isdigit() and 1 <= int(choice) <= len(session_dirs):
selected_session = session_dirs[int(choice) - 1]
else:
selected_session = session_dirs[0]
user_data_dir = os.path.join(user_data_base_dir, selected_session)
print(f"Using session: {selected_session}")
# Disable automation flags
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
if user_data_dir is None:
user_data_dir = os.path.join(user_data_base_dir, f'session_{self.timestamp}')
os.makedirs(user_data_dir, exist_ok=True)
print(f"Creating new session: session_{self.timestamp}")
# Enable performance logging for network requests
chrome_options.add_argument("--enable-logging")
chrome_options.add_argument("--log-level=0")
chrome_options.add_argument("--v=1")
chrome_options.add_argument(f'--user-data-dir={user_data_dir}')
# Set logging preferences for performance data
# Enable logging to capture JS console output and network activity
chrome_options.set_capability('goog:loggingPrefs', {
'performance': 'ALL',
'browser': 'ALL'
'browser': 'ALL',
'performance': 'ALL'
})
# # Add profile directory argument as provided by the user
# chrome_options.add_argument("--profile-directory=Profile 3")
try:
# Automatically download and install ChromeDriver
logger.info("Downloading/updating ChromeDriver...")
service = Service(ChromeDriverManager().install())
# Create driver
driver = webdriver.Chrome(
service=service,
options=chrome_options
)
# Hide automation indicators
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
"userAgent": user_agent
})
# Enable network domain for CDP
driver.execute_cdp_cmd('Network.enable', {})
driver.execute_cdp_cmd('Runtime.enable', {})
logger.info("ChromeDriver setup complete!")
return driver
self.driver = webdriver.Chrome(options=chrome_options)
except Exception as e:
logger.error(f"Failed to setup ChromeDriver: {e}")
raise
print(f"Failed to start browser with session: {e}")
print("Falling back to a new session...")
user_data_dir = os.path.join(user_data_base_dir, f'session_{self.timestamp}_fallback')
os.makedirs(user_data_dir, exist_ok=True)
print(f"Creating fallback session: session_{self.timestamp}_fallback")
chrome_options = webdriver.ChromeOptions()
if self.headless:
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument(f'--user-data-dir={user_data_dir}')
chrome_options.set_capability('goog:loggingPrefs', {
'browser': 'ALL',
'performance': 'ALL'
})
self.driver = webdriver.Chrome(options=chrome_options)
return self.driver
def start_monitoring(self):
"""Start the browser and begin monitoring"""
@ -153,7 +141,7 @@ class MEXCRequestInterceptor:
try:
# Setup ChromeDriver
self.driver = self.setup_chrome_with_logging()
self.driver = self.setup_browser()
# Navigate to MEXC futures
mexc_url = "https://www.mexc.com/en-GB/futures/ETH_USDT?type=linear_swap"

View File

@ -22,6 +22,17 @@ from urllib.parse import urlencode
logger = logging.getLogger(__name__)
class MEXCSessionManager:
def __init__(self):
self.captcha_token = None
def get_captcha_token(self) -> str:
return self.captcha_token if self.captcha_token else ""
def save_captcha_token(self, token: str):
self.captcha_token = token
logger.info("MEXC: Captcha token saved in session manager")
class MEXCFuturesWebClient:
"""
MEXC Futures Web Client that mimics browser behavior for futures trading.
@ -30,30 +41,27 @@ class MEXCFuturesWebClient:
the exact HTTP requests made by their web interface.
"""
def __init__(self, session_cookies: Dict[str, str] = None):
def __init__(self, api_key: str, api_secret: str, user_id: str, base_url: str = 'https://www.mexc.com', headless: bool = True):
"""
Initialize the MEXC Futures Web Client
Args:
session_cookies: Dictionary of cookies from an authenticated browser session
api_key: API key for authentication
api_secret: API secret for authentication
user_id: User ID for authentication
base_url: Base URL for the MEXC website
headless: Whether to run the browser in headless mode
"""
self.session = requests.Session()
# Base URLs for different endpoints
self.base_url = "https://www.mexc.com"
self.futures_api_url = "https://futures.mexc.com/api/v1"
self.captcha_url = f"{self.base_url}/ucgateway/captcha_api/captcha/robot"
# Session state
self.api_key = api_key
self.api_secret = api_secret
self.user_id = user_id
self.base_url = base_url
self.is_authenticated = False
self.user_id = None
self.auth_token = None
self.fingerprint = None
self.visitor_id = None
# Load session cookies if provided
if session_cookies:
self.load_session_cookies(session_cookies)
self.headless = headless
self.session = requests.Session()
self.session_manager = MEXCSessionManager() # Adding session_manager attribute
self.captcha_url = f'{base_url}/ucgateway/captcha_api'
self.futures_api_url = "https://futures.mexc.com/api/v1"
# Setup default headers that mimic a real browser
self.setup_browser_headers()
@ -142,37 +150,59 @@ class MEXCFuturesWebClient:
endpoint = f"robot.future.{side}.{symbol}.{leverage}"
url = f"{self.captcha_url}/{endpoint}"
# Setup headers for captcha request
# Attempt to get captcha token from session manager
captcha_token = self.session_manager.get_captcha_token()
if not captcha_token:
logger.warning("MEXC: No captcha token available, attempting to fetch from browser")
captcha_token = self._extract_captcha_token_from_browser()
if captcha_token:
self.session_manager.save_captcha_token(captcha_token)
else:
logger.error("MEXC: Failed to extract captcha token from browser")
return False
headers = {
'Content-Type': 'application/json',
'Language': 'en-GB',
'Referer': f'{self.base_url}/en-GB/futures/{symbol}?type=linear_swap',
'trochilus-uid': self.user_id if self.user_id else '',
'trochilus-trace-id': f"{uuid.uuid4()}-{int(time.time() * 1000) % 10000:04d}"
'trochilus-trace-id': f"{uuid.uuid4()}-{int(time.time() * 1000) % 10000:04d}",
'captcha-token': captcha_token
}
# Add captcha token if available (this would need to be extracted from browser)
# For now, we'll make the request without it and see what happens
logger.info(f"MEXC: Verifying captcha for {endpoint}")
try:
response = self.session.get(url, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data.get('success') and data.get('code') == 0:
logger.info(f"MEXC: Captcha verification successful for {side} {symbol}")
if data.get('success'):
logger.info(f"MEXC: Captcha verified successfully for {endpoint}")
return True
else:
logger.warning(f"MEXC: Captcha verification failed: {data}")
logger.error(f"MEXC: Captcha verification failed for {endpoint}: {data}")
return False
else:
logger.error(f"MEXC: Captcha request failed with status {response.status_code}")
logger.error(f"MEXC: Captcha verification request failed with status {response.status_code}: {response.text}")
return False
except Exception as e:
logger.error(f"MEXC: Captcha verification error: {e}")
logger.error(f"MEXC: Captcha verification error for {endpoint}: {str(e)}")
return False
def _extract_captcha_token_from_browser(self) -> str:
"""
Extract captcha token from browser session using stored cookies or requests.
This is a placeholder for actual implementation which would interact with browser data.
"""
try:
# Placeholder for extracting token from browser session or stored data
# In a real scenario, this would parse the mexc_requests JSON file or interact with Selenium
logger.info("MEXC: Attempting to extract captcha token from browser data")
# For now, return empty string as placeholder
return ""
except Exception as e:
logger.error(f"MEXC: Error extracting captcha token from browser: {str(e)}")
return ""
def generate_signature(self, method: str, path: str, params: Dict[str, Any],
timestamp: int, nonce: int) -> str:
"""

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,10 @@ def test_basic_connection():
logger.warning("Extracted cookies may be incomplete")
# Initialize the web client
client = MEXCFuturesWebClient(session_cookies=cookies)
client = MEXCFuturesWebClient(api_key='', api_secret='', user_id='', base_url='https://www.mexc.com', headless=True)
# Load cookies into the client's session
for name, value in cookies.items():
client.session.cookies.set(name, value)
# Update headers to include additional parameters from captured requests
client.session.headers.update({
@ -246,7 +249,10 @@ def main():
logger.error("No valid session available")
return
client = MEXCFuturesWebClient(session_cookies=cookies)
client = MEXCFuturesWebClient(api_key='', api_secret='', user_id='', base_url='https://www.mexc.com', headless=True)
# Load cookies into the client's session
for name, value in cookies.items():
client.session.cookies.set(name, value)
if not client.is_authenticated:
logger.error("Failed to authenticate with MEXC")