函数计算中使用 puppeteer 的过程分析

本文涉及的产品
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
函数计算FC,每月15万CU 3个月
简介: 本文通过实现网页截图功能案例来讲解在函数计算中如何使用 Puppeteer。另外,读者如果遇到同类问题,如:在函数计算中安装自己的共享库,同样可以参考本文章。

该文章已经过期

最新的方案请参考: fc-puppeteer-demo

puppeteer.js github 地址:https://github.com/GoogleChrome/puppeteer
API: https://github.com/GoogleChrome/puppeteer/blob/v1.4.0/docs/api.md
函数计算文档:https://help.aliyun.com/product/50980.html?spm=a2c4g.750001.2.6.uO2VV4

简介

本文通过实现网页截图功能案例来讲解在函数计算中如何使用 Puppeteer。另外,读者如果遇到同类问题,如:在函数计算中安装自己的共享库,同样可以参考本文章。

快速开始

如果您不想知道技术细节,而是想快速的将 Puppeteer 在函数计算中用起来,我这里提供了一个快速开始项目,基于这个项目,您可以马上写业务相关的代码,还提供快速打包和本地调试脚本(强烈推荐)。项目地址:https://github.com/awesome-fc/puppeteer-fc-starter-kit。接下来,我会介绍 Puppeteer 能在函数计算中使用的实现方法。

Puppeteer 简介

Puppeteer 是一个 node 库,他提供了一组用来操纵 Chrome 的 API, 通俗来说就是一个 headless chrome 浏览器 (当然你也可以配置成有UI的,默认是没有的)。既然是浏览器,那么我们手工可以在浏览器上做的事情 Puppeteer 都能胜任, 另外,Puppeteer 翻译成中文是”木偶”意思,所以听名字就知道,操纵起来很方便,你可以很方便的操纵他去实现:

  • 生成网页截图或者 PDF
  • 高级爬虫,可以爬取大量异步渲染内容的网页
  • 模拟键盘输入、表单自动提交、登录网页等,实现 UI 自动化测试
  • 捕获站点的时间线,以便追踪你的网站,帮助分析网站性能问题

在函数计算中使用遇到的问题

  • 尺寸太大: Puppeteer 默认下载的 chrome headless 文件尺寸太大( 180左右 MB,压缩后 50 MB 以上),超过了函数计算的限制大小(限制:压缩后 50 MB ,解压后 250 MB)
  • 依赖动态链接库: chrome headless 自身依赖了一些动态链接库,在函数计算运行环境中没有提供
  • 目录只读: 函数计算运行环境只有 /tmp 目录有写的权限,也无法在运行时直接安装依赖包到系统目录

解决方案

将项目中依赖的 deb 包安装(或者解压)到指定目录,由于依赖的动态库文件只有 4 MB 多,所以可以安装到项目根目录下的 lib 目录中, chrome headless 文件默认尺寸会比较大,我们可以自己编译 chrome headless,自己编译的 chrome headless 文件大小为 109.6 MB,压缩后才 45.6 MB。项目代码、chrome headless 和相关动态链接库一起打包,压缩包的大小也没有超过 50 MB 的限制。如果依赖的动态链接库超过 50 MB,可以打包上传到 oss通过 oss 下载安装到 /tmp 目录中。在本案例中,chrome headless 和 chrome headless 的相关第三方依赖库文件尺寸没有超过 50 MB。方案具体实施步骤如下所述。

实施步骤

创建项目

cd ~
mkdir screenshot
cd screenshot
npm init

注意: 项目用到了一些比较新的语法 await 和 async,所以需要函数计算运行环境选择 nodejs8

进入沙箱环境

cd ~/screenshot
fcli shell            #进入 fcli 交互模式
sbox -d . -t nodejs8  #将当前目录(~/screenshot)挂载到沙盒环境的 /code 位置

注:fcli 为您提供了一个本地的沙盒环境,和函数计算服务中的函数运行环境保持一致。在沙盒环境中,您可以方便的安装第三方库,进行本地调试等操作。

fcli 工具文档

安装项目依赖

package.json 如下:

{
    ...
    "dependencies": {
        "puppeteer": "^1.4.0",
        "tar": "^4.4.4"
    }
    ...
}
export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true  #设置跳过下载 chrome headless 的环境变量
npm install
#或者直接 npm install --ignore-scripts

安装 chrome headless 依赖的动态链接库

##在沙箱环境中
cd /code

mkdir debs
#下面的命令参数 -d 是让 apt-get 只下载安装包,不进行安装
apt-get install -d -o=dir::cache=/code/debs libnspr4 libnss3
#创建 lib 目录,用于安装 chrome headless 依赖的动态链接库
mkdir lib
#安装上面下载的库文件到指定目录
for file in $(ls /code/debs/archives)
do
    dpkg -x  /code/debs/archives/$file /code/lib/
done
r​m -rf debs

说明:动态链接库的关联需要设置环境变量 LD_LIBRARY_PATH,在下面 nodejs 代码中设置了,具体请看编写函数

编译 chrome headless

我已经编译过 chrome headless,下载地址:https://github.com/muxiangqiu/puppeteer-fc-starter-kit/blob/master/chrome/headless_shell.tar.gz?raw=true,如果需要自己编译,可以参考我写好的脚本,或者直接运行我的脚本。

编写函数

基于 pupeteer.js 实现对网页截图,并将图片返回,代码如下:

//index.js
const puppeteer = require('puppeteer');
const tar = require('tar');
const fs = require('fs');
const path = require('path');

//判断是否存在 /tmp/headless 目录
const existsExecutableChrome = () => {
    return  new Promise((resolve, reject) => {
        fs.exists('/tmp/headless_shell', exists => {
            resolve(exists);
        });
    });
};

//从 oss 下载安装 chrome headless 和第三方依赖库文件,如果安装过了,则跳过
const setupChromeIfNecessary = async (context, callback) => {
    if (await existsExecutableChrome()) {
        return;
    }

    return new Promise((resolve, reject) => {
        //解压到 /tmp 目录中
        fs.createReadStream(config.localChromePath)
            .on('error', (err) => reject(err))
            .pipe(tar.x({
              C: 'tmp',
            }))
            .on('error', (err) => reject(err))
            .on('end', () => resolve());
    });
    
};

module.exports.handler =  async (event, context, callback) => {
    await setupChromeIfNecessary(context, callback);
    const ldLibraryPath = `${process.env['FC_FUNC_CODE_PATH']}/lib/usr/lib/x86_64-linux-gnu/`;
    const browser = await puppeteer.launch({
        headless: true,
        //指定 chrome headless 的执行路径
        executablePath: '/tmp/headless_shell',
        args: ['--no-sandbox', '--disable-setuid-sandbox'],
        env: {
            //chrome headless 的第三方依赖库安装到项目的 lib 目录下面,
            //所以需要设置 LD_LIBRARY_PATH 环境变量,告诉系统如何加载这部分的动态库
            LD_LIBRARY_PATH: `${process.env['LD_LIBRARY_PATH']}:${ldLibraryPath}`
        }
    });

    const page = await browser.newPage();
    await page.goto('https://fc.console.aliyun.com');
    try {
        const screenshot = await page.screenshot({
          clip: {
            x: 200,
            y: 60,
            width: 780,
            height: 450
          }
        });
        await page.close();
        callback(null, screenshot))
    } catch (err) {
        callback(err);
    }
};

总结

通过上面的步骤,项目代码压缩后大小为 47 MB 左右 ,包含 chrome headless 和相关动态链接库。冷启动运行时间: 2700 ms 左右,热启动运行时间:300 ms 左右,内存使用:350 MB 左右(注意:在创建函数的时候,内存最好设置为 512 MB)。

本解决方案适用于很多类似的场景,适用规则如下:

  • 需要给函数计算运行环境安装动态链接库
  • 项目尺寸超过了函数计算的限制大小

查阅参考

感谢

感谢如下同学在本案列制作和文档撰写过程中给予的建议和帮助

@倚贤 @不瞋 @夏莞 @敬畏

联系方式

电子邮件: subo.ysb@alibaba-inc.com

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
6月前
|
关系型数据库 MySQL Serverless
高顿教育:大数据抽数分析业务引入polardb mysql serverless
高顿教育通过使用polardb serverless形态进行数据汇总,然后统一进行数据同步到数仓,业务有明显高低峰期,灵活的弹性伸缩能力,大大降低了客户使用成本。
|
21天前
|
SQL 分布式计算 Serverless
EMR Serverless Spark:一站式全托管湖仓分析利器
本文根据2024云栖大会阿里云 EMR 团队负责人李钰(绝顶) 演讲实录整理而成
110 2
|
4月前
|
弹性计算 分布式计算 Serverless
全托管一站式大规模数据处理和分析Serverless平台 | EMR Serverless Spark 评测
【7月更文挑战第6天】全托管一站式大规模数据处理和分析Serverless平台 | EMR Serverless Spark 评测
23706 42
|
6月前
|
SQL 分布式计算 监控
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
本文演示了使用 EMR Serverless Spark 产品搭建一个日志分析应用的全流程,包括数据开发和生产调度以及交互式查询等场景。
56595 7
基于阿里云 EMR Serverless Spark 版快速搭建OSS日志分析应用
|
6月前
|
关系型数据库 Serverless 分布式数据库
【PolarDB 开源】PolarDB Serverless 模式:自动扩缩容与成本效益分析
【5月更文挑战第25天】PolarDB Serverless 提供自动扩缩容功能,适应动态工作负载,降低成本。在业务高峰期增加资源保障性能,低谷期减少资源实现成本优化。通过对比传统模式下的成本浪费,示例说明了Serverless如何节省开支。代码演示了连接与查询PolarDB Serverless数据库的基本操作。要充分利用该模式,需合理规划业务、监控性能并结合其他云服务。PolarDB Serverless是弹性、经济的数据库选择,未来将持续创新,助力企业高效发展。
422 1
|
缓存 关系型数据库 Serverless
数据库内核那些事,PolarDB HTAP Serverless,打造经济易用的实时分析系统
下本从IMCI Serverless核心优势角度的介绍各优化工作内容。
数据库内核那些事,PolarDB HTAP Serverless,打造经济易用的实时分析系统
|
SQL 运维 DataWorks
EMR Serverless StarRocks + DataWorks 开启极速分析新体验
EMR Serverless StarRocks + DataWorks ,开启极速分析体验
1110 0
EMR Serverless StarRocks + DataWorks 开启极速分析新体验
|
Cloud Native 安全 关系型数据库
一起架构-某实时分析项目云原生 serverless 架构的设计思路和poc代码实现
一起架构-某实时分析项目云原生 serverless 架构的设计思路和poc代码实现
|
存储 SQL 数据可视化
EMR Serverless StarRocks 5000CU*时免费试用——体验极致性能和全面 OLAP 分析
EMR Serverless StarRocks 5000CU*H 计算资源,48000GB*H存储资源免费试用进行中,提供极致的性能和丰富的 OLAP 场景模型,包括 OLAP 多维分析、数据湖分析、高并发查询以及实时数据分析,快来体验吧!
1508 0
EMR Serverless StarRocks 5000CU*时免费试用——体验极致性能和全面 OLAP 分析
|
数据采集 Serverless
《函数计算最佳实践:快速开发一个分布式 Puppeteer 网页截图服务》电子版地址
Serverless 开发实战-快速开发一个分布式 Puppeteer 网页截图服务
141 0
《函数计算最佳实践:快速开发一个分布式 Puppeteer 网页截图服务》电子版地址

热门文章

最新文章

相关产品

  • 函数计算