목차
Puppeteer 소개
솔루션 구현
结尾
웹 프론트엔드 JS 튜토리얼 Puppeteer 라이브러리를 사용하여 Node에서 포스터를 생성하는 방법에 대한 간략한 분석(구현 계획 공유)

Puppeteer 라이브러리를 사용하여 Node에서 포스터를 생성하는 방법에 대한 간략한 분석(구현 계획 공유)

Jan 18, 2022 pm 07:26 PM
node

Node를 사용하여 포스터를 생성하는 방법은 무엇입니까? 다음 글에서는 Node+Puppeteer를 사용하여 포스터를 생성하는 방법을 소개하겠습니다. 도움이 되길 바랍니다!

Puppeteer 라이브러리를 사용하여 Node에서 포스터를 생성하는 방법에 대한 간략한 분석(구현 계획 공유)

이전 글에서 며칠 전 html2canvas를 사용하다가 많은 호환성 문제에 부딪혀 버킷을 들고 도망갈 뻔했다고 적었습니다. 그러다가 댓글 영역의 전문가들의 지도를 통해 작동이 간단하고 재사용 가능성이 높은 포스터 생성 솔루션인 Node+Puppeteer가 포스터를 생성합니다를 발견했습니다.

주요 디자인 아이디어는: 포스터 생성을 위한 인터페이스에 액세스하는 것입니다. 인터페이스는 Puppeteer를 통해 수신 주소에 액세스하고 해당 요소의 스크린샷을 반환합니다.

캔버스 생성에 비해 Puppeteer를 사용한 포스터 생성의 장점은 무엇입니까?

  • 브라우저 호환성, 플랫폼 호환성 및 기타 문제가 없습니다.
  • 코드는 재사용성이 뛰어나며 h5, 미니 프로그램 및 앱용 포스터를 생성하는 데 사용할 수 있습니다.
  • 최적화 작업을 위한 더 많은 공간. 포스터를 생성하는 인터페이스로 변경되었기 때문에 서버 추가, 캐시 추가

Puppeteer 소개

Puppeteer는 Nodejs입니다. DevTools 프로토콜을 통해 Chromium 또는 Chrome을 제어하기 위한 고급 API를 제공하는 라이브러리입니다. Puppeteer는 기본적으로 헤드리스 모드, 즉 "헤드리스" 모드에서 실행되지만 headless:false 구성을 수정하여 "헤드리스" 모드를 실행할 수 있습니다. 브라우저에서 수동으로 수행하는 대부분의 작업은 Puppeteer를 사용하여 수행할 수 있습니다! 다음은 몇 가지 예입니다.

  • 페이지 PDF 또는 스크린샷을 생성합니다.
  • SPA(단일 페이지 애플리케이션)를 포착하고 사전 렌더링된 콘텐츠(예: "SSR"(서버 측 렌더링))를 생성하세요.
  • 자동으로 양식 제출, UI 테스트, 키보드 입력 등을 수행합니다.
  • 지속적으로 업데이트되는 자동화된 테스트 환경을 만듭니다. 최신 JavaScript 및 브라우저 기능을 사용하여 최신 버전의 Chrome에서 직접 테스트를 실행하세요.
  • 웹사이트의 타임라인 추적을 캡처하여 성능 문제를 분석하는 데 도움을 줍니다.
  • 브라우저 확장 기능을 테스트하세요.

솔루션 구현

1. 간단한 인터페이스 작성

Express는 간단하고 유연한 node.js 웹 애플리케이션 프레임워크입니다. 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([옵션]): 브라우저 실행
  • browser.newPage(): 탭 페이지 생성
  • page.goto(url[, options]): 페이지 탐색
  • page.setViewport(viewport): 페이지를 열 창을 지정
  • page .$ (선택기): 요소 선택
  • elementHandle.screenshot([옵션]): 스크린샷. 인코딩 속성은 반환 값이 base64 또는 Buffer
  • browser.close()임을 지정할 수 있습니다. 브라우저 및 탭 페이지를 닫습니다

3. 최적화

1. goto( url[, options]) 메소드의 waitUntil 구성 항목은 실행이 완료된 상태를 나타냅니다. 기본값은 로드 이벤트가 트리거되는 시점입니다. 이벤트에는 다음이 포함됩니다.

 await page.goto(url, {
     waitUntil: [
         'load', //页面“load” 事件触发
         'domcontentloaded', //页面 “DOMcontentloaded” 事件触发
         'networkidle0', //在 500ms 内没有任何网络连接
         'networkidle2' //在 500ms 内网络连接个数不超过 2 个
     ]
 });
로그인 후 복사

networkidle0 솔루션을 사용하여 페이지가 완료될 때까지 기다리는 경우 networkidle0이 500ms를 기다려야 하기 때문에 인터페이스의 응답 시간이 더 길어지는 것을 알 수 있습니다. 대부분의 경우 기다릴 필요가 없으므로 지연 시간을 사용자 정의할 수 있습니다. 예를 들어, 포스터 페이지는 배경 이미지와 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 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 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

nvm에서 노드를 삭제하는 방법 nvm에서 노드를 삭제하는 방법 Dec 29, 2022 am 10:07 AM

nvm을 사용하여 노드를 삭제하는 방법: 1. "nvm-setup.zip"을 다운로드하여 C 드라이브에 설치합니다. 2. "nvm -v" 명령을 통해 환경 변수를 구성하고 버전 번호를 확인합니다. 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를 서비스하면서 쌓은 최적화 경험을 여러분의 참고용으로 공유하겠습니다.

PI 노드 교육 : PI 노드 란 무엇입니까? Pi 노드를 설치하고 설정하는 방법은 무엇입니까? PI 노드 교육 : PI 노드 란 무엇입니까? Pi 노드를 설치하고 설정하는 방법은 무엇입니까? Mar 05, 2025 pm 05:57 PM

Pinetwork 노드에 대한 자세한 설명 및 설치 안내서이 기사에서는 Pinetwork Ecosystem을 자세히 소개합니다. Pi 노드, Pinetwork 생태계의 주요 역할을 수행하고 설치 및 구성을위한 전체 단계를 제공합니다. Pinetwork 블록 체인 테스트 네트워크가 출시 된 후, PI 노드는 다가오는 주요 네트워크 릴리스를 준비하여 테스트에 적극적으로 참여하는 많은 개척자들의 중요한 부분이되었습니다. 아직 Pinetwork를 모른다면 Picoin이 무엇인지 참조하십시오. 리스팅 가격은 얼마입니까? PI 사용, 광업 및 보안 분석. Pinetwork 란 무엇입니까? Pinetwork 프로젝트는 2019 년에 시작되었으며 독점적 인 Cryptocurrency Pi Coin을 소유하고 있습니다. 이 프로젝트는 모든 사람이 참여할 수있는 사람을 만드는 것을 목표로합니다.

Node의 프로세스 관리 도구 'pm2”에 대한 심층 분석 Node의 프로세스 관리 도구 'pm2”에 대한 심층 분석 Apr 03, 2023 pm 06:02 PM

이 기사에서는 Node의 프로세스 관리 도구인 "pm2"를 공유하고 pm2가 필요한 이유, pm2 설치 및 사용 방법에 대해 설명합니다. 모두에게 도움이 되기를 바랍니다!

Angular 및 Node를 사용한 토큰 기반 인증 Angular 및 Node를 사용한 토큰 기반 인증 Sep 01, 2023 pm 02:01 PM

인증은 모든 웹 애플리케이션에서 가장 중요한 부분 중 하나입니다. 이 튜토리얼에서는 토큰 기반 인증 시스템과 기존 로그인 시스템과의 차이점에 대해 설명합니다. 이 튜토리얼이 끝나면 Angular와 Node.js로 작성된 완벽하게 작동하는 데모를 볼 수 있습니다. 기존 인증 시스템 토큰 기반 인증 시스템으로 넘어가기 전에 기존 인증 시스템을 살펴보겠습니다. 사용자는 로그인 양식에 사용자 이름과 비밀번호를 입력하고 로그인을 클릭합니다. 요청한 후 데이터베이스를 쿼리하여 백엔드에서 사용자를 인증합니다. 요청이 유효하면 데이터베이스에서 얻은 사용자 정보를 이용하여 세션을 생성하고, 세션 정보를 응답 헤더에 반환하여 브라우저에 세션 ID를 저장한다. 다음과 같은 애플리케이션에 대한 액세스를 제공합니다.

npm node gyp가 실패하는 경우 수행할 작업 npm node gyp가 실패하는 경우 수행할 작업 Dec 29, 2022 pm 02:42 PM

"node-gyp.js"와 "Node.js"의 버전이 일치하지 않아 npm node gyp가 실패했습니다. 해결 방법: 1. "npm 캐시 clean -f"를 통해 노드 캐시를 지웁니다. 2. "npm install - g n" n 모듈을 설치합니다. 3. "n v12.21.0" 명령을 통해 "node v12.21.0" 버전을 설치합니다.

pkg를 사용하여 Node.js 프로젝트를 실행 파일로 패키징하는 방법에 대해 이야기해 보겠습니다. pkg를 사용하여 Node.js 프로젝트를 실행 파일로 패키징하는 방법에 대해 이야기해 보겠습니다. Dec 02, 2022 pm 09:06 PM

nodejs 실행 파일을 pkg로 패키징하는 방법은 무엇입니까? 다음 기사에서는 pkg를 사용하여 Node 프로젝트를 실행 파일로 패키징하는 방법을 소개합니다. 도움이 되기를 바랍니다.

See all articles