基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)
转载于:https://github.com/Meowv/Blog

本篇继续围绕抓取完成后的操作做一个提醒。当每次抓取完数据后,自动发送邮件进行提醒。

在开始正题之前还是先玩一玩之前的说到却没有用到的一个库PuppeteerSharp。

PuppeteerSharp:Headless Chrome .NET API ,它运用最多的应该是自动化测试和抓取异步加载的网页数据,更多介绍可以看GitHub:https://github.com/hardkoded/puppeteer-sharp 。

我这里主要来试试它的异步抓取功能,同时它还能帮我们生成网页截图或者PDF。

如果没有安装可以先安装一下,在.BackgroundJobs层安装PuppeteerSharp:Install-Package PuppeteerSharp

在Jobs文件夹下新建一个PuppeteerTestJob.cs,继承IBackgroundJob,同样是在ExecuteAsync()方法中执行操作。

//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 浏览器。

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
{
///
/// Host
///
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
{
///
/// 发送Email
///
///
///
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});// 发送带图片的Emailvar 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赋上值在调用发送邮件方法即可。

图片

成功收到邮件,搞定了,你学会了吗?

基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(三)相关推荐

  1. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二)

    基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(二) 转载于:https://github.com/Meowv/Blog 本篇继续来完成一个全网各大平台的热点新闻 ...

  2. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)

    基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一) 转载于:https://github.com/Meowv/Blog 本篇主要围绕定时任务和数据抓取相关的知识 ...

  3. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(一)

    系列文章 基于 abp vNext 和 .NET Core 开发博客项目 - 使用 abp cli 搭建项目 基于 abp vNext 和 .NET Core 开发博客项目 - 给项目瘦身,让它跑起来 ...

  4. 基于 abp vNext 和 .NET Core 开发博客项目 - 终结篇之发布项目

    基于 abp vNext 和 .NET Core 开发博客项目 - 终结篇之发布项目 转载于:https://github.com/Meowv/Blog 既然开发完成了,还是拿出来溜溜比较好,本篇是本 ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九)

    基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(九) 转载于:https://github.com/Meowv/Blog 终于要接近尾声了,上一篇基本上将文 ...

  6. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(八)

    基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(八) 转载于:https://github.com/Meowv/Blog 上一篇完成了标签模块和友情链接模块 ...

  7. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(七)

    基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(七) 转载于:https://github.com/Meowv/Blog 上一篇完成了后台分类模块的所有功能 ...

  8. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(六)

    基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(六) 转载于:https://github.com/Meowv/Blog 上一篇完成了博客文章详情页面的数据 ...

  9. 基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(五)

    基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(五) 转载于:https://github.com/Meowv/Blog 上一篇完成了分类标签友链的列表查询 ...

最新文章

  1. rsync+inotify实现数据的实时备份
  2. [转]Android fragment 重叠问题——通过hide,show方式导致的解决方法
  3. RabbitMQ调试与测试工具-v1.0.1 -提供下载测试与使用
  4. WebSSH2安装过程可实现WEB可视化管理SSH工具
  5. WordPress Citizen Space插件跨站请求伪造漏洞
  6. android4.2 音频模块启动分析,Android 音频模块学习小结
  7. python函数式编程 pdf-Python函数式编程指南(二):从函数开始
  8. [Usaco2011][bzoj2442][洛谷2527]修剪草坪解题报告(dp,贪心,单调队列)
  9. 一次搞定this和闭包
  10. Spring注解原理的详细剖析与实现
  11. 【测试理论】如何做好探索性测试(二)—增加维度
  12. 苹果电脑系统如何读取移动硬盘数据?
  13. 使用.NET技术制作KTV点歌项目,新手篇
  14. 自动关闭当前的Fragment返回上一个Fragment该如何实现
  15. Mac Xcode 各种缓存清理
  16. 【解决】更新微信后为何还是没有修改微信号的功能
  17. 算法思想(持续更新...)
  18. 泛微OA-ecology8数据字典大全
  19. 【UE5 C++基础 05】UBT基础
  20. 机器学习实战教程(2):K-近邻算法(史诗级干货长文)

热门文章

  1. 一文读懂残差网络ResNet
  2. 简历中的项目如何体现实战能力? 如何有技巧地描述你做过的 project?
  3. Cocos Creator中的动画支持技术
  4. ceil与intval区别
  5. 戏说春秋 第三关 窃符救赵 图片隐写
  6. C#使用ICSharpCode.SharpZipLib压缩后进行web批量下载文件
  7. Queue 队列的用法
  8. javascript计时原理
  9. jdbc查看网络状态
  10. 【Spring reference】@ResponseBody注解