Node.js/Puppeteer - DOM NodeList 转 JS 对象
Node.js/Puppeteer - DOM NodeList to JS Object
我想将 NodeList 转换为对象。
H1 为 object.name
依此类推。
我仍然无法理解 page.evaluate()
的确切行为。
这是我需要的:
这是我的尝试之一,但 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;
});
您必须使用以下方法将变量 selG
传递给 page.evaluate()
:
const g = await page.evaluate(selG => { /* ... */ }, selG);
Note: Notice the that I added selG
as a separate argument after the page function.
page.evaluate(pageFunction, ...args)
这应该可以防止 document.querySelector(selG)
返回 null
。
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);
不能 return 任何东西。 selG
被定义到您用来启动 Puppeteer 的脚本中,但是您传递给 page.evaluate()
的函数在浏览器中将是 运行,而不是在 Node 执行上下文中。
直接引用 Puppeteer 文档
page.evaluate(pageFunction, ...args)
pageFunction Function to be evaluated in the page context
...args <...Serializable|JSHandle> Arguments to pass to pageFunction
使用(如 Grant 所说)第二个剩余 args
将 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()
的函数不能使用在其外部声明的变量,因为它会 运行 进入浏览器,a上下文与您的 NodeJS 脚本分离(编写以启动 Puppeteer 本身)。
试试我的代码,它应该可以正常工作而无需任何更改。
让我知道是否足够清楚。
奖金
请记住,如果您想使用一些与 DOM 相关的数据,您至少可以使用三种不同的方法来执行相同的操作。
下面是我的示例,我想读取在页面中找到的第一个 link 的 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();
我想将 NodeList 转换为对象。
H1 为 object.name
依此类推。
我仍然无法理解 page.evaluate()
的确切行为。
这是我需要的:
这是我的尝试之一,但 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;
});
您必须使用以下方法将变量 selG
传递给 page.evaluate()
:
const g = await page.evaluate(selG => { /* ... */ }, selG);
Note: Notice the that I added
selG
as a separate argument after the page function.page.evaluate(pageFunction, ...args)
这应该可以防止 document.querySelector(selG)
返回 null
。
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);
不能 return 任何东西。 selG
被定义到您用来启动 Puppeteer 的脚本中,但是您传递给 page.evaluate()
的函数在浏览器中将是 运行,而不是在 Node 执行上下文中。
直接引用 Puppeteer 文档
page.evaluate(pageFunction, ...args)
pageFunction Function to be evaluated in the page context
...args <...Serializable|JSHandle> Arguments to pass to pageFunction
使用(如 Grant 所说)第二个剩余 args
将 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()
的函数不能使用在其外部声明的变量,因为它会 运行 进入浏览器,a上下文与您的 NodeJS 脚本分离(编写以启动 Puppeteer 本身)。
试试我的代码,它应该可以正常工作而无需任何更改。 让我知道是否足够清楚。
奖金
请记住,如果您想使用一些与 DOM 相关的数据,您至少可以使用三种不同的方法来执行相同的操作。
下面是我的示例,我想读取在页面中找到的第一个 link 的 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();