前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在 SCF 中运行 Puppeteer

在 SCF 中运行 Puppeteer

原创
作者头像
ritchiechen
发布2019-04-05 18:06:16
6.5K10
发布2019-04-05 18:06:16
举报
文章被收录于专栏:Serverless+Serverless+

Puppeteer 是一个 Node.js 库, 提供了一组封装良好的接口, 使你可以通过 DevTools 协议控制 Chrome. 本文介绍如何在 SCF 中使用 Puppeteer.

一个截图的例子

我们使用官方仓库里的截图例子

代码语言:txt
复制
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});

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

将其改造一下, 使其可以在 SCF 上运行

代码语言:txt
复制
// index.js
'use strict';

const puppeteer = require('puppeteer');
const fs = require('fs');

exports.main_handler = async (event, context, callback) => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.screenshot({path: '/tmp/example.png'});
    await browser.close();

    let img = fs.readFileSync('/tmp/example.png');
    let data = {
        isBase64Encoded: true,
        statusCode: 200,
        headers: {'content-type': 'image/png'},
        body: img.toString('base64'),
    };
    return data;
};

为了可以看到截图的效果, 我们可以添加一个 API 网关触发器, 并将图片以 Base64 编码的格式返回.

至此, 我们期望这个函数可以在 SCF 上正确运行.

运行函数

在本地创建一个新项目, 把依赖装完后, 将代码打包上传至 COS, 创建一个新的 SCF 函数, 引用这个 COS 文件(由于打包生成的代码超过 50 MB, 你需要使用这种方式上传代码)

代码语言:txt
复制
$ npm init
$ npm install puppeteer
$ tree -L 1 .
.
|-- index.js
|-- node_modules
|-- package.json
`-- package-lock.json

第一次运行

在控制台上点击测试, 你可能会看到如下错误:

代码语言:txt
复制
Failed to launch chrome!
[0405/090101.405444:FATAL:zygote_host_impl_linux.cc(116)] No usable sandbox! Update your kernel or see https://chromium.googlesource.com/chromium/src/+/master/docs/linux_suid_sandbox_development.md for more information on developing with the SUID sandbox. If you want to live dangerously and need an immediate workaround, you can try using --no-sandbox.

我们按照提示来修复这个错误, 添加启动参数:

代码语言:txt
复制
const browser = await puppeteer.launch({args: ['--no-sandbox']});

第二次运行

这一次, 你会遇到不一样的错误:

代码语言:txt
复制
Error: Failed to launch chrome!
/var/user/node_modules/puppeteer/.local-chromium/linux-641577/chrome-linux/chrome: error while loading shared libraries: libXss.so.1: cannot open shared object file: No such file or directory

作为一个有经验的程序员, 你知道这是运行环境里缺少了必要的动态链接库, 你也发现机器上没有这个动态链接库, 搜索发现, 可以这样解决

代码语言:txt
复制
$ yum install libXScrnSaver

安装完后, 你把 libXss.so.1/lib64 目录拷贝到项目到目录里, 并在代码中将项目的目录追加到 LD_LIBRARY_PATH 环境变量中.

代码语言:txt
复制
// index.js
'use strict';

process.env['LD_LIBRARY_PATH'] += ';' + __dirname;

操作完后, 你想看看 Chrome 还依赖哪些动态链接库, 于是你执行了以下命令:

代码语言:txt
复制
$ ldd node_modules/puppeteer/.local-chromium/linux-641577/chrome-linux/chrome

你会发现, Chrome 依赖多达 107 个动态链接库, 你可以选择把这些库都拷贝到当前目录, 这样就可以一劳永逸地解决依赖的问题.

你没有选择这样做, 因为这会使代码包变大许多, 你打包了代码, 再次运行.

第三次运行

问题不大, 你已经知道如何解决了

代码语言:txt
复制
Error: Failed to launch chrome!
/var/user/node_modules/puppeteer/.local-chromium/linux-641577/chrome-linux/chrome: error while loading shared libraries: libatk-bridge-2.0.so.0: cannot open shared object file: No such file or directory

拷贝缺失的库到当前目录, 再次打包上传

第 X 次运行

你并没有崩溃 (:, 反复执行这个过程后, 你终于把缺失的动态库都补齐了

代码语言:txt
复制
$ ls lib*
libatk-1.0.so.0         libatspi.so.0          libepoxy.so.0  libgtk-3.so.0           libwayland-egl.so.1  libXss.so.1
libatk-bridge-2.0.so.0  libcairo-gobject.so.2  libgdk-3.so.0  libwayland-cursor.so.0  libxkbcommon.so.0

函数终于可以正常运行了

代码语言:txt
复制
{"isBase64Encoded":true,"statusCode":200,"headers":{"content-type":"image/png"},"body":"iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAYAAACadoJwAAAAAXNSR0IArs4c6QAAIABJREFUeJzs3Xd8Tff/B/DXzZCIaOy9Y48vpdSmVFXtEETs0dqKIChVlEao1pbYKyFmrVBao5TG1qZ2iBBChiA7ef/+8HB+rqx7k3vPjdvX8/E4j0dy7uee8z7n8/mce95naqKiogVEREREREQqsDB1AERERERE9N/BBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBISIiIiIiFTDBI..."}

总结

本文介绍了如何解决在 SCF 中运行 Puppeteer 缺少动态链接库的问题. 缺失的库包括:

代码语言:txt
复制
libatk-1.0.so.0         libatspi.so.0          libepoxy.so.0  libgtk-3.so.0           libwayland-egl.so.1  libXss.so.1
libatk-bridge-2.0.so.0  libcairo-gobject.so.2  libgdk-3.so.0  libwayland-cursor.so.0  libxkbcommon.so.0

完整的示例代码如下:

代码语言:txt
复制
// index.js
'use strict';

process.env['LD_LIBRARY_PATH'] += ';' + __dirname;

const puppeteer = require('puppeteer');
const fs = require('fs');

exports.main_handler = async (event, context, callback) => {
    const browser = await puppeteer.launch({args: ['--no-sandbox']});
    const page = await browser.newPage();
    await page.goto('https://example.com');
    await page.screenshot({path: '/tmp/example.png'});
    await browser.close();

    let img = fs.readFileSync('/tmp/example.png');
    let data = {
        isBase64Encoded: true,
        statusCode: 200,
        headers: {'content-type': 'image/png'},
        body: img.toString('base64'),
    };
    return data;
};

你想通过 API 网关 看看效果, 没有如你所愿, 截图上的文本没有被正确显示, 但是聪明的你一定想到了, 这是字体的问题. 这个问题就留给读者自行解决啦!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一个截图的例子
  • 运行函数
    • 第一次运行
      • 第二次运行
        • 第三次运行
          • 第 X 次运行
          • 总结
          相关产品与服务
          API 网关
          腾讯云 API 网关(API Gateway)是腾讯云推出的一种 API 托管服务,能提供 API 的完整生命周期管理,包括创建、维护、发布、运行、下线等。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档