Вход

Просмотр полной версии : Nightmare Js не возвращает NodeList


loksvem
10.08.2019, 22:34
Здравствуйте. Я использую Nightmare JS в Node Js проекте. Вопрос по этому коду:
async function someFunc() {
let nightmare;
try { nightmare = Nightmare({show: true, typeInterval: 10, waitTimeout: 5000});
await nightmare
.goto(`https://example.com`)
.click(".button")
.wait(".someClass")

let result = await nightmare.evaluate(function () {

return document.querySelectorAll(".someClass");
});

console.log(result);

} catch (error) {
throw error;
} finally {
await nightmare.end();
}
}

"someClass" содержит несколько элементов(например,3). Я хочу получить в result NodeList, но я получаю только пустой объект. Этот код работает, только если я сразу возвращаю текстовое значение, например так:

return document.querySelectorAll(".someClass")[0].textContent;

Почему я не могу вернуть NodeList в result ?

Audaxviator
19.08.2019, 18:44
Знаете, я уж отвечал на этот вопрос - так сказать, "в практическом смысле", - потом удалил свой ответ (раз он спрашивающему не интересен, то чего им маячить?)
Но теперь я ещё раз на него отвечу - на этот раз "по существу". Зачем? -- А потому что мне обидно, что единственный нормальный русскоязычный форум про Node.js выглядит умирающим.
Итак, ответ по существу.

Когда-то давно умные люди придумали специальное устройство ("девайс") для общения в сети Энторнеты, оно называется "браузер". Это устройство умеет делать только три вещи - изготовлять из html-строки "документ-объектную модель" (DOM), разукрашивать её (DOM) всякими цветами и размерами (CSS) и динамически - если надо - её изменять (JavaScript) в рамках полученного "документа". Больше это тупое устройство - "браузер" - ничего делать не умеет.

Обратим внимание на его последнее (в списке) умение.
Что делает в браузере код на языке JavaScript типа такого?
document.querySelectorAll(".someClass");
Поскольку тупой браузер - при помощи своего первого умения - уже построил из "документа" (т.е., фактически, из банальной строки, полученной в виде октет-стрима по интернетам) "документ-объектную модель", то данный код имеет возможность обратиться к этой самой DOM и выбрать из неё (из объекта - выбрать подобъекты) кусочки, удовлетворяющие условиям выборки. И если мы в консоле браузера напишем магические букавы:
console.log(document.querySelectorAll(".someClass");)
то тупой браузер нам тут же, в консоль, и напишет искомую NodeList, т.е. "СПИСОК УЗЛОВ DOM (document-object-model)".

Проблемка заключается в том, что NodeList ("список узлов DOM") существует только в браузере.

А что делает крутой модуль Nightmare? (я его попробовал - он, и вправду, крутой)
1. Делает запрос по указанному URL и получает в ответ html-строку в виде октет-стрима.
2. Вызывает браузер Chromium (как он есть "ядро" десктопного приложения Электрон) и просит создать из полученного "документа(строки)" DOM.
3. На языке JavaScript обращается к созданной DOM с запросом коллекции document.querySelectorAll(".someClass"); и получает ответ в виде "кусочков подобъектов, собранных из объекта"... в виде чего?...
4. Поскольку Nightmare - это не тупой браузер, то она получает результат своего запроса - в виде той самой СТРОКИ, которую браузер когда-то получил и интерпретировал как "Документ-Объектную-Модель".

Nightmare - это не браузер, она не умеет оперировать "узлами DOM" (теми самыми, которыми браузер так услужливо изображает нам у себя в консоли в ответ на наш запрос). В качестве ответа она умеет понять только "строку".

Ну всё, я устал.
Если кто не согласен с ответом - милости прошу разъяснить детали.

А если не последует разъяснений - ну и хуй с ним, с форумом.

SuperZen
19.08.2019, 20:34
5 копеек называются https://github.com/GoogleChrome/puppeteer

но оно опять не для всех )

Audaxviator
20.08.2019, 13:49
Да вообще, это вопрос про "типы данных". В javascript он же никогда не стоит, как в "правильных" языках, но это он - в таком вот, несколько неожиданном виде.
Мы же не удивимся, если попытаться открыть в каком-нибудь приложении файл, тип которого это приложение не поддерживает (ну там, открыть html-документ в Фотошопе), и он там не откроется. Здесь примерно тот же случай. "Узлы DOM" и их коллекции (NodeList) - это, вроде бы, объекты, но специфические - браузерные объекты, тип которых Nightmare (да видимо, Нода вообще) не понимает. И функция, которая передаётся в аргумент метода evaluate, должна вернуть какой-нибудь понятный ей тип данных - строку или массив строк, или объект с ключами и значениями-строками.
Вот, собсна, и всё.

SuperZen
20.08.2019, 13:55
сам автор nightmarejs уже сказал, что это все устарело и он больше не разрабатывает этот проект

Audaxviator
20.08.2019, 13:59
Да это не важно. Express тоже "устарел", и его никто больше не разрабатывает. А его знаменитый аффтар сказал, что Нода - это отстой, и он теперь пишет на Go.
И как дальше жить?

SuperZen
20.08.2019, 14:22
я думаю: пока жив web на javascript'е, nodejs не умрет тоже ) ну или как go будет манипулировать dom'ом ) без js? Ну максимум mvc, и приплыли )

https://stackoverflow.com/q/29886552

By default, {} objects are not iterable, but why? Would the disadvantages outweigh the potential benefits of objects being iterable? What are the issues associated with this?

In addition, because {} objects are different from "Array-like" collections and "iterable objects" such as NodeList, HtmlCollection, and arguments, they can't be converted into Arrays.

https://github.com/segmentio/nightmare/issues/617

-- отсюда, наверное, вывод: надо парсить nodeList в evalute, а не возвращать в node и парсить там )... или возвращать document.body.innerHTML в нод, в нод создавать инстанс дом'а, и его парсить... а что будет если вернуть document.querySelector(".someClass")
(не querySelectorAll)... ))

Audaxviator
20.08.2019, 14:37
Это всё равно, document.querySelector(".someClass") вернёт один непонятный "узел". Можно так - return document.querySelector(".someClass").parentElement.innerHTML
А внутри этой функции можно делать что угодно, только возвращать понятные результаты - elem.id или elem.innerHTML, или elem.textContent, elem.href, elem.src - или массивы этого всего собирать.
Но - внутри этой функции, она как раз для этого и предназначена. Всё, что в её теле пишется, это клиенткий javascript в браузере, любой.

SuperZen
20.08.2019, 15:18
это должно быть понятно, что в evalute и надо все парсить...