typescript 如何使用电子 puppet 机芯?

yfwxisqw  于 2023-02-25  发布在  TypeScript
关注(0)|答案(4)|浏览(240)

我从另一个Stackoverflow问题中得到了这个代码:

import electron from "electron";
import puppeteer from "puppeteer-core";

const delay = (ms: number) =>
  new Promise(resolve => {
    setTimeout(() => {
      resolve();
    }, ms);
  });

(async () => {
  try {
    const app = await puppeteer.launch({
      executablePath: electron,
      args: ["."],
      headless: false,
    });
    const pages = await app.pages();
    const [page] = pages;

    await page.setViewport({ width: 1200, height: 700 });
    await delay(5000);
    const image = await page.screenshot();
    console.log(image);
    await page.close();
    await delay(2000);
    await app.close();
  } catch (error) {
    console.error(error);
  }
})();

类型脚本编译器抱怨launch方法选项对象的executablePath属性,因为它需要string类型,而不是Electron类型。那么如何将电子 chrome 可执行路径传递给puppeteer呢?

ig9co6j1

ig9co6j11#

你不能直接使用电子可执行文件与Puppeteer没有一些变通办法和标志的变化。他们有吨的API差异。特别是电子没有所有的**chrome.***API这是 chrome 浏览器正常工作所需的,许多标志仍然没有适当的替代品,如the headless flag
下面你会看到两种方法。但是你需要确定两点,

  • 在启动应用程序之前,请确保 puppet 师已连接。
  • 请确保您得到正确的版本puppeteer或puppeteer-core的版本的 chrome 是运行在电子!

使用puppeteer-in-electron

有很多变通方法,但最近有一个puppeteer-in-electron包,允许您使用electron在电子应用程序中运行puppeteer。
首先,安装依赖项,

npm install puppeteer-in-electron puppeteer-core electron

那就运行它。

import {BrowserWindow, app} from "electron";
import pie from "puppeteer-in-electron";
import puppeteer from "puppeteer-core";

const main = async () => {
  const browser = await pie.connect(app, puppeteer);

  const window = new BrowserWindow();
  const url = "https://example.com/";
  await window.loadURL(url);

  const page = await pie.getPage(browser, window);
  console.log(page.url());
  window.destroy();
};

main();

获取调试端口并连接到它

另一种方法是获取电子应用程序的远程调试端口并连接到它,这个解决方案是由trusktr on electron forum共享的。

import {app, BrowserWindow, ...} from "electron"
import fetch from 'node-fetch'

import * as puppeteer from 'puppeteer'

app.commandLine.appendSwitch('remote-debugging-port', '8315')

async function test() {
    const response = await fetch(`http://localhost:8315/json/versions/list?t=${Math.random()}`)
    const debugEndpoints = await response.json()

    let webSocketDebuggerUrl = debugEndpoints['webSocketDebuggerUrl ']

    const browser = await puppeteer.connect({
        browserWSEndpoint: webSocketDebuggerUrl
    })

    // use puppeteer APIs now!
}

// ... make your window, etc, the usual, and then: ...

  // wait for the window to open/load, then connect Puppeteer to it:
  mainWindow.webContents.on("did-finish-load", () => { 
    test()
  })

上述两种解决方案均使用webSocketDebuggerUrl来解决问题。
额外
添加此注解是因为大多数人使用电子产品捆绑应用程序。
如果你想构建puppeteer-core和puppeteer-in-electron,你需要使用hazardouselectron-builder来确保get-port-cli工作。
在main.js顶部添加危险

// main.js
require ('hazardous');

确保get-port-cli脚本已解压缩,并在package.json上添加以下内容

"build": {
  "asarUnpack": "node_modules/get-port-cli"
}

构建后结果:

6tr1vspr

6tr1vspr2#

最上面的答案对我不起作用使用electron 11和puppeteer-core 8。但是在main进程中启动puppeteer,然后在renderer进程中启动me.you可以使用ipcMain和ipcRenderer相互通信。下面的代码
main.ts(主进程代码)

import { app, BrowserWindow, ipcMain } from 'electron';
import puppeteer from 'puppeteer-core';
async function newGrabBrowser({ url }) {
  const browser = await puppeteer.launch({
    headless: false,
    executablePath:
      '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
  });
  const page = await browser.newPage();
  page.goto(url);
}
ipcMain.on('grab', (event, props) => {
  newGrabBrowser(JSON.parse(props));
});

home.ts(渲染器进程代码)

const { ipcRenderer } = require('electron');
ipcRenderer.send('grab',JSON.stringify({url: 'https://www.google.com'}));
f87krz0w

f87krz0w3#

还有另一个选项,适用于electron 5.x.y及以上版本(目前最高可达7.x.y,我还没有在8.x.y测试版上测试过):

// const assert = require("assert");
const electron = require("electron");
const kill = require("tree-kill");
const puppeteer = require("puppeteer-core");
const { spawn } = require("child_process");

let pid;

const run = async () => {
  const port = 9200; // Debugging port
  const startTime = Date.now();
  const timeout = 20000; // Timeout in miliseconds
  let app;

  // Start Electron with custom debugging port
  pid = spawn(electron, [".", `--remote-debugging-port=${port}`], {
    shell: true
  }).pid;

  // Wait for Puppeteer to connect
  while (!app) {
    try {
      app = await puppeteer.connect({
        browserURL: `http://localhost:${port}`,
        defaultViewport: { width: 1000, height: 600 } // Optional I think
      });
    } catch (error) {
      if (Date.now() > startTime + timeout) {
        throw error;
      }
    }
  }

  // Do something, e.g.:
  // const [page] = await app.pages();
  // await page.waitForSelector("#someid")// 
  // const text = await page.$eval("#someid", element => element.innerText);
  // assert(text === "Your expected text");
  // await page.close();
};

run()
  .then(() => {
    // Do something
  })
  .catch(error => {
    // Do something
    kill(pid, () => {
      process.exit(1);
    });
  });

获取pid和使用kill是可选的。对于在一些CI平台上运行脚本来说,这并不重要,但对于本地环境,您必须在每次尝试失败后手动关闭电子应用程序。
请看这个sample repo

t3psigkw

t3psigkw4#

根据此文档puppeteer-in-electron,它工作正常。但请注意,对于与ipcMain一起工作,您应该在调用main函数之前初始化应用程序。

主文件.js

// main.js
const {BrowserWindow, app} = require("electron");
const pie = require("puppeteer-in-electron")
const puppeteer = require("puppeteer-core");

app.whenReady().then(() => {
    ipcMain.handle('get-url', getUrl)
    createWindow()

    ///
})

async function initialize(){
    await pie.initialize(app);
}
initialize();

async function getUrl(){
  const browser = await pie.connect(app, puppeteer);
 
  const window = new BrowserWindow();
  const url = "https://example.com/";
  await window.loadURL(url);
 
  const page = await pie.getPage(browser, window);
  console.log(page.url());
  window.destroy();
  return page.url();
};

预加载.js

const { contextBridge,ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
    getUrl: () => ipcRenderer.invoke('get-url')
})

渲染器(vue3)

<script setup>
import { ref } from 'vue';

const res = ref();

async function get(){
    const result = await window.electronAPI.getUrl()
    res.value = result
    console.log(result);
}
</script>

我的软件包版本

  • “ puppet 师核心”:“^19.7.1”
  • “电子 puppet ”:“^3.0.5”
  • “电子”:“^23.1.0”

相关问题