Spaces:
Runtime error
Runtime error
| const express = require('express'); | |
| const puppeteer = require('puppeteer'); | |
| const app = express(); | |
| const port = 7860; | |
| const colorCodes = { | |
| reset: "\x1b[0m", | |
| green: "\x1b[32m" | |
| }; | |
| let requestCounter = 0; | |
| let browserInstance; | |
| app.use(express.json()); | |
| app.get('/api', async (req, res) => { | |
| const { url, time } = req.query; | |
| const timestamp = new Date().toLocaleString(); | |
| const start = Date.now(); | |
| const requestId = ++requestCounter; | |
| let delayTime = parseInt(time) || 0; | |
| let delayDuration = 0; | |
| try { | |
| if (!isNaN(delayTime) && delayTime >= 0 && delayTime <= 60) { | |
| const formattedURL = formatURL(url); | |
| if (!formattedURL) { | |
| console.log(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] URL格式错误 ${colorizeURLAndMS(url)}`); | |
| return res.status(400).send(`请求错误:URL格式错误`); | |
| } | |
| console.log(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] 请求截图 ${delayTime} ${colorizeURLAndMS(formattedURL)}`); | |
| const browser = await getBrowserInstance(); | |
| const page = await browser.newPage(); | |
| await page.goto(formattedURL, { timeout: 60000 }); | |
| //await page.setViewport({ width: 1920, height: 1080 }); | |
| if (delayTime > 0) { | |
| await new Promise(resolve => setTimeout(resolve, delayTime * 1000)); | |
| delayDuration = Date.now() - start - delayTime * 1000; | |
| } | |
| const screenshot = await page.screenshot({ fullPage: true }); | |
| res.set('Content-Type', 'image/png'); | |
| res.send(screenshot); | |
| // 关闭页面 | |
| await page.close(); | |
| } else { | |
| console.log(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] 延时错误 ${colorizeURLAndMS(url)}`); | |
| res.status(400).send(`请求错误:延时时间不正确!仅支持0到60秒之间`); | |
| } | |
| const end = Date.now(); | |
| const totalTime = end - start - delayDuration; | |
| console.log(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] 处理完成 ${colorCodes.green}${totalTime}ms${colorCodes.reset}`); | |
| // 记录完整请求信息 | |
| console.log(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] ${JSON.stringify(req.query)}`); | |
| } catch (error) { | |
| console.error(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] 处理错误:${error}`); | |
| res.status(500).send(`处理错误:${error}`); | |
| // 记录完整请求信息 | |
| console.log(`[${colorizeTimestamp(timestamp)}] [${colorCodes.green}${requestId}${colorCodes.reset}] ${JSON.stringify(req.query)}`); | |
| } | |
| }); | |
| app.listen(port, () => { | |
| console.log(`服务已运行 监听端口${port}`); | |
| }); | |
| async function getBrowserInstance() { | |
| if (!browserInstance) { | |
| browserInstance = await puppeteer.launch({ | |
| headless: "new", | |
| args: [ | |
| '--disable-gpu', | |
| '--disable-dev-shm-usage', | |
| '--disable-setuid-sandbox', | |
| '--no-first-run', | |
| '--no-sandbox', | |
| '--no-zygote', | |
| '--single-process', | |
| '--lang=zh-CN,zh' | |
| ], | |
| }); | |
| } | |
| const browser = await browserInstance; | |
| await browser.pages().then(async (pages) => { | |
| if (pages.length > 0) { | |
| await pages[0].evaluateOnNewDocument(() => { | |
| Object.defineProperty(navigator, "language", { | |
| get: function() { | |
| return "zh-CN"; | |
| } | |
| }); | |
| Object.defineProperty(navigator, "languages", { | |
| get: function() { | |
| return ["zh-CN", "zh"]; | |
| } | |
| }); | |
| }); | |
| } | |
| }); | |
| return browserInstance; | |
| } | |
| function formatURL(url) { | |
| const regex = /^(?:https?:\/\/)?([\w.-]+\.\w+(\.\w+)?)(.*)$/; | |
| const match = url.match(regex); | |
| if (match) { | |
| const domain = match[1]; | |
| const path = match[3] || '/'; | |
| return `https://${domain}${path}`; | |
| } | |
| return null; | |
| } | |
| function colorizeTimestamp(text) { | |
| const regex = /\[(.*?)\]/g; | |
| return text.replace(regex, (match, p1) => { | |
| return `[${colorCodes.green}${p1}${colorCodes.reset}]`; | |
| }); | |
| } | |
| function colorizeURLAndMS(text) { | |
| const regex = /(?:https?:\/\/[^\s]+)/g; | |
| const msRegex = /\b\d+ms\b/g; | |
| return text | |
| .replace(regex, (match) => { | |
| return colorCodes.green + match + colorCodes.reset; | |
| }) | |
| .replace(msRegex, (match) => { | |
| return colorCodes.green + match + colorCodes.reset; | |
| }); | |
| } |