Вопрос или проблема
У меня есть программа на puppeteer, в которой я получаю элемент div, а затем обрабатываю его дочерние элементы. Когда я пытаюсь вывести с помощью console.log()
, я могу проверить и увидеть значение в браузере. Однако в консоли node js я не вижу значение, которое должно было быть добавлено в массив.
Это более длинная программа, но я просто публикую код функции, к которой относится моя проблема. Какова причина этого? Я также проверял Как я могу передать переменную в функцию evaluate?, чтобы взаимодействовать с переменными вне области видимости с помощью .evaluate()
… если console.log()
дает правильное значение, это означает, что значение получено, но метод push
не срабатывает. И я не вижу ни предупреждения, ни ошибки ни в браузере, ни в журнале программы. Какова причина?
async function observer(){
await page.waitForFunction("document.querySelectorAll(\"div[id='myid']\").length > 1")
var arrayOfMailNames = []
await page.evaluate((arrayOfMailNames) => {
var parentDiv = document.querySelectorAll("div[id='myid']");
for(var t = 0; t < parentDiv.length; t++){
if(parentDiv[t].getAttribute('id') !=null){
console.log(` ${parentDiv[t].split(";")[0]}`); //возвращает правильные значения в консоли браузера.
arrayOfMailNames.push(parentDiv[t].split(";")[0]); //по-видимому, не работает
}
}
}, arrayOfMailNames)
console.log(`${arrayOfMailNames.length}`); //выводит 0 в терминале nodejs... что неверно, так как я использовал push выше
}
Вы должны возвращать
значение из обратного вызова evaluate, который выполняется в контексте страницы. Возвращаемое значение затем присваивается переменной, которую вам нужно.
var arrayOfMailNames = await page.evaluate(() => {
var parentDiv = document.querySelectorAll("div[id='myid']");
var tempArray = [];
for (var t = 0; t < parentDiv.length; t++) {
if (parentDiv[t].getAttribute('id') != null) {
console.log(` ${parentDiv[t].textContent.split(";")[0]}`);
tempArray.push(parentDiv[t].textContent.split(";")[0]);
}
}
return tempArray;
});
Ответ или решение
Основные аспекты работы с Puppeteer и проблема извлечения данных
При использовании Puppeteer для манипуляции с веб-страницами часто возникает ситуация, когда необходима передача данных между контекстом браузера и Node.js. Вопрос, который вы подняли, касается того, почему переменная arrayOfMailNames
, объявленная в Node.js, не получает значения, которые вы пытаетесь добавить в ее массив внутри функции page.evaluate()
.
Проблема: Изоляция контекста
Механизм page.evaluate()
выполняет код внутри браузера, что создает изоляцию от контекста Node.js. Это означает, что любые изменения в переменных, находящихся вне данного контекста, не будут иметь эффекта. В вашем случае, вы пытаетесь модифицировать arrayOfMailNames
, который объявлен в Node.js, но выполняется это в контексте браузера. Ваш код находит значения, но не может их вернуть обратно в Node.js.
Решение: Возврат значений
Чтобы решить данную проблему, нужно возвращать данные из контекста браузера, а не пытаться изменять переменные вне этой области. Это можно сделать с помощью возвращаемого значения функции, переданной в page.evaluate()
.
Вот исправленный вариант вашего кода:
async function observer(){
await page.waitForFunction("document.querySelectorAll(\"div[id='myid']\").length > 1");
const arrayOfMailNames = await page.evaluate(() => {
const parentDiv = document.querySelectorAll("div[id='myid']");
const tempArray = [];
for(let t = 0; t < parentDiv.length; t++){
if(parentDiv[t].getAttribute('id') != null){
console.log(` ${parentDiv[t].textContent.split(";")[0]}`); // Отладочный вывод в консоль браузера
tempArray.push(parentDiv[t].textContent.split(";")[0]); // Добавляем элемент во временный массив
}
}
return tempArray; // Возвращаем массив из контекста браузера
});
console.log(`${arrayOfMailNames.length}`); // Теперь здесь будет правильное значение
console.log(arrayOfMailNames); // Выводим результат
}
Объяснение кода
- Ожидание наличия элементов: Мы ждем, пока не будет найдено более одного элемента с указанным
id
на странице. - Локальный массив: Внутри
page.evaluate()
создается локальный массивtempArray
, в который мы собираем необходимые данные. - Возврат данных: Важно вернуть
tempArray
в конце функции, чтобы данные могли быть доступны в Node.js. - Логирование результата: После выполнения функции, массив
arrayOfMailNames
содержит все собранные данные, и их можно логировать или использовать дальше по коду.
Заключение
Использование page.evaluate()
требует специфического подхода из-за разрыва контекста исполнения. Понимание архитектуры Puppeteer и особенностей работы с асинхронностью в Node.js поможет вам более эффективно управлять данными и избегать распространенных ошибок. Надеюсь, это решение поможет вам в ваших задачах с Puppeteer.