Puppeteer监控商品按钮的脚本在VSCode调试模式正常,Node.js直接运行时触发TargetCloseError错误
Puppeteer监控商品按钮的脚本在VSCode调试模式正常,Node.js直接运行时触发TargetCloseError错误
看起来你遇到的问题挺典型的——调试模式下脚本能正常跑,但直接用Node执行就会触发TargetCloseError。本质原因是调试时执行速度慢,页面有足够时间完成状态同步;但正常运行时循环重载的节奏太快,导致浏览器页面的CDP会话还没就绪就被强制操作,最终会话被意外关闭。
咱们来调整一下脚本,解决这个问题:
修复后的代码
const puppeteer = require('puppeteer'); (async () => { // Launch a new browser instance const browser = await puppeteer.launch({ headless: false }); let page = await browser.newPage(); // URL of the page to load const url = 'https://www.bestbuy.com/site/xfx-mercury-amd-radeon-rx-7900-xtx-magnetic-air-24gb-gddr6-pci-express-4-0-gaming-graphics-card-black-red/6588232.p?skuId=6588232'; // Open the page await page.goto(url, { waitUntil: 'networkidle2' }); // Define the selector for the button you are looking for const buttonSelector = '.c-button.c-button-primary.c-button-lg.c-button-block.c-button-icon.c-button-icon-leading.add-to-cart-button'; // 增加最大重试次数,避免无限循环 const maxRetries = 20; let retryCount = 0; // Wait for the button to appear or reload the page while (retryCount < maxRetries) { try { // 确保页面未被关闭,如果已关闭则重新创建 if (page.isClosed()) { console.log('Page was closed, creating new page...'); page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle2' }); } // Try to find the button await page.waitForSelector(buttonSelector, { visible: true, timeout: 30000 }); console.log('Button found!'); break; // Exit the loop once the button is found } catch (error) { if (error.name === 'TimeoutError') { console.log(`Button not found (retry ${retryCount + 1}/${maxRetries}), reloading the page...`); retryCount++; // 增加短暂等待,避免频繁重载触发反爬 await page.waitForTimeout(1000); // 重载页面,等待网络空闲确保状态稳定 await page.reload({ waitUntil: 'networkidle2' }); } else { console.log('Unexpected error:', error.message); // 针对会话关闭错误,直接重新创建页面 if (error.message.includes('Session closed')) { console.log('Recreating page due to session error...'); page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle2' }); } retryCount++; } } } if (retryCount >= maxRetries) { console.log(`Reached max retries (${maxRetries}), stopping...`); } // Close the browser await browser.close(); })();
关键修改点说明
- 增加最大重试次数:避免无限循环给浏览器和目标网站造成压力,也防止脚本意外死循环
- 页面状态前置检查:在每次尝试前确认页面是否正常打开,若已关闭则重新创建页面,避免在无效资源上执行操作
- 优化重载逻辑:
- 重载前增加1秒等待,模拟人类操作节奏,同时避免过于频繁的请求触发反爬机制
- 重载时使用
waitUntil: 'networkidle2',确保页面完全加载、网络稳定后再进行下一轮检查
- 精细化错误处理:区分超时错误和会话关闭错误,针对不同异常场景做针对性修复,比如会话关闭时直接重建页面
- 调整等待超时:把
waitForSelector的超时从50秒降到30秒,减少会话资源的长期占用
额外注意事项
- BestBuy有严格的反爬机制,频繁刷新页面可能会被IP封禁,建议把固定等待改成随机延迟(比如
await page.waitForTimeout(Math.random() * 2000 + 1000)) - 可以配合
puppeteer-extra和puppeteer-extra-plugin-stealth插件绕过反爬检测,降低被识别为爬虫的概率 - 电商网站的页面结构可能会随时更新,记得定期检查按钮选择器的有效性
备注:内容来源于stack exchange,提问作者Justin Lin
相关产品推荐
相关产品推荐

