如何从 DOM 获取所有链接?

How to get all links from the DOM?

根据https://github.com/GoogleChrome/puppeteer/issues/628,我应该能够从中获取所有links行:

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

但是当我尝试简单的时候:

console.log(hrefs)

我只得到:

http://example.de/index.html

... 作为输出,这意味着它只能找到 1 link?但是页面在源码中肯定有12link/DOM。为什么找不到所有?

最小示例:

'use strict';
const puppeteer = require('puppeteer');

crawlPage();

function crawlPage() {
    (async () => {
 
 const args = [
            "--disable-setuid-sandbox",
            "--no-sandbox",
            "--blink-settings=imagesEnabled=false",
        ];
        const options = {
            args,
            headless: true,
            ignoreHTTPSErrors: true,
        };

 const browser = await puppeteer.launch(options);
        const page = await browser.newPage();
 await page.goto("http://example.de", {
            waitUntil: 'networkidle2',
            timeout: 30000
        });
     
 const hrefs = await page.$eval('a', a => a.href);
        console.log(hrefs);
  
        await page.close();
 await browser.close();
  
    })().catch((error) => {
        console.error(error);
    });;

}

在您的示例代码中,您使用的是 page.$eval,而不是 page.$$eval。由于前者使用 document.querySelector 而不是 document.querySelectorAll,因此您描述的行为是预期的行为。

此外,您应该在 $$eval 参数中更改 pageFunction

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

page.$$eval() 方法在页面内运行 Array.from(document.querySelectorAll(selector)) 并将其作为第一个参数传递给页面函数。

由于您的示例中的 a 表示一个数组,您需要指定要获取数组的哪个元素 href from, or you will need to map 所有 href 属性数组。

page.$$eval()

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

或者,您也可以使用page.evaluate() or a combination of page.$$(), elementHandle.getProperty(), or jsHandle.jsonValue()来实现页面所有链接的数组。

page.evaluate()

const hrefs = await page.evaluate(() => {
  return Array.from(document.getElementsByTagName('a'), a => a.href);
});

page.$$() / elementHandle.getProperty() / jsHandle.jsonValue()

const hrefs = await Promise.all((await page.$$('a')).map(async a => {
  return await (await a.getProperty('href')).jsonValue();
}));