优化puppeteer - Sea's Blog
Opened this issue · 4 comments
MrSeaWave commented
MrSeaWave commented
watermark.js
export function htmlGenWaterMark (options) {
// 默认配置
const defaultOption = {
id: 'watermark-id',
// parentEl: '',
// 防止别人外界破坏
preventTamper: false,
// 水印单个图片配置
width: 110,
height: 80,
text: 'watermark',
font: '20px Times New Roman',
fontColor: 'rgba(204,204,204,0.45)',
// 顺时针旋转的弧度
rotateDegree: (30 * Math.PI) / 180,
// 平移变换
translateX: 0,
translateY: 0,
// 水印容器的样式
style: {
'pointer-events': 'none',
width: '100%',
height: '100%',
top: 0,
left: 0,
position: 'fixed',
'z-index': 1000
}
};
let container;
// 创建水印背景图片
function createImageUrl (options) {
const canvas = document.createElement('canvas');
const text = options.text;
canvas.width = options.width;
canvas.height = options.height;
const ctx = canvas.getContext('2d');
ctx.shadowOffsetX = 2; // X轴阴影距离,负值表示往上,正值表示往下
ctx.shadowOffsetY = 2; // Y轴阴影距离,负值表示往左,正值表示往右
ctx.shadowBlur = 2; // 阴影的模糊程度
// ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; //阴影颜色
ctx.font = options.font;
ctx.fillStyle = options.fontColor;
ctx.rotate(options.rotateDegree);
ctx.translate(options.translateX, options.translateY);
ctx.textAlign = 'left';
// 在 (x, y)位置填充实体文本
ctx.fillText(text, 35, 32);
return canvas.toDataURL('image/png');
}
// 将背景填充至指定水印位置处
function createContainer (options, forceCreate) {
const oldDiv = document.getElementById(options.id);
if (!forceCreate && oldDiv) return container;
const url = createImageUrl(options);
const div = oldDiv || document.createElement('div');
div.id = options.id;
// 水印容器的父元素,默认document.body
let parentEl = options.preventTamper ? document.body : options.parentEl || document.body;
if (typeof parentEl === 'string') {
if (parentEl.startsWith('#')) parentEl = parentEl.substring(1);
parentEl = document.getElementById(parentEl);
}
// 返回元素的大小及其相对于视口的位置。
const rect = parentEl.getBoundingClientRect();
// 默认:按照父元素的偏移位置
options.style.left = (options.left || rect.left) + 'px';
options.style.top = (options.top || rect.top) + 'px';
div.style.cssText = getStyleText(options);
div.setAttribute('class', '');
div.style.background = 'url(' + url + ') repeat top left';
!oldDiv && parentEl.appendChild(div);
return div;
}
// 获取配置中的style
function getStyleText (options) {
let ret = '';
const style = options.style;
Object.keys(style).forEach((k) => {
ret += k + ': ' + style[k] + ';';
});
return ret;
}
// 入口函数
function init (options) {
options = !options ? defaultOption : { ...defaultOption, ...options };
container = createContainer(options);
}
init(options);
}
ruiyongsheng commented
大佬,文章写的很不错,首先给你点个赞👍🏻,有个问题,不知道您遇到了么?
如果不执行 browser.disconnect()
, 会造成 Estab Connections over
每次建立 TCP
连接后会一直 ESTABLISHED
;
所以在 puppeteer 每次执行任务完成之后,需要在 finally
方法里 执行
await page.close()
await browser.disconnect();
MrSeaWave commented
@ruiyongsheng 暂时没有遇到过😂,不过await browser.disconnect()
也是可以添加在finally
里,不会影响代码运行。
async screenshot() {
....
} finally {
console.log('【PuppeteerHelper】结束截图,关闭当前页面');
// 无论截图失败还是成功都会关闭当前页面
await page.close();
await browser.disconnect();
}
}
MrSeaWave commented
这里再介绍下:browser.disconnect: 断开 Puppeteer 和浏览器的连接,但 Chromium 进程仍然在运行。在调用 disconnect 之后,Browser 对象本身被认为是处理过的并不能再被使用。
如下,一个断开连接和重连到 Browser 的例子:
const puppeteer = require('puppeteer');
puppeteer.launch().then(async browser => {
// 存储节点以便能重新连接到 Chromium
const browserWSEndpoint = browser.wsEndpoint();
// 从 Chromium 断开和 puppeteer 的连接
browser.disconnect();
// 使用节点来重新建立连接
const browser2 = await puppeteer.connect({browserWSEndpoint});
// 关闭 Chromium
await browser2.close();
});