使用Playwright循环跳转页面时返回空数组问题求助
问题分析与解决方案
问题根源
- 环境混淆:
evaluateAll的回调函数运行在浏览器页面的JavaScript环境中,无法直接调用Playwright的Node.js端API(比如context.newPage()),这是导致代码异常的核心原因。 - 异步未等待:
map中使用async函数会生成Promise数组,但你没有用Promise.all等待所有异步任务完成就直接返回data,此时数组还没被填充,自然为空。 - 变量名错误:多处出现变量名拼写错误(比如把
newPage写成newPageData,contentData未正确赋值给rowObject.content)。 - 变量不一致:最后打印的
gamesData实际定义的变量是tableData。
修正后的代码
const browserType = "chromium"; const url = "https://page-with-table.html"; const browser = await playwright[browserType].launch(); const context = await browser.newContext(); const page = await context.newPage(); await page.goto(url); const tableRowsLocator = page.locator("table tr"); // 第一步:在浏览器环境提取所有行的基础数据(rowData和目标URL),返回给Node.js端 const rowBaseData = await tableRowsLocator.evaluateAll((tableRows) => { return tableRows.map(tableRow => { const rowDataEl = tableRow.querySelector('td[data="rowData"]'); const urlEl = tableRow.querySelector('td[data="url"] a'); return { rowData: rowDataEl?.textContent.trim() || '', targetUrl: urlEl?.getAttribute("href") || '' }; }); }); // 第二步:在Node.js端逐个处理URL,打开新页面抓取内容 const tableData = []; for (const baseData of rowBaseData) { if (!baseData.targetUrl) { tableData.push({...baseData, content: "无目标URL"}); continue; } const newPage = await context.newPage(); try { await newPage.goto(baseData.targetUrl); // 直接用Playwright内置方法获取文本,无需额外evaluate const contentData = await newPage.locator("#content").textContent(); tableData.push({ ...baseData, content: contentData?.trim() || "无内容" }); } catch (err) { console.error(`抓取${baseData.targetUrl}失败:`, err); tableData.push({ ...baseData, content: "抓取失败" }); } finally { await newPage.close(); // 无论成功失败,都关闭页面释放资源 } } await browser.close(); console.log(tableData);
关键修正点
- 拆分逻辑:把浏览器端的基础数据提取和Node.js端的异步页面跳转分开,避免环境混淆。
- 同步等待:用
for...of循环替代map,确保每个异步任务完成后再处理下一个,保证数组被正确填充。 - 错误处理:增加异常捕获,单个URL抓取失败不会中断整个流程,同时保留基础数据。
- 变量规范:修正所有变量名错误,避免命名冲突。
内容的提问来源于stack exchange,提问作者Dachan
相关产品推荐
相关产品推荐

