前言
你聽過隕石開發法嗎?
沒聽過?那你可以看看轉載好文:隕石開發法
甚麼?你問隕石開發法跟這篇文有甚麼關係?
因為神有了需求
本文
上次有提到 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;
}
}
實際結果
- 第一頁
- 第二頁
後記
原本以為只是說著玩的,突然就…
網頁截圖還有許多奧妙啊…譬如實際抓取網路渲染時間其實也是會有誤差,所以此方法目前是研究出來可行性最高的方式了,但一次運行還是要跑個十秒,所以不知道實際上線功能狀況會如何;以及圖片大小還需針對各網站進行最適調教,如果有人有更適合方式歡迎互相交流。