目次
结尾
ホームページ ウェブフロントエンド jsチュートリアル Puppeteer ライブラリを使用して Node でポスターを生成する方法の簡単な分析 (実装計画の共有)

Puppeteer ライブラリを使用して Node でポスターを生成する方法の簡単な分析 (実装計画の共有)

Jan 18, 2022 pm 07:26 PM
node

Node を使用してポスターを生成するにはどうすればよいですか?次の記事では、Node Puppeteer を使用してポスターを生成する方法を紹介します。

Puppeteer ライブラリを使用して Node でポスターを生成する方法の簡単な分析 (実装計画の共有)

前回の記事で、数日前に html2canvas を使用しているときに多くの互換性の問題に遭遇し、バケツを持って逃げそうになったことを書きました。その後、コメント エリアの偉い人の指導により、操作が簡単で再利用性の高いポスター生成ソリューションである Node Puppeteer がポスターを生成するソリューションを発見しました。

主な設計アイデアは次のとおりです: ポスターを生成するためのインターフェイスにアクセスするこのインターフェイスは、Puppeteer を通じて受信アドレスにアクセスし、対応する要素のスクリーンショットを返します。


Puppeteer によるポスター生成の Canvas 生成と比較した利点は何ですか:

    ブラウザの互換性、プラットフォームの互換性、その他の問題はありません。
  • コードは再利用性が高く、h5、ミニ プログラム、アプリのポスターの生成に使用できます。
  • 最適化演算領域が大きくなります。ポスターを生成するインターフェースに変更されたため、サーバーの追加やキャッシュの追加など、サーバー側のさまざまな方法を使用して応答速度を最適化できます

puppeteer Introduction

Puppeteer は、DevTools プロトコルを通じて Chromium または Chrome を制御するための高レベル API を提供する

Nodejs ライブラリです。 Puppeteer はデフォルトではヘッドレス モード、つまり「ヘッドレス」モードで実行されますが、設定 headless:false を変更することで「ヘッド」モードを実行できます。 ブラウザで手動で行うことのほとんどは、Puppeteer を使用して行うことができます。例をいくつか示します。

    ページ PDF またはスクリーンショットを生成します。
  • SPA (シングル ページ アプリケーション) をクロールし、事前レンダリングされたコンテンツ (つまり、「SSR」 (サーバー サイド レンダリング)) を生成します。
  • フォームの自動送信、UI テスト、キーボード入力などを実行します。
  • 常に更新される自動テスト環境を作成します。最新の JavaScript とブラウザ機能を使用して、最新バージョンの Chrome でテストを直接実行します。
  • Web サイトのタイムライン トレースをキャプチャして、パフォーマンスの問題の分析に役立てます。
  • ブラウザ拡張機能をテストします。

ソリューションの実装

1. 単純なインターフェイスを作成します

Express は Aシンプルで柔軟なnode.js Webアプリケーションフレームワーク。 Express を使用して単純なノード サービスを作成し、インターフェイスを定義し、スクリーンショットに必要な構成アイテムを受け取り、puppeteer に渡します。

const express = require('express')
const createError = require("http-errors")
const app = express()
// 中间件--json化入参
app.use(express.json())
app.post('/api/getShareImg', (req, res) => {
    // 业务逻辑
})
// 错误拦截
app.use(function(req, res, next) {
    next(createError(404));
});
app.use(function(err, req, res, next) {
    let result = {
        code: 0,
        msg: err.message,
        err: err.stack
    }
    res.status(err.status || 500).json(result)
})
// 启动服务监听7000端口
const server = app.listen(7000, '0.0.0.0', () => {
    const host = server.address().address;
    const port = server.address().port;
    console.log('app start listening at http://%s:%s', host, port);
});
ログイン後にコピー

2. スクリーンショット モジュールの作成

ブラウザを開く=> タブを開く=> スクリーンショット=> ブラウザを閉じる

const puppeteer = require("puppeteer");

module.exports = async (opt) => {
    try {
        const browser = await puppeteer.launch();
        const page = await browser.newPage();
        await page.goto(opt.url, {
            waitUntil: ['networkidle0']
        });
        await page.setViewport({
            width: opt.width,
            height: opt.height,
        });
        const ele = await page.$(opt.ele);
        const base64 = await ele.screenshot({
            fullPage: false,
            omitBackground: true,
            encoding: 'base64'
        });
        await browser.close();
        return 'data:image/png;base64,'+ base64
    } catch (error) {
        throw error
    }
};
ログイン後にコピー

    puppeteer.launch([options]): ブラウザを起動します
  • browser.newPage(): タブ ページを作成します
  • page.goto (url[, options]): ページに移動します
  • page.setViewport(viewport): ページを開くウィンドウを指定します
  • page.$(selector): 要素の選択
  • elementHandle .screenshot([オプション]): スクリーンショット。エンコード属性では、戻り値がbase64またはBuffer
  • browser.close(): ブラウザとタブページを閉じます

#3. 最適化

1. リクエスト時間の最適化

page.goto(url[, options]) メソッドの設定項目 waitUntil は、実行時の状態を示します。デフォルトでは、load イベントがトリガーされたときです。

 await page.goto(url, {
     waitUntil: [
         'load', //页面“load” 事件触发
         'domcontentloaded', //页面 “DOMcontentloaded” 事件触发
         'networkidle0', //在 500ms 内没有任何网络连接
         'networkidle2' //在 500ms 内网络连接个数不超过 2 个
     ]
 });
ログイン後にコピー

networkidle0 ソリューションを使用してページの完了を待機する場合、networkidle0 は 500 ミリ秒待機する必要があるため、インターフェイスの応答時間が長くなることがわかります。シナリオでは、多くの場合待つ必要がないため、Delay をカプセル化し、待ち時間をカスタマイズできます。たとえば、ポスター ページは背景画像と QR コード画像のみをレンダリングします。ページが読み込みをトリガーするとき、ページはすでに読み込まれています。待ち時間はありません。待ち時間をスキップするには、0 を渡すことができます。

 const waitTime = (n) => new Promise((r) => setTimeout(r, n));
 //省略部分代码
 await page.goto(opt.url);
 await waitTime(opt.waitTime || 0);
ログイン後にコピー

このメソッドでは不十分で、ページが特定の時間に終了するようにパペッティアに通知する必要がある場合は、page.waitForSelector(selector[, options]) を使用して、ページ上の指定された要素を待つこともできます。ページが表示されます。たとえば、ページが操作を完了すると、id="end" の要素が挿入され、puppereer はこの要素が表示されるのを待ちます。

 await page.waitForSelector("#end")
ログイン後にコピー

同様の方法には次のようなものがあります:

  • page.waitForXPath(xpath[, options]):等待 xPath 对应的元素出现在页面中。
  • page.waitForSelector(selector[, options]):等待指定的选择器匹配的元素出现在页面中,如果调用此方法时已经有匹配的元素,那么此方法立即返回。
  • page.waitForResponse(urlOrPredicate[, options]):等待指定的响应结束。
  • page.waitForRequest(urlOrPredicate[, options]):等待指定的响应出现。
  • page.waitForFunction(pageFunction[, options[, ...args]]):等待某个方法执行。
  • page.waitFor(selectorOrFunctionOrTimeout[, options[, ...args]]):此方法相当于上面几个方法的选择器,根据第一个参数的不同结果不同,比如:传入一个string类型,会判断是不是xpath或者selector,此时相当于waitForXPath或waitForSelector。

2. 启动项优化

Chromium启动时还会开启很多不需要的功能,可以通过参数禁用某些启动项。

    const browser = await puppeteer.launch({
        headless: true,
        slowMo: 0,
        args: [
            '--no-zygote',
            '--no-sandbox',
            '--disable-gpu',
            '--no-first-run',
            '--single-process',
            '--disable-extensions',
            "--disable-xss-auditor",
            '--disable-dev-shm-usage',
            '--disable-popup-blocking',
            '--disable-setuid-sandbox',
            '--disable-accelerated-2d-canvas',
            '--enable-features=NetworkService',
        ]
    });
ログイン後にコピー

3. 复用浏览器

因为每次接口被调用都启动了一个浏览器,截图之后关闭了这个浏览器,造成了资源的浪费,并且启动浏览器也需要耗费时间。并且同时启动的浏览器过多,程序还会抛出异常。所以使用了连接池:启动多个浏览器,在其中一个浏览器下创建标签页打开页面,截图完成后只关闭标签页,保留浏览器。下一次请求过来时直接创建标签页,达到复用浏览器的目的。当浏览器使用次数达到一定数目或者一段时间内没有被使用时就关闭这个浏览器。 有大佬已经对generic-pool这个连接池进行了处理,我就直接拿来用了。

const initPuppeteerPool = () => {
 if (global.pp) global.pp.drain().then(() => global.pp.clear())
 const opt = {
   max: 4,//最多产生多少个puppeteer实例 。
   min: 1,//保证池中最少有多少个puppeteer实例存活
   testOnBorrow: true,// 在将实例提供给用户之前,池应该验证这些实例。
   autostart: false,//是不是需要在池初始化时初始化实例
   idleTimeoutMillis: 1000 * 60 * 60,//如果一个实例60分钟都没访问就关掉他
   evictionRunIntervalMillis: 1000 * 60 * 3,//每3分钟检查一次实例的访问状态
   maxUses: 2048,//自定义的属性:每一个 实例 最大可重用次数。
   validator: () => Promise.resolve(true)
 }
 const factory = {
   create: () =>
     puppeteer.launch({
       //启动参数参考第二条
     }).then(instance => {
       instance.useCount = 0;
       return instance;
     }),
   destroy: instance => {
     instance.close()
   },
   validate: instance => {
     return opt.validator(instance).then(valid => Promise.resolve(valid && (opt.maxUses <= 0 || instance.useCount < opt.maxUses)));
   }
 };
 const pool = genericPool.createPool(factory, opt)
 const genericAcquire = pool.acquire.bind(pool)
 // 重写了原有池的消费实例的方法。添加一个实例使用次数的增加
 pool.acquire = () =>
   genericAcquire().then(instance => {
     instance.useCount += 1
     return instance
   })

 pool.use = fn => {
   let resource
   return pool
     .acquire()
     .then(r => {
       resource = r
       return resource
     })
     .then(fn)
     .then(
       result => {
         // 不管业务方使用实例成功与后都表示一下实例消费完成
         pool.release(resource)
         return result
       },
       err => {
         pool.release(resource)
         throw err
       }
     )
 }
 return pool;
}
global.pp = initPuppeteerPool()
ログイン後にコピー

4. 优化接口防止图片重复生成

        用同一组参数重复调用时每次都会开启一个浏览器进程去截图,可以使用缓存机制优化重复的请求。可以通过传入唯一的key作为标识位(比如用户id+活动id),将图片base64存入redis或者写入内存中。当接口被请求时先查看缓存里是否已经生成过,如果生成过就直接从缓存取。否则就走生成海报的流程。

结尾

        这个方案目前已经开始在项目里试运行了,这对于我一个前端开发来说简直太友好了,再也不用在小程序里一步一步去绘制canvas,不用考虑资源跨域,也不用考虑微信浏览器、各种自带浏览器的兼容问题。省下了时间可以让我写这篇文章。其次,我比较担心的还是性能问题,因为只有在分享的动作才会触发,并发较小,目前使用还未暴露出性能的问题,有了解的大佬们可以指导我一下可以进一步优化或者预防的点。

代码

完整代码查看:github

https://github.com/yuwuwu/markdown-code/tree/master/puppeteer%E6%88%AA%E5%9B%BE

更多node相关知识,请访问:nodejs 教程!!

以上がPuppeteer ライブラリを使用して Node でポスターを生成する方法の簡単な分析 (実装計画の共有)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

nvmでノードを削除する方法 nvmでノードを削除する方法 Dec 29, 2022 am 10:07 AM

nvm でノードを削除する方法: 1. 「nvm-setup.zip」をダウンロードして C ドライブにインストールします; 2. 「nvm -v」コマンドで環境変数を構成し、バージョン番号を確認します; 3. 「nvm」を使用しますinstall" コマンド ノードのインストール; 4. "nvm uninstall" コマンドでインストールしたノードを削除します。

Express を使用してノード プロジェクトでファイルのアップロードを処理する方法 Express を使用してノード プロジェクトでファイルのアップロードを処理する方法 Mar 28, 2023 pm 07:28 PM

ファイルのアップロードをどのように処理するか?次の記事では、Express を使用してノード プロジェクトでファイルのアップロードを処理する方法を紹介します。

NodeサービスのDockerミラーリングを行うにはどうすればよいですか?極限最適化の詳しい説明 NodeサービスのDockerミラーリングを行うにはどうすればよいですか?極限最適化の詳しい説明 Oct 19, 2022 pm 07:38 PM

この期間中、私は Tencent ドキュメントのすべてのカテゴリに共通する HTML 動的サービスを開発していましたが、さまざまなカテゴリへのアクセスの生成と展開を容易にし、クラウド移行のトレンドに従うために、Docker を使用して修正することを検討しました。サービス内容や製品バージョンを一元管理します。この記事では、私が Docker を提供するプロセスで蓄積した最適化の経験を参考として共有します。

Nodeのプロセス管理ツール「pm2」を徹底分析 Nodeのプロセス管理ツール「pm2」を徹底分析 Apr 03, 2023 pm 06:02 PM

この記事では、Node のプロセス管理ツール「pm2」について説明し、pm2 が必要な理由、pm2 のインストール方法と使用方法について説明します。皆様のお役に立てれば幸いです。

PIノードティーチング:PIノードとは何ですか? PIノードをインストールしてセットアップする方法は? PIノードティーチング:PIノードとは何ですか? PIノードをインストールしてセットアップする方法は? Mar 05, 2025 pm 05:57 PM

ピン張りのノードの詳細な説明とインストールガイドこの記事では、ピネットワークのエコシステムを詳細に紹介します - PIノードは、ピン系生態系における重要な役割であり、設置と構成の完全な手順を提供します。 Pinetworkブロックチェーンテストネットワークの発売後、PIノードは多くの先駆者の重要な部分になり、テストに積極的に参加し、今後のメインネットワークリリースの準備をしています。まだピン張りのものがわからない場合は、ピコインとは何かを参照してください。リストの価格はいくらですか? PIの使用、マイニング、セキュリティ分析。パインワークとは何ですか?ピン競技プロジェクトは2019年に開始され、独占的な暗号通貨PIコインを所有しています。このプロジェクトは、誰もが参加できるものを作成することを目指しています

pkg を使用して Node.js プロジェクトを実行可能ファイルにパッケージ化する方法について説明します。 pkg を使用して Node.js プロジェクトを実行可能ファイルにパッケージ化する方法について説明します。 Dec 02, 2022 pm 09:06 PM

Nodejs実行可能ファイルをpkgでパッケージ化するにはどうすればよいですか?次の記事では、pkg を使用して Node プロジェクトを実行可能ファイルにパッケージ化する方法を紹介します。

npm ノード gyp が失敗した場合の対処方法 npm ノード gyp が失敗した場合の対処方法 Dec 29, 2022 pm 02:42 PM

「node-gyp.js」が「Node.js」のバージョンと一致しないため、npm node gyp が失敗します。解決策は次のとおりです: 1. 「npm cache clean -f」を使用してノード キャッシュをクリアします; 2. 「npm install -」を使用します。 g n" n モジュールをインストールします。 3. 「n v12.21.0」コマンドを使用して、「node v12.21.0」バージョンをインストールします。

シングルサインオンシステムとは何ですか? Nodejsを使用して実装するにはどうすればよいですか? シングルサインオンシステムとは何ですか? Nodejsを使用して実装するにはどうすればよいですか? Feb 24, 2023 pm 07:33 PM

シングルサインオンシステムとは何ですか? Nodejsを使用して実装するにはどうすればよいですか?次の記事ではnodeを使ってシングルサインオンシステムを実現する方法を紹介しますので、参考になれば幸いです。

See all articles