NetCore控制台程序-使用HostService和HttpClient实现简单的定时爬虫
.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-Type和Content-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);
}
LikeCountCrawler在StartAsync方法中, 设置开启了一个定时器, 定时器每次溢出, 都执行一次爬虫逻辑
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实现简单的定时爬虫的更多相关文章
- windows下建立netcore控制台程序,然后传送到centos7下的docker容器里运行
1.首先,在window下用vs2017开发netcore控制台项目. 2.把建立好的项目传送到centos7下面的容器里. docker cp sharefoldersforwindows/ 359 ...
- C#控制台程序的参数解析类库 CommandLine简单使用说明
前言 C#开发的控制台程序,默认接收string[] args参数.如果有多个参数需要输入时,可以按照顺序依次输入:但如果有些参数不是必选的,或者有些参数中间需要有空格比如时间“2016-05-18 ...
- 控制台程序的参数解析类库 CommandLine
C#控制台程序的参数解析类库 CommandLine简单使用说明 前言 C#开发的控制台程序,默认接收string[] args参数.如果有多个参数需要输入时,可以按照顺序依次输入:但如果有些参数不是 ...
- .NET CORE与Spring Boot编写控制台程序应有的优雅姿势
本文分别说明.NET CORE与Spring Boot 编写控制台程序应有的“正确”方法,以便.NET程序员.JAVA程序员可以相互学习与加深了解,注意本文只介绍用法,不会刻意强调哪种语言或哪种框架写 ...
- .NET CORE编写控制台程序应有的优雅姿势(转载)
原文地址:https://www.cnblogs.com/zuowj/p/11107243.html 本文所说的编写控制台程序应有的“正确”方法,我把正确二字加上引号,因为没有绝对的正确,因人而异,因 ...
- Mac/Windows开发跨平台.NET Core 控制台程序
自从微软开始在Github上开源搞.NET Core后,.NET的跨平台逐渐就成真了.多年使用各种语言,说实话还是csharp用起来最舒服.不过现在的工作环境里使用它的机会比较少,大部分时候只是用来写 ...
- 使用.NetCore 控制台演示 熔断 降级(polly)
1.熔断降级的概念: 熔断:我这里有一根长度一米的钢铁,钢铁的熔点1000度(假设),现在我想用力把这根钢铁折弯,但是人的力有限达不到折弯的点,然后我使用火给钢铁加热,每隔一段时间我就会尝试一下是否能 ...
- mac 发布.net Core2.0 控制台程序
安装.net core2.0 环境,略 新建文件夹 TestA, 存放项目 TestA 在 TestA 文件夹下,创建控制台程序: dotnet new console(会自动生成 TestA.csp ...
- Net Core 控制台程序使用Nlog 输出到log文件
using CoreImportDataApp.Common; using Microsoft.Extensions.Configuration; using Microsoft.Extensions ...
随机推荐
- kafka-spark偏移量提交至redis kafka1.0版本
kafka版本 1.0.0 spark版本 spark-streaming-kafka-0-10_2.11/** * @created by imp ON 2019/12/21 */class Kaf ...
- 我与CSDN的第一百天
- Docker-ce Centos8 笔记二:常见问题
- Eclipse-Che 安装(Centos)
安装docker,然后执行:docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock -v /home/cheData:/dat ...
- 【MyBatis】MyBatis 注解开发
MyBatis 注解开发 文章源码 环境搭建 Mybatis 也可以使用注解开发方式,这样就可以减少编写 Mapper 映射文件. 常用注解说明: @Insert 实现新增 @Update 实现更新 ...
- Python——绘制埃菲尔铁塔
from turtle import * import turtle colormode(255) #设置turtle颜色模式 speed(0) #速度 setup(800,800,720,0) #画 ...
- Docker学习笔记之进入容器Bash
我们在创建容器的时候,如果容器的命令(command)不是/bin/bash的时候,使用docker attach命令是会卡住进不去容器的bash shell的.如下图所示: 所以,这里记录一个可以进 ...
- H5手机网页元素识别
- 【ORA】ORA-32004: 问题分析和解决
今天做一个特殊的实验,需要重启数据库 数据库关闭没有问题 SQL> shutdown immediate; Database closed. Database dismounted. ORACL ...
- ctfhub技能树—RCE—过滤空格
打开靶机 查看页面信息 开始尝试注入 127.0.0.1 || ls 尝试绕过 127.0.0.1||ls 使用cat命令查看flag 127.0.0.11||cat<flag_10872536 ...