Playwright Library调用context.close()抛出Target closed错误的原因与解决
问题分析与修复方案
错误原因
- 代码里用
rows.forEach(async (row) => { ... })遍历行时,forEach不会等待内部异步操作完成,主线程会直接执行到await context.close()。 - 上下文被提前关闭后,forEach里未完成的异步任务还在尝试获取元素文本,此时浏览器上下文已销毁,就会抛出
locator.innerText: Target closed错误。 - 注释
context.close()后,浏览器进程一直存活,终端会话会因进程未退出而挂起。
修复方案
方案一:使用for...of循环(推荐)
把forEach替换成for...of循环,确保所有异步爬取任务完成后再关闭上下文:
import { firefox } from 'playwright'; (async () => { const browser = await firefox.launch({ headless: true }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://example.com'); const rows = await page .locator('.row') .filter({ hasText: 'some text that some rows have' }) .all(); // 用for...of等待每个异步任务执行完毕 for (const row of rows) { const time = await row.locator('.time').innerText(); const heading = await row.getByText('some common heading').innerText(); console.log(`${time} ${heading}`); } // 所有数据爬取完成后关闭上下文和浏览器 await context.close(); await browser.close(); })();
方案二:使用Promise.all
将所有异步遍历任务包装成Promise数组,等待全部完成后再关闭上下文:
import { firefox } from 'playwright'; (async () => { const browser = await firefox.launch({ headless: true }); const context = await browser.newContext(); const page = await context.newPage(); await page.goto('https://example.com'); const rows = await page .locator('.row') .filter({ hasText: 'some text that some rows have' }) .all(); // 用Promise.all等待所有异步爬取任务完成 await Promise.all(rows.map(async (row) => { const time = await row.locator('.time').innerText(); const heading = await row.getByText('some common heading').innerText(); console.log(`${time} ${heading}`); })); await context.close(); await browser.close(); })();
额外说明
- 修复后建议同时调用
await browser.close(),确保浏览器进程完全终止,避免残留进程导致终端挂起。 - Playwright的元素定位操作依赖活跃的浏览器上下文,必须保证所有元素操作完成后再关闭上下文或浏览器。
内容的提问来源于stack exchange,提问作者Brian Zelip
相关产品推荐
相关产品推荐

