专栏首页Serverless+在 SCF 中运行 Puppeteer
原创

在 SCF 中运行 Puppeteer

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

一个截图的例子

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

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 上运行

// 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, 你需要使用这种方式上传代码)

$ npm init
$ npm install puppeteer
$ tree -L 1 .
.
|-- index.js
|-- node_modules
|-- package.json
`-- package-lock.json

第一次运行

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

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.

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

const browser = await puppeteer.launch({args: ['--no-sandbox']});

第二次运行

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

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

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

$ yum install libXScrnSaver

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

// index.js
'use strict';

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

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

$ ldd node_modules/puppeteer/.local-chromium/linux-641577/chrome-linux/chrome

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

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

第三次运行

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

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 次运行

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

$ 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

函数终于可以正常运行了

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

总结

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

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

完整的示例代码如下:

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

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

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 搭建以 serverless 为后台服务的疫情热搜快应用

    今年疫情的影响越来越大,已经成为一个世界性的问题,疫情的发展时刻牵动每个人的心,正好也是因为疫情,今年让作为加班狗的我突然重温“放寒假”的感觉。宅在家里太久就想...

    dadong
  • travis-ci 中运行 puppeteer

    易墨
  • 云函数扫盲

    云函数作为无服务模式的一种实现(FaaS)已经有很多公司在提供了,亚马逊AWS、微软Azure、Google Cloud、IBM Cloud、阿里云、腾讯云、华...

    薛定喵君
  • /自动化测试/ puppeteer环境搭建

    Puppeteer is a Node library which provides a high-level API to control Chrome or...

    测试邦
  • 用 Puppeteer 实现一个自动化机器人

    Puppeteer 是 Node.js 的一个函数库,可用来操控浏览器,是 Google 的项目,可以应用的范围包括:前端的自动化测试、爬虫、表单提交等。

    疯狂的技术宅
  • deno牌puppeteer,真香!

    puppeteer是一个Node库,它提供了高级API来通过DevTools协议控制Chrome或Chromium,puppeteer 默认以 headless...

    胡琦
  • 大前端神器安利之 Puppeteer

    Puppeteer(中文翻译”木偶”) 是 Google Chrome 团队官方的无界面(Headless)Chrome 工具,它是一个 Node 库,提供了一...

    晚晴幽草轩轩主
  • 最完美方案!模拟浏览器如何正确隐藏特征

    在前天的公众号文章《别去送死了。Selenium 与 Puppeteer 能被网站探测的几十个特征》中,我们提到目前网上的反检测方法几乎都是掩耳盗铃,因为模拟浏...

    青南
  • Puppeteer之爬虫入门

    译者按: 本文通过简单的例子介绍如何使用 Puppeteer 来爬取网页数据,特别是用谷歌开发者工具获取元素选择器值得学习。

    Fundebug
  • Laravel 中使用 puppeteer 采集异步加载的网页内容

    overtrue
  • Puppeteer Sharp: 使用C#和Headless Chrome爬网页

    Puppeteer 是谷歌构建的流行的Headless Chrome NodeJS API爬虫库。Puppeteer Sharp是用C#写的,由达里奥·孔德拉蒂...

    皇上得了花柳病
  • node爬取新型冠状病毒的疫情实时动态

    新型冠状病毒有多么可怕,我想大家都已经知道了。湖北爆发了新型冠状病毒,湖南前几天爆发了禽流感,四川发生地震,中国加油!昨天晚上我突发奇想地打算把疫情实时动态展示...

    喜欢ctrl的cxk
  • 不仅仅可以用来做爬虫,Puppeteer 还可以干这个!

    自动化测试对于软件开发来说是一个很重要也很方便的东西,但是自动化测试工具除了能用来做测试以外,还能被用来做一些模拟人类操作的事情,所以一些 E2E 自动化测试工...

    崔庆才
  • 用Node.js把HTML转成PDF格式[每日前端夜话0x46]

    在本文中,我将展示如何使用 Node.js、Puppeteer、headless Chrome 和 Docker 从样式复杂的 React 页面生成 PDF 文...

    疯狂的技术宅
  • Puppeteer 爬取豆瓣小组公开信息

    面对未知的事物,最好的老师显然是搜索引擎,而搜索引擎中公认最好的又是 Google 搜索。

    前端老王
  • 小程序测试方案初探

    对于小程序如何做测试,依然是一头雾水,直到做了不少的项目,积累的一些经验和开源库之后才理清如何做测试,下面将会介绍如何对小程序做 UI 测试和单元测试。

    云加社区
  • 前端使用puppeteer 爬虫生成《React.js 小书》PDF并合并

    puppeteer: Google 官方出品的 headless Chrome node 库 puppeteer github仓库 puppeteer API

    若川
  • 利用docker部署puppeteer

    puppeteer可以使用Network.emulateNetworkConditions和Emulation.setCPUThrottlingRate轻松地模...

    2014v
  • puppeteer实现线上服务器任意区域截图

    整个九月份由于业务繁重以及玩心颇重,一直没有机会来写一篇博文。而且笔者于十月一日将会举办人生大事--婚礼,现在家里筹办过程中只能抽出零碎的时间来写这篇文章。

    欲休

扫码关注云+社区

领取腾讯云代金券