Playwright调用page.evaluate/page.$eval始终返回undefined问题
Playwright evaluate返回undefined问题排查
问题现象
使用Playwright进行网站数据爬取时,调用page.evaluate/page.$eval相关方法,回调内部可以在浏览器控制台正常打印爬取到的数据,但Node侧(终端/命令行)始终拿到undefined返回值。
问题复现代码如下:
const table= await page.$eval("#txnHistoryList > tbody", (table) => { let arrayData = []; if (table != null) { const rows = Array.from(table.querySelectorAll("tr")); rows.forEach((row, rowIndex) => { if (rowIndex > 1) { const td = row.querySelectorAll("td"); let arrays = {}; if (td.length > 2) { td.forEach((item, tdIndex) => { if (tdIndex == 1) { const date = item.innerText; arrays.date = date ? date.toString().trim() : ""; } if (tdIndex == 2) { const transaction = item.innerText; arrays.transaction = transaction ? transaction.toString().trim() : ""; } if (tdIndex == 4) { const type = item.innerText; arrays.type = type ? type.toString().trim() : ""; } if (tdIndex == 5) { const paymentAmount = item.innerText; arrays.payment_amount = paymentAmount ? paymentAmount.toString().trim() : ""; } if (tdIndex == 6) { const balance = item.innerText; arrays.balance = balance ? balance.toString().trim() : ""; } }); arrayData.push(arrays); } } }); } console.log(arrayData); return arrayData; }); console.log(tableMutasi); const data = { data: tableMutasi, }; res.send(data);
根因与修复方案
1. 核心错误:变量名引用不匹配
代码中page.$eval的返回值被赋值给了table变量,但后续打印、组装接口响应时,使用的是从未定义的tableMutasi变量,非严格模式下未赋值的变量默认值就是undefined,自然拿不到爬取结果。
直接统一变量名即可,比如将接收返回值的变量名改为tableMutasi:
// 把接收返回值的变量从table改为tableMutasi,和后续引用保持一致 const tableMutasi = await page.$eval("#txnHistoryList > tbody", (table) => { // 回调内部逻辑无需修改 let arrayData = []; if (table != null) { const rows = Array.from(table.querySelectorAll("tr")); rows.forEach((row, rowIndex) => { if (rowIndex > 1) { const td = row.querySelectorAll("td"); let arrays = {}; if (td.length > 2) { td.forEach((item, tdIndex) => { if (tdIndex == 1) { const date = item.innerText; arrays.date = date ? date.toString().trim() : ""; } if (tdIndex == 2) { const transaction = item.innerText; arrays.transaction = transaction ? transaction.toString().trim() : ""; } if (tdIndex == 4) { const type = item.innerText; arrays.type = type ? type.toString().trim() : ""; } if (tdIndex == 5) { const paymentAmount = item.innerText; arrays.payment_amount = paymentAmount ? paymentAmount.toString().trim() : ""; } if (tdIndex == 6) { const balance = item.innerText; arrays.balance = balance ? balance.toString().trim() : ""; } }); arrayData.push(arrays); } } }); } return arrayData; }); console.log(tableMutasi); // 此时可以正常打印爬取到的数组 const data = { data: tableMutasi, }; res.send(data);
2. 可选优化:增加DOM渲染等待
如果修正变量名后偶现拿不到数据,是因为目标DOM还没完成动态渲染就执行了爬取逻辑,可以在$eval调用前增加选择器等待:
// 等待目标表格渲染完成再执行爬取,超时时间可根据页面实际加载速度调整 await page.waitForSelector("#txnHistoryList > tbody", {timeout: 10000}); const tableMutasi = await page.$eval(/* 后续逻辑不变 */);
补充说明:Playwright的evaluate类方法回调运行在浏览器上下文,返回值会经过JSON序列化后传回Node侧,只要返回的是可序列化的普通值(字符串、数字、普通对象/数组、null等,不含DOM节点、函数、Symbol、循环引用)就可以正常传输,当前代码返回的纯文本对象数组完全符合序列化要求,不需要额外做转换处理。
内容的提问来源于stack exchange,提问作者Sultan Achmad
相关产品推荐
相关产品推荐

