Я хочу преобразовать 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.info(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()
запускает функцию, которую вы передаете, непосредственно в браузер и у него нет размаха (доступ к переменным) сценария NodeJS, запустившего Puppetter.
Чтобы полностью понять, попробуйте следующее:
1 - скопируйте свою функцию как есть
2 - превращает его в самозапускающуюся функцию ([your-function])()
, результат следующий (я добавил еще одну строку console.info(selG);
)
((selG) => {
console.info(selG); // I added this line
let gp = document.querySelector(selG);
let n = Array.from(gp.querySelectorAll('h1'), element => element.textContent);
console.info(n[0]);
return n;
})()
3 - вставьте прямо в консоль devtools
Поступая таким образом, вы выполняете более менее (с точки зрения понимания) то, что делает page.evaluate()
, то есть запускает функцию, которую вы передаете непосредственно в браузер.
Что в результате? Это Cannot read property 'querySelectorAll' of null
, потому что, как вы отметили, gp
имеет значение null.
Но сконцентрируйтесь на console.info(selG);
, который я добавил ... он записывает undefined
... это большая проблема!
Почему это происходит?
Взгляните на саму функцию, переменная selG
не существует, поэтому let gp = document.querySelector(selG);
не может ничего вернуть. selG
определен в сценарии, который вы использовали для запуска Puppeteer, но функция, которую вы передаете page.evaluate()
, будет запускаться в браузере, а не в контексте выполнения узла.
Цитирование прямо из документов Puppeteer
page.evaluate(pageFunction, ...args)
pageFunction Function to be evaluated in the page context
...args <...Serializable|JSHandle> Arguments to pass to 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.info(n[0]);
return n;
}, selG);
Пожалуйста, обрати внимание:
что я передаю переменную selG
(последняя строка) в pageFunction
(ваша функция)
pageFunction
получает переменную и сохраняет ее в переменной SELECTOR
pageFunction
, чем потребляет полученный SELECTOR
Обобщить: функция, переданная в page.evaluate()
, CAN'T потребляет переменные, объявленные вне нее, потому что она будет запущена в браузере, в контексте, отделенном от вашего скрипта 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();
@tramada предоставьте мне репозиторий GitHub, и я посмотрю на него
не могли бы вы помочь мне? он снова стал неопределенным после того, как я добавил свой класс. Мне нужно создать массив объектов jsfiddle.net/keypdamf