capture more capcha info
This commit is contained in:
@ -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"
|
||||
|
@ -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,36 +150,58 @@ 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 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: Captcha verification error: {e}")
|
||||
return False
|
||||
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:
|
||||
|
15618
mexc_requests_20250703_021049.json
Normal file
15618
mexc_requests_20250703_021049.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -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")
|
||||
|
Reference in New Issue
Block a user