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

时间:2019-03-01 21:26:45

标签: 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 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();
})();

我的第一个尝试(在注释中)是仅返回锚,以便稍后可以使用其所有属性,但是显然返回的始终是undefined。

如果我访问其属性之一,则map函数包含某些内容。我什至可以创建一个新对象来添加更多属性

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

1 个答案:

答案 0 :(得分:3)

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

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

这对我来说很好

const hrefs = await page.$$eval( 'a', anchors => anchors.map(a => a.href ));
hrefs.forEach( h => console.log(h)); // prints the href

现在,假设您确实想使用HTML元素。最好的方法是使用$$ function

const anchors = await page.$$('a');

anchors不是HTML元素数组,而是ElementHandles数组。 ElementHandle本质上是指向Chromium中元素的指针。

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

const promises = anchors.map(h => page.evaluate(h => h.href, h));
var hrefs = await Promise.all(promises);
hrefs.map(p => console.log(p));

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

相关问题