木偶:如何获取节点列表中每个元素的内容?

i.b*_*rod 4 javascript node.js headless-browser google-chrome-devtools puppeteer

我正在尝试实现一些非常琐碎的事情:获取元素列表,然后innerText对每个元素的元素进行操作。

const tweets = await page.$$('.tweet');
Run Code Online (Sandbox Code Playgroud)

据我所知,这将返回一个节点列表,就像document.querySelectorAll()浏览器中的方法一样。

我如何遍历它并得到我所需要的?我尝试了各种东西,例如:

[...tweets].forEach(tweet => {
  console.log(tweet.innerText)
});
Run Code Online (Sandbox Code Playgroud)

Gra*_*ler 13

页面。$$():

您可以使用的组合elementHandle.getProperty(),并jsHandle.jsonValue()获得innerText来自ElementHandle与获得page.$$()

const tweets = await page.$$('.tweet');

for (let i = 0; i < tweets.length; i++) {
  const tweet = await (await tweets[i].getProperty('innerText')).jsonValue();
  console.log(tweet);
}
Run Code Online (Sandbox Code Playgroud)

如果您使用forEach()方法设置,则可以将循环包装在promise中:

const tweets = await page.$$('.tweet');

await new Promise((resolve, reject) => {
  tweets.forEach(async (tweet, i) => {
    tweet = await (await tweet.getProperty('innerText')).jsonValue();
    console.log(tweet);
    if (i === tweets.length - 1) {
      resolve();
    }
  });
});
Run Code Online (Sandbox Code Playgroud)

page.evaluate():

或者,您可以page.$$()完全跳过使用,而使用page.evaluate()

const tweets = await page.evaluate(() => Array.from(document.getElementsByClassName('tweet'), e => e.innerText));

tweets.forEach(tweet => {
  console.log(tweet);
});
Run Code Online (Sandbox Code Playgroud)

  • 我真的很喜欢最后一个例子。我什至都不知道Array.from()方法。 (4认同)

Md.*_*her 7

根据此处的 puppeteer文档,$$不返回节点列表,而是返回ElementHandle数组的承诺。它和NodeList不同。

有几种解决问题的方法。

1.使用内置函数调用循环 page.$$eval

此方法Array.from(document.querySelectorAll(selector))在页面内运行,并将其作为第一个参数传递给pageFunction

所以要获取innerText就像下面这样,

// Find all .tweet, and return innerText for each element, in a array.
const tweets = await page.$$eval('.tweet', element => element.innerText);
Run Code Online (Sandbox Code Playgroud)

2.将传递elementHandlepage.evaluate

无论您从中得到什么,await page.$$('.tweet')都是一个elementHandle数组。如果您进行控制台操作,则会显示JShandleElementHandle取决于类型。

不用费力的解释,它更容易演示。

// let's just call them tweetHandle 
const tweetHandles = await page.$$('.tweet');

// loop thru all handles
for(const tweethandle of tweetHandles){

   // pass the single handle below
   const singleTweet = await page.evaluate(el => el.innerText, tweethandle)

   // do whatever you want with the data
   console.log(singleTweet) 
}
Run Code Online (Sandbox Code Playgroud)

当然,有多种方法可以解决此问题,格兰特·米勒(Grant Miller)在其他答案中也回答了很少的方法。