page.evaluate()
запускает функцию, которую вы передаете прямо в браузер, и не имеет области действия (доступ к переменным) скрипта NodeJS, который запустил Puppetter.
Чтобы полностью понять, попробуйте это:
1 - скопируйте вашу функцию как есть
2 - оберните ее в самовозглашающуюся функцию ([your-function])()
, результат следующий (я добавил еще однуconsole.log(selG);
line)
((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 <... Serializable | JSHandle>Аргументы для передачи на pageFunction
используют (как сказал Грант) второй остаток 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()
CAN'T, использует переменные, объявленные oкроме этого, потому что он будет запущен в браузере, контекст, отделенный от вашего скрипта NodeJS (записанного для запуска самого Puppeteer).
Попробуйте мой код, он должен работать без каких-либо изменений.Дайте мне знать, если это достаточно ясно.
БОНУС
Помните, что если вы хотите использовать некоторые данные, связанные с DOM, у вас есть по крайней мере три различных метода, которые делают то же самое.
Ниже вы найдете мой пример, где я хочу прочитать атрибут href
первой ссылки, найденной на странице.В первом примере используется page.evaluate()
, как и вы, в двух последних примерах показан другой подход с использованием некоторых других API Puppeteer.
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();