Spaces:
Sleeping
Sleeping
File size: 5,115 Bytes
33d9697 a016163 8843e8b 33d9697 0c4e80b 33d9697 ca5573b 6665a69 33d9697 8843e8b 3909b11 8843e8b 3909b11 8843e8b 58819e0 3909b11 8843e8b 3909b11 d143045 3909b11 cfb1f28 3909b11 58ca2bd 8843e8b 3909b11 8843e8b 58ca2bd 3909b11 25897e7 d143045 8843e8b 3909b11 8843e8b 3909b11 8843e8b 3909b11 d143045 8843e8b 3909b11 74042c5 3909b11 74042c5 3909b11 ca5573b 8843e8b 33d9697 0c4e80b 33d9697 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
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(`
<html>
<body>
<h2>Remote Live Browser</h2>
<video id="video" autoplay playsinline style="width:1280px;height:720px;border:1px solid black;"></video>
<script>
const ws = new WebSocket('ws://' + location.host + '/ws/${sessionId}');
const video = document.getElementById('video');
ws.onmessage = async (msg) => {
const data = msg.data;
if (data instanceof Blob || typeof data === 'string') {
// Normally you would use WebRTC to stream video
console.log('Message:', data);
}
};
// Capture clicks & send to server
video.addEventListener('click', e => {
const rect = video.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width;
const y = (e.clientY - rect.top) / rect.height;
ws.send(JSON.stringify({ type: 'click', x, y }));
});
</script>
</body>
</html>
`);
});
// Start new session via API
app.get('/api/live', async (req, res) => {
const { url } = req.query;
if (!url) return res.status(400).send('URL is required');
const sessionId = await launchRemoteBrowser(url);
res.send(`✅ Live browser launched. Open <a href="/remote/${sessionId}">this link</a> to interact remotely.`);
});
// WebSocket for remote control
wss.on('connection', (ws, req) => {
const sessionId = req.url.split('/').pop();
const session = sessions[sessionId];
if (!session) return ws.close();
ws.on('message', async (msg) => {
const data = JSON.parse(msg.toString());
const { page } = session;
if (data.type === 'click') {
const { x, y } = data;
const box = await page.viewport();
await page.mouse.click(x * box.width, y * box.height);
}
});
});
// 健康检查端点
app.get('/', (req, res) => {
res.json({ status: 'hii', timestamp: new Date().toISOString() });
});
// 启动服务器
app.listen(PORT, () => {
console.log(`Puppeteer服务器运行在 http://localhost:${PORT}`);
console.log('API端点:');
console.log(' POST /api/generate-pdf - 生成PDF');
console.log(' POST /api/generate-images - 生成图片');
console.log(' GET /api/health - 健康检查');
});
module.exports = app; |