使用 Playwright 和沙箱模式实现安全的浏览器自动化
我的需求,做一个流式测试环境,一个结点测试用例跑完,进入下一个结点运行。
需要具备下面特性:
1、使用沙箱模式隔离执行环境
2、利用 Playwright 进行浏览器自动化
3. 实现了安全的变量共享机制
4、包含了错误处理和资源清理
5、支持动态代码执行
实现代码片段
const { chromium } = require('playwright')
class Sandbox {
constructor() {
this.sharedVariables = {
browser: null,
page: null,
pageScreenshot: null,
}
// 创建代理对象来自动处理变量存取
this.context = new Proxy(this.sharedVariables, {
get: (target, prop) => target[prop],
set: (target, prop, value) => {
target[prop] = value
return true
},
})
}
// 获取代理对象
getContext() {
return this.context
}
// 保留cleanup方法
async cleanup() {
if (this.context.browser) {
await this.context.browser.close()
this.context.browser = null
this.context.page = null
}
}
}
// 修改 createSandboxExecutor 使用新的 context
const createSandboxExecutor = (code, sandbox) => {
return new Function(
'sandbox',
'chromium',
`
return (async () => {
try {
const context = sandbox.getContext();
// 添加全局对象到上下文
Object.assign(context, {
console,
setTimeout,
setInterval,
clearTimeout,
clearInterval,
chromium,
});
with (context) {
${code}
}
return context;
} catch (error) {
throw new Error('Sandbox execution error: ' + error.message);
}
})()
`
)
}
// 执行代码片段
async function executeCodeSnippet(sandbox, code) {
try {
const executor = createSandboxExecutor(code, sandbox)
return await executor(sandbox, chromium)
} catch (error) {
await sandbox.cleanup()
throw error
}
}
// 优化后的代码片段 1
const code1 = `
browser = await chromium.launch({
headless: false,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
timeout: 10000
});
page = await browser.newPage();
await page.setViewportSize({ width: 1280, height: 800 });
console.log('Browser and page launched');
`
// 优化后的代码片段 2
const code2 = `
try {
await page.goto('https://music.163.com/', { waitUntil: 'networkidle' });
pageScreenshot = Buffer.from(await page.screenshot({
fullPage: true,
quality: 80,
type: 'jpeg'
})).toString('base64');
console.log('Page screenshot captured');
} catch (error) {
console.error('Failed to capture screenshot:', error);
throw error;
}
`
async function run() {
const sandbox = new Sandbox()
try {
await executeCodeSnippet(sandbox, code1)
await executeCodeSnippet(sandbox, code2)
const context = sandbox.getContext()
console.log('截图成功:', !!context.pageScreenshot)
} catch (error) {
console.error('执行错误:', error)
} finally {
await sandbox.cleanup()
}
}
run()