Spaces:
Runtime error
Runtime error
| const puppeteer = require('puppeteer-extra'); | |
| const StealthPlugin = require('puppeteer-extra-plugin-stealth'); | |
| const FormData = require('form-data'); | |
| const fs = require('fs'); | |
| const path = require('path'); | |
| // Use stealth plugin to avoid detection | |
| puppeteer.use(StealthPlugin()); | |
| // Helper function to wait | |
| const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms)); | |
| // Random delay to appear more human-like | |
| const randomWait = (min, max) => wait(Math.floor(Math.random() * (max - min + 1)) + min); | |
| // Function to upload image to catbox.moe | |
| async function uploadToCatbox(filePath) { | |
| return new Promise((resolve, reject) => { | |
| const form = new FormData(); | |
| form.append('reqtype', 'fileupload'); | |
| form.append('fileToUpload', fs.createReadStream(filePath)); | |
| form.submit('https://catbox.moe/user/api.php', (err, res) => { | |
| if (err) { | |
| reject(err); | |
| return; | |
| } | |
| let data = ''; | |
| res.on('data', chunk => { | |
| data += chunk; | |
| }); | |
| res.on('end', () => { | |
| if (res.statusCode === 200) { | |
| resolve(data.trim()); | |
| } else { | |
| reject(new Error(`Upload failed with status code: ${res.statusCode}`)); | |
| } | |
| }); | |
| res.on('error', reject); | |
| }); | |
| }); | |
| } | |
| // Load cookies from JSON file | |
| function loadCookies(cookieFilePath) { | |
| try { | |
| if (fs.existsSync(cookieFilePath)) { | |
| const cookieData = JSON.parse(fs.readFileSync(cookieFilePath, 'utf8')); | |
| console.log(`β Loaded cookies from: ${cookieFilePath}`); | |
| console.log(` - ${cookieData.cookies.length} cookies found`); | |
| console.log(` - ${Object.keys(cookieData.localStorage || {}).length} localStorage items`); | |
| console.log(` - ${Object.keys(cookieData.sessionStorage || {}).length} sessionStorage items`); | |
| return cookieData; | |
| } else { | |
| console.log(`β οΈ Cookie file not found: ${cookieFilePath}`); | |
| console.log(' Running without cookies...'); | |
| return null; | |
| } | |
| } catch (error) { | |
| console.error(`β Error loading cookies: ${error.message}`); | |
| return null; | |
| } | |
| } | |
| (async () => { | |
| // Look for cookie file in multiple locations | |
| const possibleCookieFiles = [ | |
| path.join(__dirname, 'cookies.json'), | |
| path.join(__dirname, 'betking-cookies.json'), | |
| '/mnt/user-data/uploads/cookies.json' | |
| ]; | |
| let cookieData = null; | |
| for (const cookieFile of possibleCookieFiles) { | |
| cookieData = loadCookies(cookieFile); | |
| if (cookieData) break; | |
| } | |
| const browser = await puppeteer.launch({ | |
| headless: false, | |
| args: [ | |
| '--no-sandbox', | |
| '--disable-setuid-sandbox', | |
| '--disable-blink-features=AutomationControlled', | |
| '--disable-web-security', | |
| '--disable-features=IsolateOrigins,site-per-process', | |
| '--disable-dev-shm-usage', | |
| '--disable-accelerated-2d-canvas', | |
| '--no-first-run', | |
| '--no-zygote', | |
| '--disable-gpu', | |
| '--disable-notifications', | |
| '--disable-popup-blocking' | |
| ], | |
| ignoreHTTPSErrors: true, | |
| defaultViewport: null | |
| }); | |
| const page = await browser.newPage(); | |
| try { | |
| // Enable JavaScript | |
| await page.setJavaScriptEnabled(true); | |
| // Use user agent from cookie file if available | |
| const userAgent = cookieData?.userAgent || 'Mozilla/5.0 (iPhone; CPU iPhone OS 16_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1'; | |
| await page.setUserAgent(userAgent); | |
| console.log(`β Using User Agent: ${userAgent}`); | |
| // Set realistic mobile viewport to match cookies | |
| await page.setViewport({ | |
| width: 390, | |
| height: 844, | |
| isMobile: true, | |
| hasTouch: true, | |
| deviceScaleFactor: 3 | |
| }); | |
| // Set additional headers | |
| const headers = { | |
| 'Accept-Language': 'en-US,en;q=0.9,en-NG;q=0.8', | |
| 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8', | |
| 'Accept-Encoding': 'gzip, deflate, br', | |
| 'Connection': 'keep-alive', | |
| 'Upgrade-Insecure-Requests': '1', | |
| 'Sec-Fetch-Dest': 'document', | |
| 'Sec-Fetch-Mode': 'navigate', | |
| 'Sec-Fetch-Site': 'none', | |
| 'Sec-Fetch-User': '?1', | |
| 'Cache-Control': 'max-age=0' | |
| }; | |
| await page.setExtraHTTPHeaders(headers); | |
| // CRITICAL: Set cookies BEFORE navigating | |
| if (cookieData && cookieData.cookies) { | |
| console.log('\nπͺ Setting cookies BEFORE navigation...'); | |
| // First, navigate to the domain to establish context | |
| await page.goto('https://m.betking.com/', { | |
| waitUntil: 'domcontentloaded', | |
| timeout: 10000 | |
| }).catch(() => { | |
| console.log('Initial navigation for cookie context...'); | |
| }); | |
| // Now set all cookies | |
| for (const cookie of cookieData.cookies) { | |
| try { | |
| await page.setCookie(cookie); | |
| } catch (error) { | |
| console.log(` β οΈ Could not set cookie: ${cookie.name} - ${error.message}`); | |
| } | |
| } | |
| console.log('β Cookies set successfully'); | |
| } | |
| // Override WebDriver and other bot detection properties | |
| await page.evaluateOnNewDocument(() => { | |
| // Remove webdriver property | |
| Object.defineProperty(navigator, 'webdriver', { | |
| get: () => undefined | |
| }); | |
| // Override permissions | |
| const originalQuery = window.navigator.permissions.query; | |
| window.navigator.permissions.query = (parameters) => ( | |
| parameters.name === 'notifications' ? | |
| Promise.resolve({ state: Notification.permission }) : | |
| originalQuery(parameters) | |
| ); | |
| // Add Chrome object | |
| window.chrome = { runtime: {} }; | |
| // Override plugins | |
| Object.defineProperty(navigator, 'plugins', { | |
| get: () => [1, 2, 3, 4, 5] | |
| }); | |
| // Override languages | |
| Object.defineProperty(navigator, 'languages', { | |
| get: () => ['en-US', 'en'] | |
| }); | |
| // Remove automation indicators | |
| delete navigator.__proto__.webdriver; | |
| // Override toString to avoid detection | |
| const originalToString = Function.prototype.toString; | |
| Function.prototype.toString = function() { | |
| if (this === navigator.permissions.query) { | |
| return 'function query() { [native code] }'; | |
| } | |
| return originalToString.call(this); | |
| }; | |
| }); | |
| console.log('\nπ Navigating to the page...'); | |
| await randomWait(500, 1500); | |
| // Navigate to the actual target URL | |
| const response = await page.goto('https://m.betking.com/en-ng?', { | |
| waitUntil: ['networkidle0', 'domcontentloaded'], | |
| timeout: 45000 | |
| }); | |
| const statusCode = response.status(); | |
| console.log(`Response status: ${statusCode}`); | |
| if (statusCode === 403) { | |
| console.log('β οΈ Received 403 Forbidden error.'); | |
| console.log('Trying alternative approach...'); | |
| // Try reloading with cookies already set | |
| await wait(2000); | |
| await page.reload({ waitUntil: ['networkidle0', 'domcontentloaded'] }); | |
| console.log('Page reloaded with cookies'); | |
| } else if (statusCode >= 400) { | |
| console.log(`β οΈ Received error status: ${statusCode}`); | |
| } else { | |
| console.log('β Page loaded successfully'); | |
| } | |
| // Set localStorage and sessionStorage if available | |
| if (cookieData) { | |
| if (cookieData.localStorage && Object.keys(cookieData.localStorage).length > 0) { | |
| console.log('\nπΎ Setting localStorage...'); | |
| await page.evaluate((storage) => { | |
| for (const [key, value] of Object.entries(storage)) { | |
| try { | |
| localStorage.setItem(key, value); | |
| } catch (e) { | |
| console.log('Could not set localStorage item:', key); | |
| } | |
| } | |
| }, cookieData.localStorage); | |
| console.log('β localStorage set successfully'); | |
| } | |
| if (cookieData.sessionStorage && Object.keys(cookieData.sessionStorage).length > 0) { | |
| console.log('\nπΎ Setting sessionStorage...'); | |
| await page.evaluate((storage) => { | |
| for (const [key, value] of Object.entries(storage)) { | |
| try { | |
| sessionStorage.setItem(key, value); | |
| } catch (e) { | |
| console.log('Could not set sessionStorage item:', key); | |
| } | |
| } | |
| }, cookieData.sessionStorage); | |
| console.log('β sessionStorage set successfully'); | |
| } | |
| // One more reload to ensure everything is applied | |
| console.log('\nπ Final reload to apply all data...'); | |
| await page.reload({ waitUntil: ['networkidle0', 'domcontentloaded'] }); | |
| console.log('β Page reloaded'); | |
| } | |
| console.log('\nβ³ Waiting 3 seconds...'); | |
| await wait(3000); | |
| // Take initial screenshot | |
| console.log('\nπΈ Taking initial screenshot...'); | |
| await page.screenshot({ | |
| path: './betking-initial.png', | |
| fullPage: true | |
| }); | |
| console.log('\nπ Looking for the Sign In button...'); | |
| const buttonSelectors = [ | |
| 'button[data-testid="signInButton"]', | |
| 'button#signInButton', | |
| 'button.pill.pill-text.pill-text--inherit.pill--medium.button', | |
| 'button:has-text("Login")', | |
| 'button:has-text("Sign In")' | |
| ]; | |
| let buttonFound = false; | |
| let buttonSelector = null; | |
| for (const selector of buttonSelectors) { | |
| try { | |
| const button = await page.$(selector); | |
| if (button) { | |
| buttonFound = true; | |
| buttonSelector = selector; | |
| console.log(`β Button found using selector: ${selector}`); | |
| const isVisible = await button.isIntersectingViewport(); | |
| console.log(`Button is visible: ${isVisible}`); | |
| if (isVisible) { | |
| console.log('π Clicking the button...'); | |
| await randomWait(200, 800); | |
| await button.click(); | |
| console.log('β Button clicked successfully!'); | |
| } else { | |
| console.log('Button exists but is not visible, scrolling into view...'); | |
| await page.evaluate((sel) => { | |
| document.querySelector(sel).scrollIntoView({ behavior: 'smooth', block: 'center' }); | |
| }, selector); | |
| await wait(500); | |
| await randomWait(200, 800); | |
| await button.click(); | |
| console.log('β Button clicked after scrolling!'); | |
| } | |
| await wait(1500); | |
| break; | |
| } | |
| } catch (error) { | |
| console.log(`Selector ${selector} failed: ${error.message}`); | |
| } | |
| } | |
| if (!buttonFound) { | |
| console.log('β οΈ Button not found with any selector.'); | |
| console.log('This might mean you\'re already logged in or the page structure changed.'); | |
| const allButtons = await page.evaluate(() => { | |
| return Array.from(document.querySelectorAll('button')).slice(0, 20).map(btn => ({ | |
| id: btn.id, | |
| class: btn.className, | |
| text: btn.innerText?.substring(0, 50), | |
| testId: btn.getAttribute('data-testid') | |
| })); | |
| }); | |
| console.log('\nπ Available buttons on page (first 20):'); | |
| console.log(JSON.stringify(allButtons, null, 2)); | |
| } | |
| console.log('\nπΈ Taking final screenshot...'); | |
| await page.screenshot({ | |
| path: './betking-final.png', | |
| fullPage: true | |
| }); | |
| console.log('β Screenshot saved to betking-final.png'); | |
| // Upload screenshot to catbox | |
| console.log('\nπ€ Uploading screenshot to Catbox...'); | |
| try { | |
| const catboxUrl = await uploadToCatbox('./betking-final.png'); | |
| console.log('β Upload successful!'); | |
| console.log('\nπ Download link:'); | |
| console.log(catboxUrl); | |
| console.log('\nπ Direct link (copy this):'); | |
| console.log(catboxUrl); | |
| } catch (uploadError) { | |
| console.error('β Failed to upload to Catbox:', uploadError.message); | |
| console.log('Screenshot is still saved locally at: ./betking-final.png'); | |
| } | |
| } catch (error) { | |
| console.error('\nβ Error occurred:', error.message); | |
| console.error('Stack trace:', error.stack); | |
| try { | |
| await page.screenshot({ | |
| path: './betking-error.png', | |
| fullPage: true | |
| }); | |
| console.log('Error screenshot saved to betking-error.png'); | |
| } catch (screenshotError) { | |
| console.error('Could not take error screenshot:', screenshotError.message); | |
| } | |
| } finally { | |
| await browser.close(); | |
| console.log('\nβ Browser closed'); | |
| } | |
| })(); |