使用 puppeteer 返回窗口对象

Return window object using puppeteer

提问人:alexc 提问时间:6/27/2018 最后编辑:Vishwanathalexc 更新时间:10/3/2023 访问量:16697

问:

我正在尝试从页面返回整个窗口对象,然后在 puppeteer 之外遍历该对象。

我正在尝试访问 Highcharts 属性中的数据,我需要访问窗口对象。普通的 javascript 代码类似于 .window.Highcharts.charts[0].series[0].data

我认为最简单的方法是使用 Puppeteer 访问该站点,然后将 Windows 对象发回给我,然后我就可以像任何其他 JS 对象一样在 puppeteer 之外使用它。

阅读文档后,我发现很难返回该对象,因为只需将“窗口”放入 chrome 控制台即可显示。我不确定我错过了什么?

我已经通读了文档,以下两种方法似乎应该有效?

(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.example.com', {waitUntil: 'networkidle2'});

    // METHOD 1
    // Create a Map object
    await page.evaluate(() => window.map = new Map());
    // Get a handle to the Map object prototype
    const mapPrototype = await page.evaluateHandle(() => Map.prototype);
    // Query all map instances into an array
    const mapInstances = await page.queryObjects(mapPrototype);

    console.log(mapInstances);

    await mapInstances.dispose();
    await mapPrototype.dispose();

    // METHOD 2
    const handle = await page.evaluateHandle(() => ({window, document}));
    const properties = await handle.getProperties();
    const windowHandle = properties.get('window');
    const documentHandle = properties.get('document');
    var result = await page.evaluate(win => win, windowHandle);

    console.log(result)

    await handle.dispose();



    await browser.close();
})();

但是,它只在控制台中返回以下内容,而不是我想要的简单对象;

enter image description here

不确定我是否以正确的方式处理此事,因此非常感谢任何帮助/建议。

node.js google-chrome-extension web-scraping chromium puppeteer

评论


答:

0赞 Müller 8/9/2023 #1

我遇到了同样的问题,我遇到了时间问题,因为 Puppeteer 与页面异步交互。将 waitForFunction 添加到页面对我有用。

await page.waitForFunction(() => window.objectOnMyWindow !== undefined);
const objectOnMyWindow = await page.evaluate(() => window.objectOnMyWindow);
0赞 ggorlen 9/2/2023 #2

“将窗口返回到 Node”是一个 XY 问题。无法返回窗口,因为它是一个复杂的、不可序列化的、具有循环引用的海量数据结构。当您尝试从中返回它时,Puppeteer 基本上会调用它,这在我所知道的任何浏览器中都不起作用。JSON.stringify(window)evaluate()

如果您尝试从恰好附加到窗口的对象中提取数据,则可以在浏览器中执行此操作,然后将您关心的窗口的可序列化小子集返回给 Node。下面是一个概念证明:

const puppeteer = require("puppeteer"); // ^21.0.2

const html = `<!DOCTYPE html><html><body>
<script>
setTimeout(() => {
  window.Highcharts = {
    charts: [{series: [{data: "hello world"}]}]
  };
}, 3000); // add the variable sometime after page load
</script>
</body></html>`;

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html);
  const data = await page.evaluate(`
    window.Highcharts.charts[0].series[0].data
  `);
  console.log(data); // => hello world
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

假设此数据在页面加载中不可用。你可以通过等待某个元素出现来阻止它,或者直接用 :waitForElementwaitForFunction

const html = `<!DOCTYPE html><html><body>
<script>
setTimeout(() => {
  window.Highcharts = {
    charts: [{series: [{data: "hello world"}]}]
  };
}, 3000); // add the variable sometime after page load
</script>
</body></html>`;

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.setContent(html);
  await page.waitForFunction(`
    window?.Highcharts?.charts[0]?.series[0]?.data
  `);
  const data = await page.evaluate(`
    window.Highcharts.charts[0].series[0].data
  `);
  console.log(data); // => hello world
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());