前言

你聽過隕石開發法嗎?
沒聽過?那你可以看看轉載好文:隕石開發法
甚麼?你問隕石開發法跟這篇文有甚麼關係?

因為神有了需求

本文

上次有提到 Puppeteer Sharp 這個套件、以及黑大這篇文 C# 整合 Headless Chrome 的好工具 - Puppeteer Sharp ,但因為我的 chromium 版本一直無法運行就此作罷;直到主管突然提起同單位有人成功使用這個套件實作出功能。

  • 這時候別人用了同工具可以,沒道理我不行的心就蠢蠢欲動了。

把問題倒回碰到的起始點,是 chromium 無法運行,想想應該是套件抓下來的版本有問題,於是我研究了一下 chromuim 的版本,官方文件在此,發現版本其實分很多種,有開發版、測試版、穩定版,於是研究了一下就到此網址下載了官方提供版本更換套件內抓取的chromium測試。

1、 先到專案資料夾底下 bin > Debugger > .local-chromium 內。

2、將下載版本複製貼上並取代此資料夾內檔案。

3、進行測試。


	static void Main(string[] args)
        {
		Test().Wait();
	}

        static async Task Test()
        {
            try
            {
                await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
                using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions()
                {
                    Headless = true //偵測時可設定false觀察網頁顯示結果(註:非Headless時不能匯出PDF)
                }))
                {
                    using (var page = await browser.NewPageAsync())
                    {
                        await page.GoToAsync("https://sunnyday0932.github.io/2020/%E7%B6%B2%E9%A0%81%E6%88%AA%E5%9C%96%E8%BD%89%E6%88%90pdf%E6%AA%94%E7%B4%94%E5%B1%AC%E5%A5%BD%E7%8E%A9/");
                        Thread.Sleep(1000);  
                        await page.ScreenshotAsync($"D:\\test\\Snapshot.png");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                throw;
            }
        }

實際結果

測試成功後我們回到需求本身,是需要將兩個不同的網頁合成為一個 pdf 檔案,研究了一下套件用法,我選擇結合 itextSharp 達成目的。

	static void Main(string[] args)
        {
			Test().Wait();
        }

        static async Task Test()
        {
            try
            {
				
		var firstUrl = $"https://github.com/explore";
		var secondUrl = $"https://leetcode.com/";

		byte[] mergePage = null;
		await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
		var pdfUrl = new[] { firstUrl, secondUrl };

		using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions()
		{
			Headless = true //偵測時可設定false觀察網頁顯示結果(註:非Headless時不能匯出PDF)
		}))
		{
			using (var stream = File.Create(@"D:\test\test.pdf"))
			using (var doc = new Document(PageSize.A4))
			using (var pdfWriter = PdfWriter.GetInstance(doc, stream))
			using (var page = await browser.NewPageAsync())
			{
				doc.Open();
				foreach (var item in pdfUrl)
				{
					await page.GoToAsync(item, new NavigationOptions
					{
						//此方法可以偵測JS連線都完成了
						WaitUntil = new WaitUntilNavigation[2]
					});
					//但用上述waitUntil方式我的目標網站渲染方式不同,所以最後還是加上了等待。
					Thread.Sleep(1000);		
					mergePage = await page.ScreenshotDataAsync(new ScreenshotOptions
					{
						OmitBackground = true,		//是否顯示背景圖式
						FullPage = true,		//是否整頁
						Type = ScreenshotType.Jpeg,     //可以設定檔案格式
						Quality = 100			//可以設定照片品質
					});

					//檔案都取回後再透過itextSharp進行處理
					var image = iTextSharp.text.Image.GetInstance(mergePage);
					//這邊可以調整圖片大小
					image.ScalePercent(60);
					doc.Add(image);
					}
				doc.Close();
				doc.Dispose();
				}
			}
		} 
            catch (Exception ex)
            {
			Console.WriteLine(ex.ToString());
			throw;
	    }
        }

實際結果

  • 第一頁

  • 第二頁

後記

原本以為只是說著玩的,突然就…

網頁截圖還有許多奧妙啊…譬如實際抓取網路渲染時間其實也是會有誤差,所以此方法目前是研究出來可行性最高的方式了,但一次運行還是要跑個十秒,所以不知道實際上線功能狀況會如何;以及圖片大小還需針對各網站進行最適調教,如果有人有更適合方式歡迎互相交流。

參考連結