Я использую phantomJs для анализа некоторого контента и получения от него информации (максимальный размер изображения на страницу, например) и т. д. Я решил перейти на кукловод. И я столкнулся с проблемой - в моих функциях, которые выполнялись на phantomJs, они работали с элементом узла документа. Итак, в кукольнике, как я понял, невозможно вернуть элемент node из page.evaluate и других функций. Итак, есть ли другой способ решить эту проблему? Или, может быть, мне нужно использовать другую библиотеку? Спасибо!
Headless Chrome (Puppeteer) - как получить доступ к элементу узла документа?
Ответы (2)
При использовании Puppeteer необходимо учитывать две среды:
- Среда Node.js
- Страница DOM Environment
Среда Node.js построена на движке Google Chrome V8 JavaScript.
Chrome V8 описывает свое отношение к модели DOM:
JavaScript чаще всего используется для создания сценариев на стороне клиента в браузере, например, для управления объектами объектной модели документа (DOM). Однако модель DOM обычно предоставляется не движком JavaScript, а браузером. То же самое верно и для V8 - Google Chrome предоставляет DOM. Однако V8 предоставляет все типы данных, операторы, объекты и функции, указанные в стандарте ECMA.
Другими словами, DOM по умолчанию не предоставляется Node.js.
Это означает, что Node.js не может самостоятельно интерпретировать элементы DOM.
Вот здесь и появляется Кукловод.
Функция Puppeteer page.evaluate()
позволяет оценивать выражение в текущем контексте DOM страницы с использованием Chrome или Chromium.
В документации Puppeteer описано, что происходит, когда вы попытаться вернуть несериализуемое значение, например элемент DOM:
Если функция, переданная в
page.evaluate
, возвращает несериализуемое значение, тогдаpage.evaluate
преобразуется вundefined
.
Опять же, это потому, что Node.js не знает, как интерпретировать элементы DOM без посторонней помощи.
В результате Puppeteer реализовал _5 _ класс, представляющий внутристраничный элемент DOM.
Вы можете использовать elementHandle.$()
, _ 7_ или _ 8_, чтобы вернуть ElementHandle
s обратно в Node.js.
Класс ElementHandle
является сериализуемым, поэтому его можно правильно интерпретировать в среде Node.js.
Следовательно, если вам нужно напрямую управлять элементом, вы можете сделать это внутри page.evaluate()
. Если вам нужно получить доступ к представлению элемента, используйте page.$()
или одну из связанных с ним функций.
В ответе Гранта Миллера обсуждаются некоторые методы и даются ссылки на документацию, но нет кода. Вот демонстрационный код, который показывает:
- Получение ElementHandle для тела документа путем вызова метода
page.$
. - Добавление класса в тело путем вызова его
classList.add
метода в контексте вызоваpage.evaluate
метода. - Печать PDF-файла веб-страницы example.com с оранжевым фоном, чтобы показать, что класс был добавлен.
Код:
const parameters = {
"launchParameters": { "args": [] },
"gotoURI": "https://example.com",
"marginSpecification": {"top": "0", "right": "0", "bottom": "0", "left": "0"},
"pdfPath": "example.pdf",
"styleTag":
'body.orangey, body.orangey div {background-color: orange;}',
"addBodyClass": "orangey",
"footerTemplate": "<div></div>",
"headerTemplate": "<div></div>",
};
console.log("Node version: " + process.version);
const puppeteer = require("puppeteer");
(async () => {
console.log("await puppeteer.launch");
const browser = await puppeteer.launch(parameters.launchParameters);
console.log("await browser.newPage");
const page = await browser.newPage();
console.log("await page.goto");
await page.goto(parameters.gotoURI, {waitUntil: 'networkidle2'});
console.log("await page.addStyleTag");
await page.addStyleTag({
"content": parameters.styleTag
});
if (!!parameters.addBodyClass) {
console.log("await page dollar.")
const bodyHandle = await page.$('body');
console.log("Body handle", (!!bodyHandle) ? "OK." : "no.");
console.log(`await add class "${parameters.addBodyClass}"`);
await page.evaluate(
(body, addBodyClass) => body.classList.add(addBodyClass),
bodyHandle, parameters.addBodyClass)
.catch(error => console.log(error));
console.log("await body handle dispose.");
await bodyHandle.dispose();
}
const pdfOptions = {
path: parameters.pdfPath,
format: 'A4',
margin: parameters.marginSpecification,
displayHeaderFooter: true,
printBackground: true,
footerTemplate: parameters.footerTemplate,
headerTemplate: parameters.headerTemplate
};
console.log("await page.pdf");
await page.pdf(pdfOptions);
console.log("await browser.close");
await browser.close();
})();
Справочную документацию для classList
можно найти здесь, например: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
--dump-dom
и разбирать строку HTML? - person guest271314   schedule 15.01.2018