Javascript 在本例中使用.map时,为什么必须访问对象属性

Javascript 在本例中使用.map时,为什么必须访问对象属性,javascript,puppeteer,Javascript,Puppeteer,我试图从一个页面中提取所有锚点,但显然我不能只返回相同的对象,我需要访问它的一个属性 这是我的例子: const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('http://www.example.com/');

我试图从一个页面中提取所有锚点,但显然我不能只返回相同的对象,我需要访问它的一个属性

这是我的例子:

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('http://www.example.com/');

    const hrefs = await page.$$eval( 'a', anchors => anchors.map(a => a.href ));
    //const hrefs = await page.$$eval( 'a', anchors => anchors.map(a => a ));

    hrefs.forEach( h => console.log(h)); // prints the href
    //hrefs.forEach( h => console.log(h.href)); // prints undefined
    await browser.close();
})();
我的第一次尝试(在评论中)只是返回锚点,以便以后可以使用它的所有属性,但显然,它总是返回未定义的属性

如果我访问它的一个属性,那么map函数包含一些内容。我甚至可以创建一个新对象来添加更多属性

anchors.map(a => ({href:a.href, hostname:a.hostname}));

重要的是要记住,尽管Puppeter在模糊应用程序和Chromium之间的界限方面做得很好,但当您使用
evaluate
调用获取或发送数据时,会执行序列化/反序列化

长话短说,我发现使用chromium的最佳方法是尝试解决求值函数中的所有问题,并返回所需的所有数据

我觉得这个不错

const hrefs=wait page.$$eval('a',anchors=>anchors.map(a=>a.href));
hrefs.forEach(h=>console.log(h));//打印href
现在,假设您确实想要使用HTML元素。最好的方法是使用

const锚=等待页面。$$('a');
锚定
将不是一个HTML元素数组,而是一个HTML元素数组。ElementHandle基本上是指向Chromium中元素的指针

现在您可以将
ElementHandle
作为参数传递给
evaluate
函数

const promises=anchors.map(h=>page.evaluate(h=>h.href,h));
var hrefs=等待承诺。全部(承诺);
map(p=>console.log(p));

正如您所见,在chromium和您的应用程序之间移动元素并不像您想象的那样透明,但这是可行的。

这有帮助吗
根据文档第页,$eval()不返回ElementHandle或JSHandle:它返回序列化/反序列化过程后函数在第二个参数中返回的值。由于示例中的x是HTML元素,因此不可序列化,因此返回空对象。
source@MadhawaPriyashantha您应该将其作为答案发布。@MadhawaPriyashantha确实如此(请将其作为答案添加)。我尝试使用
$('a')
来代替它,它确实返回ElementHandle,但我不知道如何从这里检索href。它看起来像@OscarRyz。可以在这里使用
JSON.stringify
吗?
(节点:43293)未处理的PromisejectionWarning:TypeError:将循环结构转换为JSON