Puppeteer使用setInterval时报会话关闭错误 如何实现页面持久驻留?
问题解答
错误原因
你的代码逻辑执行顺序存在问题:
setInterval属于异步非阻塞API,注册完成后主线程不会等待其回调执行,会直接继续向下运行- try块代码执行完毕后,会直接执行你写在try语句外的
await page.close()和await browser.close(),直接销毁页面和浏览器实例 - 等setInterval的回调首次触发时,操作的已经是被销毁的实例,自然会抛出会话关闭的错误,和你设置的间隔时长没有任何关系。
修复方案
1. 移除错误位置的关闭逻辑
你需要永久保持页面运行,所以不要主动调用page.close()和browser.close(),直接删除这两行代码即可。
2. 替换setInterval为递归setTimeout
setInterval不会等待上一次回调内的异步任务执行完成就会触发下一次,容易出现并发操作冲突,使用递归的setTimeout可以保证上一轮任务完全执行完毕后,再等待指定间隔触发下一轮任务,更稳妥。
修复后完整代码
const puppeteer = require('puppeteer'); const creds = require("./creds.json"); (async () => { try { const browser = await puppeteer.launch({ // 可选配置,避免长时间运行出现兼容性问题 defaultViewport: null, args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); await page.goto('https://www.online-messenger.com'); await goToChats(page); await page.waitForSelector('div[aria-label="Chats"]'); // 定义轮询任务 const pollTask = async () => { try { let index = 1; while (index <= 5) { if (await isUnread(page, index)) { await page.click(`#local-chat`); await page.waitForSelector('div[role="main"]', { timeout: 15000 }); let conversationName = await getConversationName(page); if (isChat(conversationName)) { await writeMessage(page); } } index++; } } catch (taskErr) { // 单轮任务异常不中断后续轮询,仅打印错误 console.error('单轮任务执行异常:', taskErr); } finally { // 本轮任务执行完成后,30秒后启动下一轮 setTimeout(pollTask, 30000); } } // 启动第一轮任务 await pollTask(); // 阻塞主进程,避免程序退出 await new Promise(() => {}); } catch (e) { console.error('主流程运行异常:', e); // 主流程异常时可根据需求添加重启逻辑 } })();
额外优化建议
- 可以在首次登录完成后调用
await page.cookies()将登录态导出存储到本地文件,下次启动浏览器时直接注入cookie,就算浏览器意外崩溃也不需要重复登录 - 给所有
waitForSelector添加超时时间配置,避免单步操作卡住整轮任务 - 可以监听
page.error和browser.disconnected事件,触发时自动重启浏览器实例,提升长时间运行的稳定性 - 如果担心页面长时间运行卡顿,可以每间隔几小时调用一次
page.reload()刷新页面,只要登录态有效就不需要重新登录
内容的提问来源于stack exchange,提问作者priortt
相关产品推荐
相关产品推荐

