Created
May 15, 2025 18:02
-
-
Save Hricha-Shandily/8510495f597fc70a8d7d4294c3120878 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * Browser Bot Script | |
| * ----------------- | |
| * | |
| * This script uses Puppeteer to simulate real browser behavior by: | |
| * - Using random viewport sizes and user agents | |
| * - Simulating human-like scrolling (50% chance) | |
| * - Clicking FAQ links (30% chance) | |
| * | |
| * Usage: | |
| * | |
| * TARGET_URL=https://example.com node index.js | |
| * | |
| */ | |
| const puppeteer = require("puppeteer"); | |
| // Common user agents for modern browsers | |
| const USER_AGENTS = [ | |
| // "PostmanRuntime/7.43.4", | |
| "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", | |
| "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36", | |
| "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0", | |
| "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Safari/605.1.15", | |
| ]; | |
| // Common screen resolutions | |
| // Function to add random variation to viewport dimensions | |
| function addRandomVariation(size) { | |
| const variation = () => Math.floor(Math.random() * 81) - 40; // Random number between -40 and +40 | |
| return { | |
| width: size.width + variation(), | |
| height: size.height + variation(), | |
| }; | |
| } | |
| const BASE_VIEWPORT_SIZES = [ | |
| { width: 1920, height: 1080 }, | |
| { width: 1366, height: 768 }, | |
| { width: 1536, height: 864 }, | |
| { width: 1440, height: 900 }, | |
| { width: 1280, height: 720 }, | |
| ]; | |
| // Common languages and regions | |
| const LANGUAGES = [ | |
| "en-US,en;q=0.9", | |
| "en-GB,en;q=0.9", | |
| "es-ES,es;q=0.9,en;q=0.8", | |
| "fr-FR,fr;q=0.9,en;q=0.8", | |
| "de-DE,de;q=0.9,en;q=0.8", | |
| ]; | |
| function getRandomElement(array) { | |
| return array[Math.floor(Math.random() * array.length)]; | |
| } | |
| async function visitPage(url) { | |
| let browser; | |
| try { | |
| // Launch the browser with specific configurations | |
| browser = await puppeteer.launch({ | |
| headless: "new", | |
| args: [ | |
| "--no-sandbox", | |
| "--disable-setuid-sandbox", | |
| "--disable-blink-features=AutomationControlled", | |
| "--disable-infobars", | |
| "--window-position=0,0", | |
| "--ignore-certifcate-errors", | |
| "--ignore-certifcate-errors-spki-list", | |
| "--disable-notifications", | |
| "--disable-geolocation", | |
| ], | |
| }); | |
| // Get random configurations | |
| const userAgent = getRandomElement(USER_AGENTS); | |
| const baseViewport = getRandomElement(BASE_VIEWPORT_SIZES); | |
| const viewport = addRandomVariation(baseViewport); | |
| const language = getRandomElement(LANGUAGES); | |
| // Create a new page | |
| const page = await browser.newPage(); | |
| // Configure browser fingerprint | |
| await page.setUserAgent(userAgent); | |
| await page.setViewport({ | |
| ...viewport, | |
| deviceScaleFactor: 1, | |
| hasTouch: false, | |
| isLandscape: true, | |
| }); | |
| // Set common headers | |
| await page.setExtraHTTPHeaders({ | |
| "Accept-Language": language, | |
| Accept: | |
| "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", | |
| "Accept-Encoding": "gzip, deflate, br", | |
| DNT: "1", | |
| Connection: "keep-alive", | |
| "Upgrade-Insecure-Requests": "1", | |
| "Sec-Fetch-Dest": "document", | |
| "Sec-Fetch-Mode": "navigate", | |
| "Sec-Fetch-Site": "none", | |
| "Sec-Fetch-User": "?1", | |
| }); | |
| // Mask webdriver | |
| await page.evaluateOnNewDocument(() => { | |
| // Overwrite the navigator | |
| Object.defineProperty(navigator, "webdriver", { | |
| get: () => false, | |
| }); | |
| // Overwrite chrome properties | |
| window.chrome = { | |
| runtime: {}, | |
| }; | |
| // Overwrite permissions | |
| const originalQuery = window.navigator.permissions.query; | |
| window.navigator.permissions.query = (parameters) => | |
| parameters.name === "notifications" | |
| ? Promise.resolve({ state: Notification.permission }) | |
| : originalQuery(parameters); | |
| }); | |
| console.log(`Navigating to ${url} with User-Agent: ${userAgent}`); | |
| // Navigate to the URL with extended options | |
| await page.goto(url, { | |
| waitUntil: ["networkidle0", "domcontentloaded", "load"], | |
| timeout: 30000, | |
| }); | |
| // Add random delay to simulate human behavior | |
| await new Promise((resolve) => | |
| setTimeout(resolve, Math.floor(Math.random() * 2000) + 1000), | |
| ); | |
| console.log("Page loaded successfully!"); | |
| const title = await page.title(); | |
| const metrics = await page.metrics(); | |
| // 50% chance of random scrolling | |
| if (Math.random() < 0.5) { | |
| console.log("Starting random scrolling..."); | |
| const startTime = Date.now(); | |
| while (Date.now() - startTime < 2000) { | |
| const scrollAmount = Math.floor(Math.random() * 100) - 30; // Random scroll between -30 and +70 | |
| await page.evaluate((scrollY) => { | |
| window.scrollBy(0, scrollY); | |
| }, scrollAmount); | |
| await new Promise((resolve) => setTimeout(resolve, 100)); // Small delay between scrolls | |
| } | |
| } else { | |
| console.log("Skipping scrolling for this session"); | |
| } | |
| // 30% chance of clicking FAQ link | |
| if (Math.random() < 0.3) { | |
| console.log("Looking for FAQ link..."); | |
| try { | |
| // Wait for any FAQ link to be available | |
| await page.waitForSelector('a[href="/faq"], a[href="#/faq"]', { | |
| timeout: 5000, | |
| }); | |
| // Click the first matching FAQ link | |
| await page.click('a[href="/faq"], a[href="#/faq"]'); | |
| console.log("Clicked FAQ link successfully"); | |
| // Wait for navigation or content change | |
| await new Promise((resolve) => setTimeout(resolve, 2000)); | |
| } catch (error) { | |
| console.log("Could not find or click FAQ link:", error.message); | |
| } | |
| } else { | |
| console.log("Skipping FAQ click for this session"); | |
| } | |
| console.log("Page Title:", title); | |
| console.log("Page Metrics:", { | |
| JSHeapUsedSize: Math.round(metrics.JSHeapUsedSize / 1024 / 1024) + "MB", | |
| Nodes: metrics.Nodes, | |
| Scripts: metrics.Scripts, | |
| }); | |
| } catch (error) { | |
| console.error("An error occurred:", error); | |
| } finally { | |
| // Cleanup | |
| if (browser) { | |
| await browser.close(); | |
| console.log("Browser closed."); | |
| } | |
| } | |
| } | |
| // Export the visitPage function | |
| module.exports = { | |
| visitPage, | |
| }; | |
| // Run directly if this is the main module | |
| if (require.main === module) { | |
| const targetUrl = process.env.TARGET_URL || "http://localhost:4321"; | |
| visitPage(targetUrl).catch(console.error); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment