上一篇(http://www.javashuo.com/article/p-vpwbauee-en.html)完成了全網各大平臺的熱點新聞數據的抓取,本篇繼續圍繞抓取完成後的操做作一個提醒。當每次抓取完數據後,自動發送郵件進行提醒。html
在開始正題以前仍是先玩一玩以前的說到卻沒有用到的一個庫PuppeteerSharp
。linux
PuppeteerSharp
:Headless Chrome .NET API ,它運用最多的應該是自動化測試和抓取異步加載的網頁數據,更多介紹能夠看GitHub:https://github.com/hardkoded/puppeteer-sharp 。git
我這裏主要來試試它的異步抓取功能,同時它還能幫咱們生成網頁截圖或者PDF。github
若是沒有安裝能夠先安裝一下,在.BackgroundJobs
層安裝PuppeteerSharp
:Install-Package PuppeteerSharp
chrome
在Jobs文件夾下新建一個PuppeteerTestJob.cs
,繼承IBackgroundJob
,一樣是在ExecuteAsync()
方法中執行操做。npm
//PuppeteerTestJob.cs using System; using System.Threading.Tasks; namespace Meowv.Blog.BackgroundJobs.Jobs.PuppeteerTest { public class PuppeteerTestJob : IBackgroundJob { public async Task ExecuteAsync() { throw new NotImplementedException(); } } }
使用 await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
第一次檢測到沒有瀏覽器文件會默認幫咱們下載 chromium 瀏覽器。json
DownloadAsync(...)
能夠指定 Chromium 版本,BrowserFetcher.DefaultRevision
下載當前默認最穩定的版本。瀏覽器
而後配置瀏覽器啓動的方式。服務器
using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true, Args = new string[] { "--no-sandbox" } });
感興趣的能夠本身看看LaunchOptions
有哪些參數,我這裏指定了Headless = true
以無頭模式運行瀏覽器,而後加了一個啓動參數 "--no-sandbox"。針對Linux環境下,若是是運行在 root 權限下,在啓動 Puppeteer 時要添加 "--no-sandbox" 參數,不然 Chromium 會啓動失敗。網絡
咱們打開一個異步加載的網頁,而後獲取到頁面加載完後的HTML,以我我的博客中的某個單頁爲例:https://meowv.com/wallpaper 。
//PuppeteerTestJob.cs using PuppeteerSharp; using System.Threading.Tasks; namespace Meowv.Blog.BackgroundJobs.Jobs.PuppeteerTest { public class PuppeteerTestJob : IBackgroundJob { public async Task ExecuteAsync() { await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision); using var browser = await Puppeteer.LaunchAsync(new LaunchOptions { Headless = true, Args = new string[] { "--no-sandbox" } }); using var page = await browser.NewPageAsync(); await page.SetViewportAsync(new ViewPortOptions { Width = 1920, Height = 1080 }); var url = "https://meowv.com/wallpaper"; await page.GoToAsync(url, WaitUntilNavigation.Networkidle0); var content = await page.GetContentAsync(); } } }
page.SetViewportAsync()
設置網頁預覽大小,page.GoToAsync()
語法打開網頁,WaitUntilNavigation.Networkidle0
等待網頁加載完畢,使用page.GetContentAsync()
獲取到HTML。
新建擴展方法,調用這個PuppeteerTestJob
的ExecuteAsync()
方法,調試看看效果。
HTML已經出來了,此時該幹嗎就幹嗎就能夠了。
第一次運行可能會很慢,由於若是你本地不存在 Chromium 是會去幫咱們下載的,由於網絡緣由可能會下載的很慢,因此推薦你們手動下載。
可使用淘寶的源:https://npm.taobao.org/mirrors/chromium-browser-snapshots/ 。
要注意的是,下載完成後的解壓的路徑不能出錯,默認下載地址是在啓動目錄下面。
Windows:..\.local-chromium\Win64-706915\chrome-win
、 Linux:../.local-chromium/Linux-706915/chrome-linux
接下來試試生成PDF和保存圖片功能,使用方式也很簡單。
await page.PdfAsync("meowv.pdf",new PdfOptions { }); await page.ScreenshotAsync("meowv.png", new ScreenshotOptions { FullPage = true, Type = ScreenshotType.Png });
這裏只作簡單的展現,page.PdfAsync()
直接生成PDF文件,同時還有不少方法能夠本身調用page.
試試,PdfOptions
選項中能夠設置各類參數。
page.ScreenshotAsync()
保存圖片,ScreenshotOptions
中FullPage能夠設置保存圖片爲全屏模式,圖片格式爲Png類型。
能夠看到項目根目錄已經生成了圖片和PDF,感受去試試吧。
接下里來實現發送郵件的功能。
我這裏發郵件的帳號是用的騰訊企業郵箱,也能夠用普通郵箱開通SMTP服務便可。
在appsettings.json
配置收發郵件的帳號等信息。
//appsettings.json "Email": { "Host": "smtp.exmail.qq.com", "Port": 465, "UseSsl": true, "From": { "Username": "123@meowv.com", "Password": "[Password]", "Name": "MEOWV.COM", "Address": "123@meowv.com" }, "To": [ { "Name": "test1", "Address": "test1@meowv.com" }, { "Name": "test2", "Address": "test2@meowv.com" } ] }
而後再AppSettings
中讀取配置的項。
//AppSettings.cs public static class Email { /// <summary> /// Host /// </summary> public static string Host => _config["Email:Host"]; /// <summary> /// Port /// </summary> public static int Port => Convert.ToInt32(_config["Email:Port"]); /// <summary> /// UseSsl /// </summary> public static bool UseSsl => Convert.ToBoolean(_config["Email:UseSsl"]); /// <summary> /// From /// </summary> public static class From { /// <summary> /// Username /// </summary> public static string Username => _config["Email:From:Username"]; /// <summary> /// Password /// </summary> public static string Password => _config["Email:From:Password"]; /// <summary> /// Name /// </summary> public static string Name => _config["Email:From:Name"]; /// <summary> /// Address /// </summary> public static string Address => _config["Email:From:Address"]; } /// <summary> /// To /// </summary> public static IDictionary<string, string> To { get { var dic = new Dictionary<string, string>(); var emails = _config.GetSection("Email:To"); foreach (IConfigurationSection section in emails.GetChildren()) { var name = section["Name"]; var address = section["Address"]; dic.Add(name, address); } return dic; } } }
分別介紹下每項的含義:
Host
:發送郵件服務器地址。Port
:服務器地址端口號。UseSsl
:是否使用SSL方式。From
:發件人的帳號密碼,名稱及郵箱地址,通常郵箱地址和帳號是相同的。To
:收件人郵箱列表,也包含名稱和郵箱地址。收件人郵箱列表我將其讀取爲IDictionary<string, string>
了,key是名稱,value是郵箱地址。
接着在.ToolKits
層添加一個EmailHelper.cs
,收發郵件我選擇了MailKit
和MailKit
兩個庫,沒有安裝的先安裝一下,Install-Package MailKit
、Install-Package MimeKit
。
直接新建一個發送郵件的方法SendAsync()
,按照要求將基本的配置信息填進去,而後直接調用便可。
//EmailHelper.cs using MailKit.Net.Smtp; using Meowv.Blog.Domain.Configurations; using MimeKit; using System.Linq; using System.Threading.Tasks; namespace Meowv.Blog.ToolKits.Helper { public static class EmailHelper { /// <summary> /// 發送Email /// </summary> /// <param name="message"></param> /// <returns></returns> public static async Task SendAsync(MimeMessage message) { if (!message.From.Any()) { message.From.Add(new MailboxAddress(AppSettings.Email.From.Name, AppSettings.Email.From.Address)); } if (!message.To.Any()) { var address = AppSettings.Email.To.Select(x => new MailboxAddress(x.Key, x.Value)); message.To.AddRange(address); } using var client = new SmtpClient { ServerCertificateValidationCallback = (s, c, h, e) => true }; client.AuthenticationMechanisms.Remove("XOAUTH2"); await client.ConnectAsync(AppSettings.Email.Host, AppSettings.Email.Port, AppSettings.Email.UseSsl); await client.AuthenticateAsync(AppSettings.Email.From.Username, AppSettings.Email.From.Password); await client.SendAsync(message); await client.DisconnectAsync(true); } } }
SendAsync(...)
接收一個參數MimeMessage
對象,這樣就完成了一個通用的發郵件方法,接着咱們去須要發郵件的地方構造MimeMessage
,調用SendAsync()
。
//WallpaperJob.cs ... // 發送Email var message = new MimeMessage { Subject = "【定時任務】壁紙數據抓取任務推送", Body = new BodyBuilder { HtmlBody = $"本次抓取到{wallpapers.Count()}條數據,時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}" }.ToMessageBody() }; await EmailHelper.SendAsync(message); ...
//HotNewsJob.cs ... // 發送Email var message = new MimeMessage { Subject = "【定時任務】每日熱點數據抓取任務推送", Body = new BodyBuilder { HtmlBody = $"本次抓取到{hotNews.Count()}條數據,時間:{DateTime.Now:yyyy-MM-dd HH:mm:ss}" }.ToMessageBody() }; await EmailHelper.SendAsync(message); ...
分別在兩個爬蟲腳本中添加發送Email,MimeMessage
中設置了郵件主題Subject
,正文Body
,最後調用await EmailHelper.SendAsync(message)
執行發送郵件操做。
編譯運行執行兩個定時任務,看看可否收到郵件提醒。
成功了,郵箱收到了兩條提醒。
還有一種比較特殊的用法,也介紹一下,若是想要發送帶圖片的郵件怎麼操做呢?注意不是附件,是將圖片內嵌在郵箱中。
通常常規都是有郵件模板的,將圖片的具體地址插入到img標籤中,這就不說了,這裏選擇另一種方式。之前面添加的PuppeteerTestJob
爲例,正好咱們生成了一張圖片的。將這種圖片以郵件的形式發出去。
public class PuppeteerTestJob : IBackgroundJob { public async Task ExecuteAsync() { var path = Path.Combine(Path.GetTempPath(), "meowv.png"); ... await page.ScreenshotAsync(path, new ScreenshotOptions { FullPage = true, Type = ScreenshotType.Png }); // 發送帶圖片的Email var builder = new BodyBuilder(); var image = builder.LinkedResources.Add(path); image.ContentId = MimeUtils.GenerateMessageId(); builder.HtmlBody = "當前時間:{0}.<img src=\"cid:{1}\"/>".FormatWith(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), image.ContentId); var message = new MimeMessage { Subject = "【定時任務】每日熱點數據抓取任務推送", Body = builder.ToMessageBody() }; await EmailHelper.SendAsync(message); } }
先肯定咱們生成圖片的路徑 path ,將圖片生成Message-Id,而後賦值給ContentId,給模板中<img src=\"cid:{1}\"/>
圖片標籤cid
賦上值在調用發送郵件方法便可。
成功收到郵件,搞定了,你學會了嗎?😁😁😁
開源地址:https://github.com/Meowv/Blog/tree/blog_tutorial
基於 abp vNext 和 .NET Core 開發博客項目,截止到本篇所用到的基礎模塊算是寫完了,若是對您有些許幫助請多多分享,個人全部原創文章都首發於我發我的公衆號:阿星Plus 。
下面有二維碼能夠直接掃一掃,若是你不想關注也沒有關係,博客園我也會同步過來的。
無論由於什麼,若是你在學習這個項目或者跟着我一塊兒作這個項目,裏面確定仍是有瑕疵的,你們能夠根據本身的需求自行修改。
接下來應該還會更新博客所用到的接口,這個純屬於CRUD,能夠本身先行開發,我這邊目前也不知道以什麼樣的方式展示給你們是最好的選擇。