MrSeaWave / blogs

✍🏻 个人博客,记录、分享一写随笔和技术知识
https://hailangya.com
3 stars 0 forks source link

优化puppeteer - Sea's Blog #40

Open MrSeaWave opened 3 years ago

MrSeaWave commented 3 years ago

https://mrseawave.github.io/blogs/articles/2021/07/05/optimize-puppeteer/#more

本文将讲述如何优化puppeteer

MrSeaWave commented 3 years ago

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 2 years ago

大佬,文章写的很不错,首先给你点个赞👍🏻,有个问题,不知道您遇到了么? 如果不执行 browser.disconnect(), 会造成 Estab Connections over 每次建立 TCP 连接后会一直 ESTABLISHED; 所以在 puppeteer 每次执行任务完成之后,需要在 finally 方法里 执行

await page.close()
await browser.disconnect();
MrSeaWave commented 2 years ago

@ruiyongsheng 暂时没有遇到过😂,不过await browser.disconnect()也是可以添加在finally里,不会影响代码运行。

 async screenshot() {
   ....
    } finally {
      console.log('【PuppeteerHelper】结束截图,关闭当前页面');
      // 无论截图失败还是成功都会关闭当前页面
      await page.close();
      await browser.disconnect();
    }
  }
MrSeaWave commented 2 years ago

这里再介绍下: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();
});