欢迎访问 生活随笔!

尊龙游戏旗舰厅官网

当前位置: 尊龙游戏旗舰厅官网 > 编程语言 > >内容正文

asp.net

基于 abp vnext 和 .net core 开发博客项目 -尊龙游戏旗舰厅官网

发布时间:2025/1/21 14 豆豆
尊龙游戏旗舰厅官网 收集整理的这篇文章主要介绍了 基于 abp vnext 和 .net core 开发博客项目 - 定时任务最佳实战(一) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

基于 abp vnext 和 .net core 开发博客项目 - 定时任务最佳实战(一)

转载于:https://github.com/meowv/blog

本篇主要围绕定时任务和数据抓取相关的知识点并结合实际应用,在定时任务中循环处理爬虫任务抓取数据。

开始之前可以删掉之前测试用的几个helloworld,没有什么实际意义,直接干掉吧。抓取数据我主要用到了,htmlagilitypack和puppeteersharp,一般情况下htmlagilitypack就可以完成大部分的数据抓取需求了,当在抓取动态网页的时候可以用到puppeteersharp,同时puppeteersharp还支持将图片保存为图片和pdf等牛逼的功能。

关于这两个库就不多介绍了,不了解的请自行去学习。

先在.backgroundjobs层安装两大神器:install-package htmlagilitypack、install-package puppeteersharp。我在使用package manager安装包的时候一般都不喜欢指定版本号,因为这样默认是给我安装最新的版本。

之前无意中发现爱思助手的网页版有很多手机壁纸(https://www.i4.cn/wper_4_0_1_1.html),于是我就动了小心思,把所有手机壁纸全部抓取过来自嗨,可以看看我个人博客中的成品吧:https://meowv.com/wallpaper 😝😝😝

图片

最开始我是用python实现的,现在我们在.net中抓它。

我数了一下,一共有20个分类,直接在.domain.shared层添加一个壁纸分类的枚举wallpaperenum.cs。

//wallpaperenum.cs
using system.componentmodel;

namespace meowv.blog.domain.shared.enum
{
public enum wallpaperenum
{
[description(“美女”)]
beauty = 1,

[description("型男")]sportsman = 2,[description("萌娃")]cutebaby = 3,[description("情感")]emotion = 4,[description("风景")]landscape = 5,[description("动物")]animal = 6,[description("植物")]plant = 7,[description("美食")]food = 8,[description("影视")]movie = 9,[description("动漫")]anime = 10,[description("手绘")]handpainted = 11,[description("文字")]text = 12,[description("创意")]creative = 13,[description("名车")]car = 14,[description("体育")]physicaleducation = 15,[description("军事")]military = 16,[description("节日")]festival = 17,[description("游戏")]game = 18,[description("苹果")]apple = 19,[description("其它")]other = 20, }

}
查看原网页可以很清晰的看到,每一个分类对应了一个不同的url,于是手动创建一个抓取的列表,列表内容包括url和分类,然后我又想用多线程来访问url,返回结果。新建一个通用的待抓项的类,起名为:wallpaperjobitem.cs,为了规范和后续的壁纸查询接口,我们放在.application.contracts层中。

//wallpaperjobitem.cs
using meowv.blog.domain.shared.enum;

namespace meowv.blog.application.contracts.wallpaper
{
public class wallpaperjobitem
{
///
///
///
public t result { get; set; }

/// /// 类型/// public wallpaperenum type { get; set; } }

}
wallpaperjobitem接受一个参数t,result的类型由t决定,在.backgroundjobs层jobs文件夹中新建一个任务,起名叫做:wallpaperjob.cs吧。老样子,继承ibackgroundjob。

//wallpaperjob.cs
using meowv.blog.application.contracts.wallpaper;
using meowv.blog.domain.shared.enum;
using system.collections.generic;
using system.threading.tasks;

namespace meowv.blog.backgroundjobs.jobs.wallpaper
{
public class wallpaperjob : ibackgroundjob
{
public async task executeasync()
{
var wallpaperurls = new list
{
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_1_1.html”, type = wallpaperenum.beauty },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_58_1.html”, type = wallpaperenum.sportsman },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_66_1.html”, type = wallpaperenum.cutebaby },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_4_1.html”, type = wallpaperenum.emotion },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_3_1.html”, type = wallpaperenum.landscape },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_9_1.html”, type = wallpaperenum.animal },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_13_1.html”, type = wallpaperenum.plant },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_64_1.html”, type = wallpaperenum.food },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_11_1.html”, type = wallpaperenum.movie },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_5_1.html”, type = wallpaperenum.anime },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_34_1.html”, type = wallpaperenum.handpainted },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_65_1.html”, type = wallpaperenum.text },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_2_1.html”, type = wallpaperenum.creative },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_10_1.html”, type = wallpaperenum.car },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_14_1.html”, type = wallpaperenum.physicaleducation },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_63_1.html”, type = wallpaperenum.military },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_17_1.html”, type = wallpaperenum.festival },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_15_1.html”, type = wallpaperenum.game },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_12_1.html”, type = wallpaperenum.apple },
new wallpaperjobitem { result = “https://www.i4.cn/wper_4_19_7_1.html”, type = wallpaperenum.other }
};
}
}
}
先构建一个要抓取的列表 wallpaperurls,这里准备用 htmlagilitypack,默认只抓取第一页最新的数据。

public async task runasync()
{

var web = new htmlweb(); var list_task = new list>>();wallpaperurls.foreach(item => {var task = task.run(async () =>{var htmldocument = await web.loadfromwebasync(item.result);return new wallpaperjobitem{result = htmldocument,type = item.type};});list_task.add(task); }); task.waitall(list_task.toarray());

}
上面这段代码,先new了一个htmlweb对象,我们主要用这个对象去加载我们的url。

web.loadfromwebasync(…),它会返回一个htmldocument对象,这样就和上面的list_task对应起来,从而也应证了前面添加的wallpaperjobitem是通用的一个待抓项的类。

循环处理 wallpaperurls,等待所有请求完成。这样就拿到了20个htmldocument,和它的分类,接下来就可以去处理list_task就行了。

在开始处理之前,要想好抓到的图片数据存放在哪里?我这里还是选择存在数据库中,因为有了之前的自定义仓储之增删改查的经验,可以很快的处理这件事情。

添加实体类、自定义仓储、dbset、code-first等一些列操作,就不一一介绍了,我相信看过之前文章的人都能完成这一步。

wallpaper实体类包含主键guid,标题title,图片地址url,类型type,和一个创建时间createtime。

自定义仓储包含一个批量插入的方法:bulkinsertasync(…)。

贴一下完成后的图片,就不上代码了,如果需要可以去github获取。

图片

回到wallpaperjob,因为我们要抓取的是图片,所以获取到html中的img标签就可以了。

图片

查看源代码发现图片是一个列表呈现的,并且被包裹在//article[@id=‘wper’]/div[@class=‘jbox’]/div[@class=‘kbox’]下面,学过xpath语法的就很容易了,关于xpath语法这里也不做介绍了,对于不会的这里有一篇快速入门的文章:xpath语法 。

利用xpath helper工具我们在浏览器上模拟一下选择的节点是否正确。

图片

使用//article[@id=‘wper’]/div[@class=‘jbox’]/div[@class=‘kbox’]/div/a/img可以成功将图片高亮,说明我们的语法是正确的。

public async task runasync()
{

var wallpapers = new list();foreach (var list in list_task) {var item = await list;var imgs = item.result.documentnode.selectnodes("//article[@id='wper']/div[@class='jbox']/div[@class='kbox']/div/a/img[1]").tolist();imgs.foreach(x =>{wallpapers.add(new wallpaper{url = x.getattributevalue("data-big", ""),title = x.getattributevalue("title", ""),type = (int)item.type,createtime = x.attributes["data-big"].value.split("/").last().split("_").first().trytodatetime()});}); } ...

}
在 foreach 循环中先拿到当前循环的item对象,即wallpaperjobitem。

通过.documentnode.selectnodes()语法获取到图片列表,因为在a标签下面有两个img标签,取第一个即可。

getattributevalue()是htmlagilitypack的扩展方法,用于直接获取属性值。

在看图片的时候,发现图片地址的规则是根据时间戳生成的,于是用trytodatetime()扩展方法将其处理转换成时间格式。

这样我们就将所有图片按分类存进了列表当中,接下来调用批量插入方法。

在构造函数中注入自定义仓储iwallpaperrepository。


private readonly iwallpaperrepository _wallpaperrepository;

public wallpaperjob(iwallpaperrepository wallpaperrepository){_wallpaperrepository = wallpaperrepository;}


var urls = (await _wallpaperrepository.getlistasync()).select(x => x.url);
wallpapers = wallpapers.where(x => !urls.contains(x.url)).tolist();
if (wallpapers.any())
{
await _wallpaperrepository.bulkinsertasync(wallpapers);
}
因为抓取的图片可能存在重复的情况,我们需要做一个去重处理,先查询到数据库中的所有的url列表,然后在判断抓取到的url是否存在,最后调用bulkinsertasync(…)批量插入方法。

这样就完成了数据抓取的全部逻辑,在保存数据到数据库之后我们可以进一步操作,比如:写日志、发送邮件通知等等,这里大家自由发挥吧。

写一个扩展方法每隔3小时执行一次。


public static void usewallpaperjob(this iserviceprovider service)
{
var job = service.getservice();
recurringjob.addorupdate(“壁纸数据抓取”, () => job.executeasync(), crontype.hour(1, 3));
}

最后在模块内中调用。


public override void onapplicationinitialization(applicationinitializationcontext context)
{

service.usewallpaperjob();
}
编译运行,打开hangfire界面手动执行看看效果。

图片

完美,数据库已经存入了不少数据了,还是要提醒一下:爬虫有风险,抓数需谨慎。

hangfire定时处理爬虫任务,用htmlagilitypack抓取数据后存入数据库,你学会了吗?😁😁😁

开源地址:https://github.com/meowv/blog/tree/blog_tutorial

总结

以上是尊龙游戏旗舰厅官网为你收集整理的基于 abp vnext 和 .net core 开发博客项目 - 定时任务最佳实战(一)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得尊龙游戏旗舰厅官网网站内容还不错,欢迎将尊龙游戏旗舰厅官网推荐给好友。

网站地图