Puppeteer 在 Linux 上的 Azure Functions 节点上部署时引发启动异常

Ven*_*ata 4 azure node.js azure-functions azure-functions-runtime puppeteer

问题:使用 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)
Run Code Online (Sandbox Code Playgroud)

我遵循了 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'] });
Run Code Online (Sandbox Code Playgroud)

以上均无效。他们都抛出同样的错误。

我检查了 FTPing 功能,发现 puppeteer 正在寻找的 chrome 文件存在。

提前致谢。

Jim*_* Xu 7

Azure 具有在 Linux 使用计划中运行无头 Chromium 所需的依赖项。这样我们就可以使用Azure功能中的包了puppeteer。但我们需要使用远程构建来部署应用程序。有关更多详细信息,请参阅Azure 反馈博客

例如

  1. 创建 Azure 函数应用 在此输入图像描述

  2. 创建 Azure 函数项目

A。安装包

  npm install puppeteer
Run Code Online (Sandbox Code Playgroud)

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"
    }
  ]
}

Run Code Online (Sandbox Code Playgroud)

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;
};

Run Code Online (Sandbox Code Playgroud)
  1. .funcignore在项目根文件夹中添加文件
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
tsconfig.json
node_modules
Run Code Online (Sandbox Code Playgroud)
  1. 部署到 Azure
func azure functionapp publish $appName --build remote
Run Code Online (Sandbox Code Playgroud)
  1. 测试 在此输入图像描述 在此输入图像描述

更新

由于您使用 typescript 创建 Azure 函数,因此我们需要更新.funcignore如下

*.js.map
.git*
.vscode
local.settings.json
test
node_modules
Run Code Online (Sandbox Code Playgroud)

例如

我的功能代码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;

Run Code Online (Sandbox Code Playgroud)

部署到 Azure

func azure functionapp publish $appName --build remote
Run Code Online (Sandbox Code Playgroud)

测试

我的服务总线消息 在此输入图像描述

结果 在此输入图像描述 在此输入图像描述

  • @VenkataK.C.Tata我使用Azure函数CLI命令“func azure functionapppublish$appName--buildremote”:https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local ?tabs=windows%2Ccsharp%2Cbash#项目文件部署 (2认同)

Ihe*_*SSI 5

2023 年更新@JimXu 的回复:

我们现在还需要通过创建文件来指定puppeteer 的下载位置.puppeteerrc.cjs

// .puppeteerrc.cjs
const path = require('path');

module.exports = {
  cacheDirectory: path.join(__dirname, '.cache', 'puppeteer')
};
Run Code Online (Sandbox Code Playgroud)