const express = require('express'); const path = require('path'); const fs = require('fs'); const puppeteer = require('puppeteer'); const stream = require('puppeteer-stream'); const WebSocket = require('ws'); const http = require('http'); const app = express(); const PORT = 7860; // 中间件 app.use(express.json({ limit: '40mb' })); app.use(express.static('.')); const server = http.createServer(app); const wss = new WebSocket.Server({ server }); // CORS支持 app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization'); if (req.method === 'OPTIONS') { res.sendStatus(200); } else { next(); } }); const sessions = {}; // store active sessions // Launch Puppeteer page and create remote session async function launchRemoteBrowser(url) { const browser = await puppeteer.launch({ executablePath: '/opt/google/chrome/chrome', headless: 'new', // fully headless args: [ '--no-sandbox', '--disable-setuid-sandbox', '--disable-web-security', '--disable-blink-features=AutomationControlled' ] }); const page = (await browser.pages())[0] || await browser.newPage(); await page.setViewport({ width: 1280, height: 900 }); await page.setUserAgent( 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36' ); // Anti-bot & anti-devtools bypass await page.evaluateOnNewDocument(() => { Object.defineProperty(navigator, 'webdriver', { get: () => false }); Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3] }); Object.defineProperty(navigator, 'languages', { get: () => ['en-US', 'en'] }); window.chrome = { runtime: {} }; window.console.debug = () => {}; window.console.log = () => {}; ['oncontextmenu', 'onkeydown', 'onkeyup', 'onbeforeunload'].forEach(e => window[e] = null); }); await page.setRequestInterception(true); page.on('request', req => req.continue()); // allow all requests await page.goto(url, { waitUntil: 'load', timeout: 60000 }); // Start streaming const mediaStream = await stream.getStream(page, { audio: false, video: true }); // Generate session ID const sessionId = Math.random().toString(36).substring(2, 12); sessions[sessionId] = { browser, page, mediaStream }; return sessionId; } // Serve web page to connect to live session app.get('/remote/:sessionId', (req, res) => { const { sessionId } = req.params; if (!sessions[sessionId]) return res.status(404).send('Session not found'); // Simple client page that connects to WebSocket res.send(`