C# Winform 使用 PuppeteerSharp 进行网页截图、生成pdf等操作
項目背景
? ? ? ? 公司某項目上有一需求:要對合同、驗收、付款申請單等審批頁面進行截圖,并生成Pdf文件回傳到影像系統做最終的歸檔。然后衍生出來了一個WinForm的自動截圖工具,其大致的實現邏輯是:定時請求數據庫,抓取帶截圖的數據,組裝得到審批頁面地址,winfrom中引用WebView進行加載地址,在OnLoadingFinish加載完成方法里面,通過ScreenShot()獲取等到Bitmap對象,然后在進行pdf文檔的生成。
? ? ? ? 弊端:因為是前后端分離的項目,OnLoadingFinish中無法判定ajax請求是否完畢,還需要定時器進行延遲截圖、保存;其次是穩定性不高,可能是技術問題,經常導致程序奔潰,并且winform無法捕獲到異常,但是另外一個項目崩潰幾率很小,可能是數據量小吧
重構
? ? ? ? 基于原項目使用的WebVIew,控件老舊,并且功能不太優化,所以采用了PuppeteerSharp進行了重構。
運行環境:Windows 服務器 開發環境:Vs@2017、.net framework 4.6以及以上,本項目4.8PuppeteerSharp?
????????Puppeteer是一個通過 DevTools Protocol 控制 headless chrome 的 high-level Node 庫,也可以通過設置使用 非 headless Chrome。
我們手工可以在瀏覽器上做的事情,Puppeteer 都能勝任:
????????PuppeteerSharp是官方Node.JS Puppeteer API的.NET移植。
? ? ? ? 1.由于Puppeteer-Sharp是NetStandard 2.0庫,因此最低平臺版本是.NET Framework 4.6.1和.NET Core 2.0
? ? ? ? 2.支持WebSocket庫的最低Windows版本是Windows 8和Windows Server 2012,具體參見?System.Net.WebSockets Namespace | Microsoft Docs
安裝
? ? ? ? 1.使用Nuget搜索PuppeteerSharp,找到PuppeteerSharp點擊安裝即可。
PuppeteerSharp的使用? ? ?
? ? ? ? ?1.獲取Browsers對象
private async Task<Browser> Browsers(){try{await slimLock.WaitAsync();// 已經拷貝了.local-chromium,不需要再下載了//await new BrowserFetcher().DownloadAsync();if (_browser == null){_browser = await Puppeteer.LaunchAsync(new LaunchOptions{Headless = true, DefaultViewport = null,//Args = new string[] {// "--disable-infobars",//隱藏 自動化標題// "--no-sandbox", // 沙盒模式// "--start-maximized" // 最大化//}}); ;return _browser;}return _browser;}catch (Exception ex){throw ex;}finally{slimLock.Release();}}? ? ? ? 2.生成Pdf,注意看注釋,方法中有倆種邏輯【一種是先生成圖片,然后圖片轉成pdf;一種是官方的生成pdf的方法,只不過官方的會有分頁,長頁面看著不太優化,所以采用了第一種方式】
private async Task BrowsersPageToPdf(string loadUrl, string savePath){var page = await _browser.NewPageAsync();// 設置頁面分辨率await page.SetViewportAsync( new ViewPortOptions(){ Width = 1400, Height = 1050 });ScreenshotLoading("頁面加載完成,等待數據渲染");//load: window.onload事件被觸發時候完成導航,某些情況下它根本不會發生。//domcontentloaded: Domcontentloaded事件觸發時候認為導航成功//networkidle0: 在 500ms 內沒有網絡連接時就算成功(全部的request結束),才認為導航結束//networkidle2: 500ms 內有不超過 2 個網絡連接時就算成功(還有兩個以下的request),就認為導航完成//加載時長 networkidle0 > networkidle2 > load > domcontentloadedawait page.GoToAsync(loadUrl, new NavigationOptions() { WaitUntil = new WaitUntilNavigation[] { WaitUntilNavigation.Networkidle0 } });ScreenshotLoading("頁面加載完成,數據渲染完成,頁面截圖中....");ScreenshotOptions screenshotOptions = new ScreenshotOptions();//screenshotOptions.Clip = new PuppeteerSharp.Media.Clip() { Height = 0, Width = 0, X = 0, Y = 0 };//設置截剪區域screenshotOptions.FullPage = true; //是否截取整個頁面screenshotOptions.OmitBackground = false;//是否使用透明背景,而不是默認白色背景screenshotOptions.Quality = 100; //截圖質量 0-100(png不可用)screenshotOptions.Type = ScreenshotType.Jpeg; //截圖格式var saveFile = System.IO.Path.GetDirectoryName(savePath);if (!Directory.Exists(saveFile)){FileInfo fi = new FileInfo(saveFile);Directory.CreateDirectory(fi.DirectoryName);}string imgUrl = saveFile + "\\" + CurrentHandlerData.DataKey + "_" + Guid.NewGuid() + ".jpg";await page.ScreenshotAsync(imgUrl, screenshotOptions);ScreenshotLoading("頁面截圖完成,正在轉Pdf文件...");//var stream = await page.ScreenshotStreamAsync();CommonHelper.ConvertJpg2Pdf(imgUrl, savePath);ScreenshotLoading("頁面截圖完成,Pdf文件生成成功!");CommonHelper.FileDel(imgUrl);ScreenshotLoading("頁面截圖文件刪除成功!");//官方生成Pdf方法//設置PDF選項//PdfOptions pdfOptions = new PdfOptions();//pdfOptions.DisplayHeaderFooter = false; //是否顯示頁眉頁腳//pdfOptions.FooterTemplate = ""; //頁腳文本//pdfOptions.Format = new PuppeteerSharp.Media.PaperFormat(11.27m, 30m); //pdf紙張格式 英寸為單位 pdfOptions.Format = PaperFormat.A4;//pdfOptions.PrintBackground = true; // false pdf文件為灰白色,一些背景色也顯示出來; true 頁面為彩色//pdfOptions.HeaderTemplate = ""; //頁眉文本//pdfOptions.Landscape = false; //紙張方向 false-垂直 true-水平//pdfOptions.MarginOptions = new PuppeteerSharp.Media.MarginOptions() { Bottom = "0px", Left = "0px", Right = "0px", Top = "0px" }; //紙張邊距,需要設置帶單位的值,默認值是None//pdfOptions.Scale = 1m; //PDF縮放,從0-1//await page.PdfAsync(savePath, pdfOptions);await page.DisposeAsync();}坑點:
? ? ? ? 1.puppeteer需要Chromium 內核用以加載網頁,所以要先調用類庫的下載sdk,他自動幫你下載Chromium ,這也可能導致第一次沒有Chromium會卡一陣子,因為在下載 ,完成之后,再程序根目錄【bin/Debug】下會發現.local-chromium 的一個文件夾
? ? ? ? 2.獲取Browser對象時,如果LaunchOptions.Headless設置為false,不能進行pdf文件生成,可以截圖,同時可以看到程序調用的headless chrome的窗口
? ? ? ? 3.LaunchOptions.DefaultViewport 為null,瀏覽的頁面會默認瀏覽器窗口大小,也可以自定義其大小【沒有試過】,否則的話,在chrome中可以看到,右邊會有部分留白
? ? ? ? 4.截圖之前最好設置下分辨率:SetViewportAsync,否則圖可能截不全
? ? ? ? 5.有的復雜網頁可能要加載一段時間,不然截圖是空白或者不完整的,可以延時或者使用類庫提供的等待方法【特別是前后端分離的項目,注意看生成pdf方法中的注釋】
其他
????????PuppeteerSharp還可以進行:向網頁中注入HTML、執行Javascript(js)代碼、連接到遠程瀏覽器等等其他功能,也可以用于爬蟲場景,其他功能可以看下官方介紹
? ? ? ? 圖片轉Pdf方法:
public static void ConvertJpg2Pdf(string jpgfile, string pdf){var document = new Document();using (var stream = new FileStream(pdf, FileMode.Create, FileAccess.Write, FileShare.None)){var pdfWriter = PdfWriter.GetInstance(document, stream);using (var imageStream = new FileStream(jpgfile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)){var image = iTextSharp.text.Image.GetInstance(imageStream);pdfWriter.CloseStream = false;document.SetPageSize(new iTextSharp.text.Rectangle(image.Width + 72f, image.Height + 72f));//(WWidth + 72f, HHeight + 72f));document.Open();image.Alignment = iTextSharp.text.Image.ALIGN_MIDDLE;document.Add(image);}document.Close();}}總結
以上是生活随笔為你收集整理的C# Winform 使用 PuppeteerSharp 进行网页截图、生成pdf等操作的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java做抽奖系统怎么搞_JAVA 随机
- 下一篇: c# char unsigned_dll