NextJs中使用Puppeteer爬取时遭遇执行上下文销毁错误的求助
解决Puppeteer导航导致执行上下文销毁的问题并实现全站搜索爬取逻辑
错误原因分析
你遇到的Error: Execution context was destroyed, most likely because of a navigation.是因为触发搜索后页面发生跳转,原页面的执行上下文被销毁,但代码未正确等待导航完成就继续操作,导致后续调用失效。
核心修复与优化点
- 循环处理歌曲列表:替换硬编码的歌曲名,遍历传入的
songs数组逐个处理 - 等待导航完成:触发搜索和点击结果后,用
waitForNavigation等待页面加载完成,避免操作已失效的上下文 - 修正元素交互逻辑:用
click()替代press('Enter')触发搜索和点击结果,更符合页面正常交互流程 - 修复DOM选择器错误:
document.querySelectorAll的参数应为逗号分隔的选择器字符串,而非多个独立参数 - 优化数据提取逻辑:精准定位目标元素,减少无效DOM遍历
修正后的代码
urlScrapper.js
import InfringementFinder from './InfringementFinder.js'; const songs = ['Artist Name - Song Name', 'Artist Name - Song Name']; const irscCodes = ['XXXXXXXXXX', 'XXXXXXXXXX']; // 修正:字符串需添加引号 InfringementFinder(songs, irscCodes).then(() => { console.log('Search complete!'); }).catch((error) => { console.error(error); });
InfringementFinder.js
import puppeteer from 'puppeteer'; const InfringementFinder = async (songs, irscCodes) => { const browser = await puppeteer.launch({ headless: false }); // 开启可视化模式方便调试 const page = await browser.newPage(); const mainPage = 'https://example.com/'; try { await page.goto(mainPage, { waitUntil: 'networkidle2' }); // 等待页面资源加载完成 // 遍历每首歌曲执行搜索爬取 for (const [index, song] of songs.entries()) { const irscCode = irscCodes[index]; console.log(`正在搜索:${song}`); // 清空搜索框并输入当前歌曲名 await page.$eval('.search-field', el => el.value = ''); await page.type('.search-field', song, { delay: 100 }); // 模拟真实输入速度,降低被拦截风险 // 触发搜索并等待结果页面加载完成 await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle2' }), page.click('.search-submit') ]); // 等待搜索结果元素出现,超时则跳过当前歌曲 const entryContent = await page.waitForSelector('.g1-frame', { timeout: 5000 }).catch(() => null); if (!entryContent) { console.log(`未找到歌曲${song}的搜索结果`); continue; } // 点击搜索结果并等待详情页加载完成 await Promise.all([ page.waitForNavigation({ waitUntil: 'networkidle2' }), entryContent.click() ]); // 提取歌曲信息与下载链接 const data = await page.evaluate((targetSong, targetIrsc) => { // 定位包含目标歌曲名的元素 const trackElement = document.querySelector(`*:contains("${targetSong}")`); const trackName = trackElement ? trackElement.innerText.trim() : '未知歌曲名'; // 提取有效下载链接 const downloadLinks = Array.from(document.querySelectorAll('.dl-btn')) .map(link => link.getAttribute('href')) .filter(href => href); return { songName: targetSong, irscCode: targetIrsc, trackName, downloadLinks }; }, song, irscCode); // 将外部变量作为参数传入evaluate,避免上下文隔离问题 console.log(`歌曲${song}爬取结果:`, data); // 可在此添加数据保存(文件/数据库)逻辑 } } catch (error) { console.error('爬取过程出错:', error); } finally { await browser.close(); } }; export default InfringementFinder;
额外提示
- 调试阶段保持
headless: false,可直观查看页面操作流程 waitUntil: 'networkidle2'确保页面资源加载稳定后再执行下一步,减少因页面未加载完成导致的错误- 用
Promise.all同时触发操作和等待导航,避免竞态条件
内容的提问来源于stack exchange,提问作者kelvin
相关产品推荐
相关产品推荐

