Puppeteer 라이브러리를 사용하여 Node에서 포스터를 생성하는 방법에 대한 간략한 분석(구현 계획 공유)
Node를 사용하여 포스터를 생성하는 방법은 무엇입니까? 다음 글에서는 Node+Puppeteer를 사용하여 포스터를 생성하는 방법을 소개하겠습니다. 도움이 되길 바랍니다!
이전 글에서 며칠 전 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 个 ] });
const waitTime = (n) => new Promise((r) => setTimeout(r, n)); //省略部分代码 await page.goto(opt.url); await waitTime(opt.waitTime || 0);
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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

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

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

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

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

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

nvm을 사용하여 노드를 삭제하는 방법: 1. "nvm-setup.zip"을 다운로드하여 C 드라이브에 설치합니다. 2. "nvm -v" 명령을 통해 환경 변수를 구성하고 버전 번호를 확인합니다. install" 명령 노드 설치; 4. "nvm uninstall" 명령을 통해 설치된 노드를 삭제합니다.

파일 업로드를 처리하는 방법은 무엇입니까? 다음 글에서는 Express를 사용하여 노드 프로젝트에서 파일 업로드를 처리하는 방법을 소개하겠습니다. 도움이 되길 바랍니다.

이 기간 동안 저는 Tencent 문서의 모든 카테고리에 공통되는 HTML 동적 서비스를 개발 중입니다. 다양한 카테고리에 대한 액세스 생성 및 배포를 촉진하고 클라우드로 이동하는 추세에 부응하기 위해. Docker를 사용하여 서비스 콘텐츠를 수정하고 제품 버전을 균일하게 관리합니다. 이 글에서는 제가 Docker를 서비스하면서 쌓은 최적화 경험을 여러분의 참고용으로 공유하겠습니다.

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

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

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

"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" 버전을 설치합니다.

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