使用 Puppeteer 访问 React 状态

awo*_*e76 7 javascript reactjs puppeteer

我正在运行一个 React 应用程序。我想知道是否可以使用 Puppeteer 访问状态值。

例如,在 React 中我有:

const [gridBlocks, setGridBlocks] = useState([])

该值稍后会更新以设置gridBlocks为值数组。

然后,使用 Puppeteer 我有:

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('http://localhost:3000/', {
    waitUntil: 'networkidle2'
  });

  // Can I get access to React and other javascript values now?
  // Something like console.log(await page.evaluate(() => <are React variables available here>));
  // Another way?

await browser.close();
})();
Run Code Online (Sandbox Code Playgroud)

gridBlocks我想循环遍历该状态的值来更新 UI 并抓取每个值的屏幕截图。我不会gridBlocks提前知道这些值是什么,所以我不能只是在我的 Puppeteer 脚本中“硬编码”它们。我真的很喜欢能够从加载的页面中读取它page.goto

我见过的大多数文章都涉及测试并传递props给组件。如果可能的话,我想直接从加载的页面读取内容。

谢谢!

Md.*_*her 6

我在 puppeteer 上找到了一种快速而肮脏的方法来做到这一点。首先,您需要从 chrome 获取扩展文件。这种方法比从 github 等克隆 React 存储库更快。

主要有两个步骤,

  1. 加载扩展和开发工具。
  2. 欺骗开发工具选择组件。

第一步:

  1. 首先安装Chrome扩展源查看器
  2. 现在下载React Developers Tools的 zip 文件。
  3. 现在将其作为文件夹解压缩到您的项目中,我选择了extension名称。

加载扩展,确保保持开发工具打开

const browser = await puppeteer.launch({
    headless: false,
    devtools: true,
    args: [
      '--disable-extensions-except=./extension/',
      '--load-extension=./extension/',
    ]
});
Run Code Online (Sandbox Code Playgroud)

打开react页面,并确保它已完全加载

const page = await browser.newPage();
await page.goto('http://localhost:3000', {waitUntil: 'networkidle0'});
Run Code Online (Sandbox Code Playgroud)

现在,我们将从根元素中找到子元素并使用开发工具中使用的内部命令。

waitFor 也很重要。我们应该给它一些时间来初始化选择。

await page.evaluate(()=>{
    const rootElement = document.querySelector('#root').childNodes[0];
    __REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent.selectNode(rootElement);
})

await page.waitFor(1000);
Run Code Online (Sandbox Code Playgroud)

最后我们得到了$r中这个特定元素的状态,

const data = await page.evaluate(()=>{
    return $r;
})
Run Code Online (Sandbox Code Playgroud)

我无法在节点上下文上用它做太多事情,但我确信您可以使用它修改和执行不同的东西。

完整代码,

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,
    devtools: true,
    args: [
      '--disable-extensions-except=./extension/',
      '--load-extension=./extension/',
    ]
  });
  const page = await browser.newPage();
  await page.goto('http://localhost:3000', {waitUntil: 'networkidle0'});

  await page.evaluate(()=>{
    const rootElement = document.querySelector('#root').childNodes[0];
    __REACT_DEVTOOLS_GLOBAL_HOOK__.reactDevtoolsAgent.selectNode(rootElement);
  })

  await page.waitFor(1000);

  const data = await page.evaluate(()=>{
    return $r;
  })

  console.log(data)
})();
Run Code Online (Sandbox Code Playgroud)

这是示例反应应用程序,

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

export default Example;
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

笔记:

  • 如果不打开devtools或选择节点,它将无法工作。
  • 在当前 1.19 版本上,它可能无法在无头模式下工作。