我想将NodeList转换为对象。

H1是object.name,依此类推。

我仍然无法理解page.evaluate()的确切行为。

这就是我需要的:

javascript - Node.js/Puppeteer-JS对象的DOM NodeList-LMLPHP

这是我的尝试之一,但是gp始终未定义:

await page.waitForNavigation();

const selG = 'body > div.content-home > div > div.box > div > div:nth- child(2) > div.col-md-12.no-padding > div:nth-child(4) > div:nth-child(2) > div.col-xs-12';
await page.waitForSelector(selG);
const g = await page.evaluate( (selG) => {
    let gp = document.querySelector(selG); //null
    let n = Array.from(gp.querySelectorAll('h1'), element => element.textContent);
    console.log(n[0]);
    return n;
});

最佳答案

page.evaluate()运行您将其直接传递到浏览器中的函数,它没有启动Puppetter的NodeJS脚本的作用域(访问变量)。

要完全理解,请尝试以下操作:

1-按原样复制您的函数

2-将其包装到一个自调用函数([your-function])()中,结果如下(我又添加了一个console.log(selG);行)

((selG) => {
  console.log(selG); // I added this line
  let gp = document.querySelector(selG);
  let n = Array.from(gp.querySelectorAll('h1'), element => element.textContent);
  console.log(n[0]);
  return n;
})()


3-将其直接粘贴到devtools控制台中

这样一来,(从理解的角度来看)您正在做的事更少,而page.evaluate()的作用就是运行将其直接传递给浏览器的功能。
结果如何?它是Cannot read property 'querySelectorAll' of null,因为如您所述,gp为空。

但是请专心于我添加的console.log(selG); ...它记录undefined ...这是个大问题!

为什么会发生?

看一下函数本身,selG变量不存在,因此let gp = document.querySelector(selG);不能返回任何内容。 selG已定义为用于启动Puppeteer的脚本,但是传递给page.evaluate()的函数将在浏览器中运行,而不是在Node执行上下文中运行。

直接引用Puppeteer文档


  page.evaluate(pageFunction,... args)
  
  pageFunction在页面上下文中要评估的函数
  
  ... args 传递给pageFunction的参数


使用第二个其余的args(由Grant告知)将selG变量传递给函数。

遵循原始代码进行一些更改

await page.waitForNavigation();

const selG = 'body > div.content-home > div > div.box > div > div:nth- child(2) > div.col-md-12.no-padding > div:nth-child(4) > div:nth-child(2) > div.col-xs-12';
await page.waitForSelector(selG);
const g = await page.evaluate( (SELECTOR) => {
    let gp = document.querySelector(SELECTOR);
    let n = Array.from(gp.querySelectorAll('h1'), element => element.textContent);
    console.log(n[0]);
    return n;
}, selG);


请注意:


我将selG变量(最后一行)传递给pageFunction(您的函数)
pageFunction接收一个变量并将其存储到SELECTOR变量中
pageFunction比消耗收到的SELECTOR


总结一下:传递给page.evaluate()的函数不能使用在其外部声明的变量,因为它将被运行到浏览器中,该上下文与NodeJS脚本分离(旨在启动Puppeteer本身)。

试试我的代码,它应该没有任何变化。
让我知道是否足够清楚。

奖金

请记住,如果要使用一些与DOM相关的数据,则至少可以使用三种不同的方法来执行相同的操作。

在下面,您可以找到我的示例,在该示例中,我想读取页面中找到的第一个链接的href属性。第一个示例像您一样使用page.evaluate(),后两个示例向您展示了使用其他一些Puppeteer API的不同方法。

const SELECTOR = '[href]:not([href=""])';
let link;

// compare the three following examples, they all do the same
link = await page.evaluate((sel) =>
    document.querySelector(sel).getAttribute('href')
, SELECTOR);
link = await page.$eval(SELECTOR, el => el.getAttribute('href'));
link = await page.$(SELECTOR).getProperty('href').jsonValue();

关于javascript - Node.js/Puppeteer-JS对象的DOM NodeList,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52918634/

10-09 22:10