Puppeteer中evaluate作用域外无法获取数组值的原因排查
问题
使用Puppeteer开发Node.js程序时,尝试获取id为myid的div元素并处理其子元素。在page.evaluate()内部,console.log()能在浏览器控制台输出正确值,但向传入的arrayOfMailNames数组执行push操作后,Node.js终端打印该数组长度为0,且无任何报错或警告。相关函数代码如下:
async function observer(){ await page.waitForFunction("document.querySelectorAll(\"div[id='myid']\").length > 1") var arrayOfMailNames = [] await page.evaluate((arrayOfMailNames) => { var parentDiv = document.querySelectorAll("div[id='myid']"); for(var t = 0; t < parentDiv.length; t++){ if(parentDiv[t].getAttribute('id') !=null){ console.log(` ${parentDiv[t].split(";")[0]}`); //浏览器控制台输出正确值 arrayOfMailNames.push(parentDiv[t].split(";")[0]); //似乎没有生效 } } }, arrayOfMailNames) console.log(`${arrayOfMailNames.length}`); //Node.js终端输出0,不符合预期 }
请问导致此问题的原因是什么?
原因分析
- Puppeteer的
page.evaluate()运行在浏览器的上下文环境中,而你定义的arrayOfMailNames属于Node.js的上下文,两个环境完全隔离,数据无法直接共享。 - 当你把
arrayOfMailNames作为参数传给page.evaluate()时,Puppeteer会对数组做**序列化(JSON.stringify)**处理,相当于传递了一个副本。你在浏览器上下文里对副本执行push操作,根本不会影响到Node.js上下文里的原数组。 - 另外原代码还有个隐藏问题:
parentDiv[t]是DOM元素对象,直接调用split(";")逻辑不成立,浏览器控制台能输出是因为隐式转换了,实际应该先取元素的文本内容(比如textContent)或HTML内容再执行split。
正确的做法是在page.evaluate()内部收集数据后返回,再在Node.js上下文接收返回值:
async function observer(){ await page.waitForFunction("document.querySelectorAll(\"div[id='myid']\").length > 1") // 接收evaluate返回的数组 const arrayOfMailNames = await page.evaluate(() => { const result = []; const parentDiv = document.querySelectorAll("div[id='myid']"); for(let t = 0; t < parentDiv.length; t++){ if(parentDiv[t].getAttribute('id') != null){ const item = parentDiv[t].textContent.split(";")[0]; console.log(` ${item}`); result.push(item); } } return result; // 返回收集好的数组 }) console.log(`${arrayOfMailNames.length}`); // 现在能得到正确长度 }
内容的提问来源于stack exchange,提问作者C.Unbay
相关产品推荐
相关产品推荐

