.NetCore承载系统

.NetCore的承载系统, 可以将长时间运行的服务承载于托管进程中, AspNetCore应用其实就是一个长时间运行的服务, 启动AspNetCore应用后, 它就会监听网络请求, 也就是开启了一个监听器, 监听器会将网络请求传递给管道进行处理, 处理后得到Http响应返回

有很多场景都会有服务承载的需求, 比如这篇博文要做的, 定时抓取华为论坛的文章点赞数

爬取文章点赞数

分析

比如这个链接 https://developer.huawei.com/consumer/cn/forum/topicview?tid=0201308791792470245&fid=23 , 点进去不难发现这是用angular做的一个页面, 既然是Angular, 那说明前后端分离了, 浏览器F12查看网络请求



找到对应api请求方法:

POST https://developer.huawei.com/consumer/cn/forum/mid/partnerforumservice/v1/open/getTopicDetail? HTTP/1.1
Host: developer.huawei.com
Content-Type: application/json
Content-Length: 33 {"topicId":"0201302923811480141"}

这里经过我的测试, Content-TypeContent-Length必须上面那样的值, 还有body, 你多一个空格请求都会失败

使用HttpClient请求数据

直接看代码吧, 这里使用了依赖注入来注入HttpClientFactory, 还可以使用强类型的HttpClient, 具体可以看文档和dudu博客的这篇博文

工厂参观记:.NET Core 中 HttpClientFactory 如何解决 HttpClient 臭名昭著的问题

private readonly IHttpClientFactory _httpClientFactory;

public async Task<int> Crawl(string link)
{
using (var httpClient = _httpClientFactory.CreateClient())
{
var uri = new Uri(link);
uri.TryReadQueryAsJson(out var queryParams);
var topicId = queryParams["tid"].ToString();
int likeCount = -1;
if (!string.IsNullOrEmpty(topicId))
{
var body = JsonConvert.SerializeObject(
new { topicId },
Formatting.None);
uri = new Uri(_baseUrl);
var jsonContentType = "application/json"; var requestMessage = new HttpRequestMessage
{
RequestUri = uri,
Headers =
{
{ "Host", uri.Host }
},
Method = HttpMethod.Post,
Content = new StringContent(body)
};
requestMessage.Content.Headers.ContentType = new MediaTypeWithQualityHeaderValue(jsonContentType);
requestMessage.Content.Headers.ContentLength = body.Length;
var response = await httpClient.SendAsync(requestMessage);
if (response.StatusCode == HttpStatusCode.OK)
{
dynamic data = await response.Content.ReadAsAsync<dynamic>();
likeCount = data.result.likes;
}
} return likeCount;
}
}

这里有更简洁的的写法, 使用_httpClient.PostAsJsonAsync(), 但是考虑到可能需要自定义Content-Type这些请求头, 所以先这样写;

配置承载系统

class Program
{
static void Main()
{
new HostBuilder()
.ConfigureServices(services =>
{
services.AddHttpClient();
services.AddHostedService<LikeCountCrawler>();
})
.Build()
.Run();
}
}

LikeCountCrawler实现了IHostedService接口

IHostedService接口

public interface IHostedService
{
/// <summary>
/// Triggered when the application host is ready to start the service.
/// </summary>
/// <param name="cancellationToken">Indicates that the start process has been aborted.</param>
Task StartAsync(CancellationToken cancellationToken); /// <summary>
/// Triggered when the application host is performing a graceful shutdown.
/// </summary>
/// <param name="cancellationToken">Indicates that the shutdown process should no longer be graceful.</param>
Task StopAsync(CancellationToken cancellationToken);
}

LikeCountCrawlerStartAsync方法中, 设置开启了一个定时器, 定时器每次溢出, 都执行一次爬虫逻辑

private readonly Timer _timer = new Timer();
private readonly IEnumerable<string> _links = new string[]
{
"https://developer.huawei.com/consumer/cn/forum/topicview?tid=0201308791792470245&fid=23",
"https://developer.huawei.com/consumer/cn/forum/topicview?tid=0201303654965850166&fid=18",
"https://developer.huawei.com/consumer/cn/forum/topicview?tid=0201294272503450453&fid=24",
"https://developer.huawei.com/consumer/cn/forum/topicview?tid=0201294189025490019&fid=17"
};
private readonly string _baseUrl = "https://developer.huawei.com/consumer/cn/forum/mid/partnerforumservice/v1/open/getTopicDetail";
... public Task StartAsync(CancellationToken cancellationToken)
{
_timer.Interval = 5 * 60 * 1000;
_timer.Elapsed += OnTimer;
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Start();
OnTimer(null, null);
return Task.CompletedTask;
} public async Task Crawl(IEnumerable<string> links)
{
await Task.Run(() =>
{
Parallel.ForEach(links, async link =>
{
Console.WriteLine($"Crawling link:{link}, ThreadId:{Thread.CurrentThread.ManagedThreadId}");
var likeCount = await Crawl(link);
Console.WriteLine($"Succeed crawling likecount - {likeCount}, ThreadId:{Thread.CurrentThread.ManagedThreadId}");
});
});
} private void OnTimer(object sender, ElapsedEventArgs args)
{
_ = Crawl(_links);
} ...

运行效果:

NetCore控制台程序-使用HostService和HttpClient实现简单的定时爬虫的更多相关文章

  1. windows下建立netcore控制台程序,然后传送到centos7下的docker容器里运行

    1.首先,在window下用vs2017开发netcore控制台项目. 2.把建立好的项目传送到centos7下面的容器里. docker cp sharefoldersforwindows/ 359 ...

  2. C#控制台程序的参数解析类库 CommandLine简单使用说明

    前言 C#开发的控制台程序,默认接收string[] args参数.如果有多个参数需要输入时,可以按照顺序依次输入:但如果有些参数不是必选的,或者有些参数中间需要有空格比如时间“2016-05-18 ...

  3. 控制台程序的参数解析类库 CommandLine

    C#控制台程序的参数解析类库 CommandLine简单使用说明 前言 C#开发的控制台程序,默认接收string[] args参数.如果有多个参数需要输入时,可以按照顺序依次输入:但如果有些参数不是 ...

  4. .NET CORE与Spring Boot编写控制台程序应有的优雅姿势

    本文分别说明.NET CORE与Spring Boot 编写控制台程序应有的“正确”方法,以便.NET程序员.JAVA程序员可以相互学习与加深了解,注意本文只介绍用法,不会刻意强调哪种语言或哪种框架写 ...

  5. .NET CORE编写控制台程序应有的优雅姿势(转载)

    原文地址:https://www.cnblogs.com/zuowj/p/11107243.html 本文所说的编写控制台程序应有的“正确”方法,我把正确二字加上引号,因为没有绝对的正确,因人而异,因 ...

  6. Mac/Windows开发跨平台.NET Core 控制台程序

    自从微软开始在Github上开源搞.NET Core后,.NET的跨平台逐渐就成真了.多年使用各种语言,说实话还是csharp用起来最舒服.不过现在的工作环境里使用它的机会比较少,大部分时候只是用来写 ...

  7. 使用.NetCore 控制台演示 熔断 降级(polly)

    1.熔断降级的概念: 熔断:我这里有一根长度一米的钢铁,钢铁的熔点1000度(假设),现在我想用力把这根钢铁折弯,但是人的力有限达不到折弯的点,然后我使用火给钢铁加热,每隔一段时间我就会尝试一下是否能 ...

  8. mac 发布.net Core2.0 控制台程序

    安装.net core2.0 环境,略 新建文件夹 TestA, 存放项目 TestA 在 TestA 文件夹下,创建控制台程序: dotnet new console(会自动生成 TestA.csp ...

  9. Net Core 控制台程序使用Nlog 输出到log文件

    using CoreImportDataApp.Common; using Microsoft.Extensions.Configuration; using Microsoft.Extensions ...

随机推荐

  1. WDCP v3 安装

    ---已更新至3.0.3---经过近期的努力,wdCP_v3正式版终于可以和大家见面了v3功能预览1 底层完全重新架构,更安全稳定,省资源更高效2 安装更简单,快速与方便3 功能更强大和易扩展,且完美 ...

  2. Asp.Net Core 应用配置

    五种读取方式 五种读取方式依赖于 IConfiguration 和 IConfigurationRoot 对象 一.初级写法 //不区分大小写 string connectionString = _c ...

  3. Laya 踩坑日记-人物模型穿模,模型显示不正常

    最近做游戏,人物要跑到很远的位置,z轴距离大概有20000个单位,然后就发现一个bug,到远处人物模型穿了,而且没办法改,这就尴尬了 Z轴对应值    0    100000 100000 当距离零点 ...

  4. ThinkPHP5表单令牌刷新

    制作登录页面的时候,加入了表单令牌,账号和密码输入错误后,再登录的话,会提示表单令牌错误, 这是因为旧的令牌已经过期了,我们要处理下前端的token,修复的办法,在路由文件下加入 //刷新表单令牌,然 ...

  5. 【Python】在CentOS6.8中安装pip9.0.1和setuptools33.1

    wget https://bootstrap.pypa.io/ez_setup.py python ez_setup.py install --如果这个文件安装需要下载的文件无法下载的话,手动下载,放 ...

  6. 【RAC】11gRAC 搭建(VMware+裸设备)

    安装环境与网络规划 安装环境 主机操作系统:windows 7虚拟机VMware12:两台Oracle Linux R6 U5 x86_64 Oracle Database software: Ora ...

  7. CSRF - Pikachu

    概述: Cross-site request forgery 简称为"CSRF"(跨站请求伪造),在CSRF的攻击场景中攻击者会伪造一个请求(这个请求一般是一个链接),然后欺骗目标 ...

  8. 2021年【线上】lammps分子动力学技术实战培训班

    材料模拟分子动力学课程 3月19号--22号 远程在线课 lammps分子动力学课程 3月12号--15号 远程在线课 第一性原理VASP实战课 3月25号-28号 远程在线课 量子化学Gaussia ...

  9. linux设备注册

    一.分配cdev cdev表示字符设备,使用cdev_alloc函数,cdev_alloc函数原型如下: /** * cdev_alloc() - allocate a cdev structure ...

  10. 对象存储 COS 帮您轻松搞定跨域访问需求

    背景 早期为了避免 CSRF(跨站请求伪造) 攻击,浏览器引入了 "同源策略" 机制.如果两个 URL 的协议,主机名(域名/IP),端口号一致,则视为这两个 URL " ...