.net core 3.1使用PuppeteerSharp截图(一窗体多窗口版)

    public class PuppeteerSharpHelps
    {
        public PuppeteerSharpHelps()
        {

        }
        private static PuppeteerSharp.Browser _browser { get; set; }
        /// <summary>
        /// 截图完成回调
        /// </summary>
        public static event EventHandler ScreenshotComplete;
        /// <summary>
        /// 截图出错回调
        /// </summary>
        public static event EventHandler ScreenshotError;
        /// <summary>
        /// 初始化浏览
        /// </summary>
        /// <returns></returns>
        private async static Task<Browser> InItBrowser()
        {
            try
            {
                await slimLock.WaitAsync();
                var result = await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
                if (_browser == null)
                {
                    Debug.WriteLine("标识输出");
                    _browser = await Puppeteer.LaunchAsync(new LaunchOptions
                    {
                        Headless = true,
                        Args = new string[] {
                            "--disable-infobars",//隐藏 自动化标题
                            "--no-sandbox", // 沙盒模式
                        },
                    });
                    return _browser;
                }
                return _browser;
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                slimLock.Release();
            }
        }
        /// <summary>
        /// 异步线程锁(让浏览器只初始化一次)
        /// </summary>
        private static SemaphoreSlim slimLock = new SemaphoreSlim(1, 1);
        /// <summary>
        /// 异步线程锁(锁定每次只处理10个任务)
        /// </summary>
        private static readonly SemaphoreSlim _mutex = new SemaphoreSlim(10);
        /// <summary>
        /// 异步截图
        /// </summary>
        /// <param name="loadUrl">加载的url</param>
        /// <param name="savePath">保存路径要带保存文件名称</param>
        /// <param name="width">设置浏览器的宽度</param>
        /// <param name="height">设置浏览器的高度</param>
        /// <param name="isTagName">判断当前传入的标签名称是否存在,存在则截图</param>
        /// <returns></returns>
        public static async Task ScreenshotAsync(string loadUrl, string savePath, string isTagName = null, string uniqueId = null, int width = 0, int height = 0)
        {
            try
            {

                await _mutex.WaitAsync();
                _browser ??= await InItBrowser();
                if (width == 0 || height == 0)
                {
                    await BrowserPages(_browser, loadUrl, savePath, isTagName);
                }
                else
                {
                    await BrowserPages(_browser, loadUrl, savePath, width, height, isTagName);
                }

            }
            catch (Exception ex)
            {
                if (_browser != null)
                {
                    await _browser?.CloseAsync();
                }
                _browser = null;
                GC.Collect();
                throw ex;
            }
            finally
            {
                _mutex.Release();
                GC.Collect();
            }
        }

        private static async Task BrowserPages(Browser browser, string loadUrl, string savePath, string isTagName, string uniqueId = null)
        {
            Page page = await browser.NewPageAsync();
            page.Load += async (sender, e) =>
            {
                try
                {
                    var _page = (Page)sender;
                    if (!string.IsNullOrEmpty(isTagName))
                    {
                        var tag = await page.QuerySelectorAsync(isTagName);
                        if (tag != null)
                        {
                            await page.ScreenshotAsync(savePath, new ScreenshotOptions() { Type = ScreenshotType.Png });
                            if (ScreenshotComplete != null)
                                ScreenshotComplete(savePath, new ScreenshotEventArgs() { IsScreenshot = true, SavePath = savePath, UniqueId = uniqueId });
                        }
                    }
                    await page.CloseAsync();
                }
                catch (Exception ex)
                {
                    //出错释放当前page资源
                    page.Dispose();
                    if (ScreenshotError != null)
                        ScreenshotError(savePath, new ScreenshotErrorEventArgs() { Error = ex, IsScreenshot = false, SavePath = savePath });
                }
            };

            page.Close += async (sender, e) =>
            {
                var pg = (Page)sender;
                var size = await pg.Browser.PagesAsync();
                if (size.Length <= 1)
                {
                    if (browser != null)
                    {
                        await browser.DisposeAsync();
                    }
                    browser = null;
                }
            };
            await page.SetViewportAsync(new ViewPortOptions
            {
                Width = 1000,
                Height = 1000
            });
            await page.GoToAsync(loadUrl);

        }

        private static async Task BrowserPages(Browser browser, string loadUrl, string savePath, int width, int height, string isTagName, string uniqueId = null)
        {
            Page page = await browser.NewPageAsync();
            //加载页面完成触发事件
            page.Load += async (sender, e) =>
            {
                try
                {
                    var load = (Page)sender;
                    if (!string.IsNullOrEmpty(isTagName))
                    {
                        var tag = await page.QuerySelectorAsync(isTagName);
                        if (tag != null)
                        {
                            await page.ScreenshotAsync(savePath, new ScreenshotOptions() { Type = ScreenshotType.Png });
                            if (ScreenshotComplete != null)
                                ScreenshotComplete(savePath, new ScreenshotEventArgs() { IsScreenshot = true, SavePath = savePath, UniqueId = uniqueId });
                        }
                    }
                    await page.CloseAsync();
                }
                catch (Exception ex)
                {
                    //出错释放当前page资源
                    page.Dispose();
                    if (ScreenshotError != null)
                        ScreenshotError(savePath, new ScreenshotErrorEventArgs() { Error = ex, IsScreenshot = false, SavePath = savePath });
                }
            };
            //关闭page窗口页触发事件
            page.Close += async (sender, e) =>
            {
                var pg = (Page)sender;
                var size = await pg.Browser.PagesAsync();
                if (size.Length <= 1)
                {
                    if (browser != null)
                    {
                        await browser.DisposeAsync();
                    }
                    browser = null;
                }
            };
            await page.SetViewportAsync(new ViewPortOptions
            {
                Width = width,
                Height = height
            });
            await page.GoToAsync(loadUrl);

        }
    }

    public class ScreenshotEventArgs : EventArgs
    {
        /// <summary>
        /// 截图成功为true
        /// </summary>
        public bool IsScreenshot { get; set; }

        /// <summary>
        /// 截图保存的路径
        /// </summary>
        public string SavePath { get; set; }

    }

    public class ScreenshotErrorEventArgs : EventArgs
    {
        /// <summary>
        /// 截图成功为true
        /// </summary>
        public bool IsScreenshot { get; set; }
        /// <summary>
        /// 截图保存的路径
        /// </summary>
        public string SavePath { get; set; }
        /// <summary>
        /// 出错内容
        /// </summary>
        public object Error { get; set; }

    }

测试:

for (int i = 1; i <= 50; i++)
                {
                    if ((i % 2) == 0)
                    {
                        PuppeteerSharpHelps.ScreenshotAsync("https://www.baidu.com", $"F://test{i}.png", i);
                    }
                    else
                    {
                        PuppeteerSharpHelps.ScreenshotAsync("https://www.csdn.net/", $"F://test{i}.png", i);
                    }
                }


本文作者:admin

本文链接:https://www.javalc.com/post/51.html

版权声明:本篇文章于2020-12-30,由admin发表,转载请注明出处:分享你我。如有疑问,请联系我们

.net core 3.1多线程使用PuppeteerSharp截图打开窗体过多导致卡死问题解决
16 条评论
  • 嘻嘻  2020-12-31  回复
  • 好家伙,我这几天也在搞这个,用的是electron+puppeteer 结果,cluster 调用时用不了,而且没法打包,
    • wlc  2020-12-31  回复
    • 你想实现怎么样的效果呢?
      • 嘻嘻  2020-12-31  回复
      • 我的功能做到了,同事给了我几个网址,让我将里面的内容保存图片出来,只是每次只能跑少点数据,不然打开的浏览器太多,系统都要炸了,嘻嘻,
        • wlc  2020-12-31  回复
        • 保证每次请求const browser = await puppeteer.launch();这个只初始化一次,问题就解决了
        • wlc  2020-12-31  回复
        • 引入异步锁
          var AsyncLock = require('async-lock');
          var lock = new AsyncLock();
          定义全局变量接收
          await puppeteer.launch();
          初始化。然后判断这个全局变量是否为空值,如果为空则初始化 await puppeteer.launch();不为空直接返回这个全局变量,可能需要以闭包的方式实现
        • wlc  2020-12-31  回复
        • 单线程情况下不需要锁
      • 嘻嘻  2020-12-31  回复
      • https://toolandhelp.com/0.png 这个时效果,哈哈
  • wlc  2021-01-01  回复
  • 复制这段内容后打开百度网盘App,操作更方便哦。 链接:https://pan.baidu.com/s/13uiqtNB55q5uWMbW_cNrZA 提取码:qx8d--来自百度网盘超级会员V4的分享 electron demo
    • 嘻嘻  2021-01-04  回复
    • 大哥,厉害,回家还写了dome啊,你时V4也不用把整个node_modules上传了吧 ^_^
  • 嘻嘻  2021-01-04  回复
  • 真有你的,本来几kb就完事了,硬是要下载180+M 你就是想秀你的百度网盘V4的:).
    • wlc  2021-01-04  回复
    • 这话说得,本想放花里蓝奏云的,那台电脑没有记录蓝奏云的密码,阿里云盘又不能分享,只好放度盘了
    • wlc  2021-01-04  回复
    • 这话说得,本想放花里蓝奏云的,那台电脑没有记录蓝奏云的密码,阿里云盘又不能分享,只好放度盘了
      • 嘻嘻  2021-01-04  回复
      • 不得鸟不得鸟,怎么多云盘啊,有没有115啊?哼小?
        • wlc  2021-01-04  回复
        • 有,免费的35tb

发表评论

取消
扫码支持
登录
用户名
密码
注册
用户名
密码(至少8位)
确认密码
昵称
邮箱(请填写常用邮箱)
获取邀请码
邀请码
验证码
找回密码
用户名
邮箱
※ 重置链接将发送到邮箱