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); } }
评论区