Puppeteer 在 Linux 上的 azure 函数节点上部署时引发启动异常

问题描述

问题:使用 puppeteer 获取网站的屏幕截图。在开发机器上运行良好,但在部署到云上的 Azure Functions 时会引发以下异常。

环境:在 Azure(节点 12、Linux、消费计划)上,使用服务总线主题触发的功能

错误

Result: Failure Exception: Error: Failed to launch the browser process! spawn 
/home/site/wwwroot/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome 
EACCES TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md 
Stack: Error: Failed to launch the browser process! 
spawn /home/site/wwwroot/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome 
EACCES TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md 
at onClose (/home/site/wwwroot/node_modules/puppeteer/lib/cjs/puppeteer/node/browserRunner.js:193:20) 
at ChildProcess.<anonymous> (/home/site/wwwroot/node_modules/puppeteer/lib/cjs/puppeteer/node/browserRunner.js:185:85)
at ChildProcess.emit (events.js:314:20) at Process.ChildProcess._handle.onexit (internal/child_process.js:274:12)
at onErrorNT (internal/child_process.js:470:16) at processticksAndRejections (internal/process/task_queues.js:84:21)

我遵循了 puppeteer 故障排除文档中的建议,但仍然遇到相同的问题。

我尝试过的午餐设置

let browser = await puppeteer.launch({ ignoreDefaultArgs: ['--disable-extensions'] });

let browser = await puppeteer.launch({ headless: true,args: ['--no-sandBox','--disable-setuid-sandBox'] });

let browser = await puppeteer.launch({ headless: true });   

let browser = await puppeteer.launch({ args: ['--no-sandBox','--disable-setuid-sandBox'] });

以上都没有奏效。他们都抛出同样的错误

我在函数中检查了 FTPing,并且 chrome 文件 puppeteer 正在寻找,存在。

提前致谢。

解决方法

Azure 具有在 Linux Consumption 计划中运行无头 Chromium 的必要依赖项。所以我们可以在 Azure 函数中使用包 puppeteer。但是我们需要使用远程构建来部署应用程序。有关详细信息,请参阅 Azure feedbackblog

例如

  1. 创建 Azure 函数应用 enter image description here

  2. 创建 Azure 函数项目

一个。安装包

  npm install puppeteer

B.函数.json

{
  "bindings": [
    {
      "name": "mySbMsg","type": "serviceBusTrigger","direction": "in","topicName": "bowman1012","subscriptionName": "test","connection": "bowman1012_SERVICEBUS"
    },{
      "type": "blob","direction": "out","name": "outputBlob","path": "outcontainer/{rand-guid}.png","connection": "AzureWebJobsStorage"
    }
  ]
}

c.代码

const puppeteer = require("puppeteer");

module.exports = async function (context,mySbMsg) {
  context.log(
    "JavaScript ServiceBus topic trigger function processed message",mySbMsg
  );
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto("https://google.com/");
  const screenshotBuffer = await page.screenshot({ fullPage: true });
  await browser.close();
  context.bindings.outputBlob = screenshotBuffer;
};

  1. 在项目根文件夹中添加.funcignore文件
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
tsconfig.json
node_modules
  1. 部署到 Azure
func azure functionapp publish $appName --build remote
  1. 测试 enter image description here enter image description here

更新

由于您使用 typescript 创建 Azure 函数,因此我们需要将 .funcignore 更新为以下内容

*.js.map
.git*
.vscode
local.settings.json
test
node_modules

例如

我的函数代码index.ts

import { AzureFunction,Context } from "@azure/functions";
import { ServiceBusMessage } from "@azure/service-bus";
import puppeteer from "puppeteer";
import { BlobServiceClient } from "@azure/storage-blob";

const serviceBusTopicTrigger: AzureFunction = async function (
  context: Context,mySbMsg: ServiceBusMessage
): Promise<void> {
  try {
    const promotionId = context.bindingData.userProperties.promotionId;
    context.log(
      "Player Screen Grabber ServiceBus topic trigger function processing message started",promotionId
    );
    const playerURL = "https://www.google.com/";
    let browser = await puppeteer.launch({ headless: true });
    let page = await browser.newPage();
    await page.goto(playerURL,{ waitUntil: "networkidle2" });
    await page.setViewport({ width: 1920,height: 1080 });
    const screenshotBuffer = await page.screenshot({
      encoding: "binary",});
    await page.close();
    await browser.close();
    // the storage account connection string
    const constr = process.env["AzureWebJobsStorage"] + "";
    const blobserviceClient = BlobServiceClient.fromConnectionString(constr);
    const containerClient = blobserviceClient.getContainerClient(
      "outcontainer"
    );
    const blob = containerClient.getBlockBlobClient(`${promotionId}.png`);
    await blob.uploadData(screenshotBuffer);
    context.log(
      "Player Screen Grabber ServiceBus topic trigger function processing message ended",promotionId
    );
  } catch (error) {
    throw error;
  }
};

export default serviceBusTopicTrigger;

部署到 Azure

func azure functionapp publish $appName --build remote

测试

我的服务总线消息 enter image description here

结果 enter image description here enter image description here