【发布时间】:2021-11-06 13:56:17
【问题描述】:
我制作了这个自定义函数并将它放在全局之外,这通常会起作用。我还尝试将它移动到主要的异步 puppeteer 函数中,但也不起作用。它是一个简单的功能。在每个页面评估函数中,我调用它并传递选择器。但是,它的说法没有定义并且承诺拒绝这很奇怪,因为该功能不是承诺......请帮助
const grabDomConvertNodlistToArray = (grabDomHtmlPath) => {
// grabbing node list from html selector all
const nList = document.querySelectorAll(grabDomHtmlPath);
// converting nodelist to array to be returned
const array = Array.from(nList);
return array;
};
我尝试将函数转换为添加新参数页面的异步函数。然后我将 async 添加到我的评估函数中,然后将 puppeteer 页面作为参数传递,但仍然错误且无法正常工作。
const grabDomConvertNodlistToArray = async (page, grabDomHtmlPath) => {
try {
// grabbing node list from html selector all
const nList = await page.document.querySelectorAll(grabDomHtmlPath);
// converting nodelist to array to be returned
const array = Array.from(nList);
return array;
} catch (error) {
console.log(error);
}
};
所以我有典型的 puppeteer 设置,你等待 browser.newPage() 然后转到 (url)。然后我添加了这个;
await page.exposeFunction("grabDomConvertNodlistToArray", grabDomConvertNodlistToArray);
将异步添加到我的评估回调函数中,即 async() => {}。但是在上面的评估函数中调用我的自定义函数时,由于某种原因它仍然不起作用。
找到了解决方案,但它对我不起作用。我正在获取 array.forEach 不是一种方法,它向我表明在我的 grabDomConvertNodlistToArray 函数中它没有抓取 nodeList 或将其转换为数组。如果是这样,那么 forEach 将是一个函数。
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(someURL);
var functionToInject = function(){
return 1+1;
}
var otherFunctionToInject = function(input){
return 6
}
await page.exposeFunction("functionToInject", functionToInject)
await page.exposeFunction("otherFunctionToInject", otherFunctionToInject)
var data = await page.evaluate(async function(){
console.log('woo I run inside a browser')
return await functionToInject() + await otherFunctionToInject();
});
return data
所以抹掉上面的两个函数,转换成下面我的函数使用。
const grabDomConvertNodlistToArray = (grabDomHtmlPath) => {
// grabbing node list from html selector all
const nList = document.querySelectorAll(grabDomHtmlPath);
// converting nodelist to array to be returned
const array = Array.from(nList);
return array;
};
运行我的 js 文件会导致 array.forEach 的错误不是一个奇怪的函数,因为如果函数按预期工作,我的评估函数中的 const 数组将是一个数组,因为它的 = 对上述函数是返回一个数组。所以.....idk 发生了什么认为它与 document.querySelectorAll() 行有关。
const rlData = async () => {
const browser = await puppeteer.launch(
{
headless: true,
},
{
args: ["--flag-switches-begin", "--disable-features=OutOfBlinkCors", "--flag-switches-end"],
}
);
const pageBodies = await browser.newPage();
await pageBodies.goto("https://test.com/bodies", {
waitUntil: "load",
});
const grabDomConvertNodlistToArray = (grabDomHtmlPath) => {
// grabbing node list from html selector all
const nList = document.querySelectorAll(grabDomHtmlPath);
// converting nodelist to array to be returned
const array = Array.from(nList);
return array;
};
await pageBodies.exposeFunction("grabDomConvertNodlistToArray", grabDomConvertNodlistToArray);
const rlBodyNames = await pageBodies.evaluate(async () => {
// grabs all elements in html to make nodelist & converts it to an array
const array = grabDomConvertNodlistToArray(".testbodies > div > h1");
// push the data collected from array into data array and returned
const data = [];
array.forEach((element) => {
data.push(element.textContent);
});
return data;
});
}
rlData();
我想我将不得不将 document.querySelectorAll 功能从自定义函数中移出并返回到评估中。但是,制作该自定义函数的全部原因是为了减少多次使用相同的代码,因为我的整个爬虫有 238 行长,并且有很多重复性。无法调用像我这样的自定义函数对于重构相同的代码执行来说是可怕的。
我放弃了尝试让它发挥作用,并决定这样做。是的,如果你有更多的页面要抓取,它会使你的代码重复,所以你将多次使用相同的代码,这是我试图避免的,但是,puppeteer 更糟糕的是重构你的代码,可能是所述包的开发人员将添加轻松使用自定义函数的能力,就像我尝试的方式一样。
const testNames = await pageBodies.evaluate(() => {
const nodeList = document.querySelectorAll(".test > div h2");
const array = Array.from(nodeList);
const data = [];
array.forEach((element) => {
data.push(element.textContent);
});
return data;
});
【问题讨论】:
标签: javascript web-scraping puppeteer