puppeteer nodejs, не могу взять значение за пределами области evaluate [дубликат]

Вопрос или проблема

У меня есть программа на 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); // Выводим результат
}

Объяснение кода

  1. Ожидание наличия элементов: Мы ждем, пока не будет найдено более одного элемента с указанным id на странице.
  2. Локальный массив: Внутри page.evaluate() создается локальный массив tempArray, в который мы собираем необходимые данные.
  3. Возврат данных: Важно вернуть tempArray в конце функции, чтобы данные могли быть доступны в Node.js.
  4. Логирование результата: После выполнения функции, массив arrayOfMailNames содержит все собранные данные, и их можно логировать или использовать дальше по коду.

Заключение

Использование page.evaluate() требует специфического подхода из-за разрыва контекста исполнения. Понимание архитектуры Puppeteer и особенностей работы с асинхронностью в Node.js поможет вам более эффективно управлять данными и избегать распространенных ошибок. Надеюсь, это решение поможет вам в ваших задачах с Puppeteer.

Оцените материал
Добавить комментарий

Капча загружается...