定时从列表中爬今日通知信息,打包成windows服务

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 场景模拟每天8点爬取今日发布的新闻和通知公告,将爬取后的信息保存到Excel文件中,将程序发布成windows服务,开机即可自动启动。技术使用1.每天8点定时执行任务,使用Quartz.

场景模拟

每天8点爬取今日发布的新闻通知公告,将爬取后的信息保存到Excel文件中,将程序发布成windows服务,开机即可自动启动。

技术使用

1.每天8点定时执行任务,使用Quartz.Net
2.爬取数据采用HtmlAgility
3.Excel操作采用NPOI
4.将应用程序发布为Windows服务,使用Topshelf
5.日志记录Log4Net

思路

因为最后的输出形式为Windows服务,所以使用Topshelf进行打包

TopShelf使用链接

http://www.cnblogs.com/jys509/p/4614975.html

TopShelf概述

Topshelf是创建Windows服务的另一种方法,老外的一篇文章Create a .NET Windows Service in 5 steps with Topshelf通过5个步骤详细的介绍使用使用Topshelf创建Windows 服务。Topshelf是一个开源的跨平台的宿主服务框架,支持Windows和Mono,只需要几行代码就可以构建一个很方便使用的服务宿主。

不了解TopShelf的童鞋可以先百度或者根据LZ提供的链接看看TopShelf是什么以及如何使用。
在了解TopShelf为何物后,我们首先建立一个控制台项目,将我们所需要的组件一一安装。

Install-package Quartz.Net
Install-package Log4Net
Install-package HtmlAgility
Install-package TopShelf

第一步:配置Log4Net日志

新建Log4net.config配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/>
  </configSections>

  <log4net>
    <appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
      <!--日志路径-->
      <param name= "File" value= "D:\App_Log\servicelog\"/>
      <!--是否是向文件中追加日志-->
      <param name= "AppendToFile" value= "true"/>
      <!--log保留天数-->
      <param name= "MaxSizeRollBackups" value= "10"/>
      <!--日志文件名是否是固定不变的-->
      <param name= "StaticLogFileName" value= "false"/>
      <!--日志文件名格式为:2008-08-31.log-->
      <param name= "DatePattern" value= "yyyy-MM-dd&quot;.read.log&quot;"/>
      <!--日志根据日期滚动-->
      <param name= "RollingStyle" value= "Date"/>
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d [%t] %-5p %c - %m%n %loggername" />
      </layout>
    </appender>

    <!-- 控制台前台显示日志 -->
    <appender name="ColoredConsoleAppender" type="log4net.Appender.ColoredConsoleAppender">
      <mapping>
        <level value="ERROR" />
        <foreColor value="Red, HighIntensity" />
      </mapping>
      <mapping>
        <level value="Info" />
        <foreColor value="Green" />
      </mapping>
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%n%date{HH:mm:ss,fff} [%-5level] %m" />
      </layout>

      <filter type="log4net.Filter.LevelRangeFilter">
        <param name="LevelMin" value="Info" />
        <param name="LevelMax" value="Fatal" />
      </filter>
    </appender>

    <root>
      <!--(高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL (低) -->
      <level value="all" />
      <appender-ref ref="ColoredConsoleAppender"/>
      <appender-ref ref="RollingLogFileAppender"/>
    </root>
  </log4net>
</configuration>
img_ebd202975c4912411271ab8e6f18767a.png
image.png

在Main方法种开始执行时,对Log4Net进行日志配置加载。

第二部:爬取信息

使用HtmlAgility,如果对此第三方库不是很理解的,可以参考LZ的爬虫系列文章,里面有对其讲解。
代码不做过多讲解,主要就是注意获取当天数据

    public class JKNews
    {
        /// <summary>
        /// 得到今日的新闻
        /// </summary>
        /// <returns></returns>
        public static List<Notice> GetTodayNews()
        {
            string[] url =
            {
                "http://www.jit.edu.cn/myNews_list_out.aspx?infotype=1",
                "http://www.jit.edu.cn/myNews_list_out.aspx?infotype=2"
            };

            var web = new HtmlWeb();
            web.OverrideEncoding = Encoding.GetEncoding("gb2312");
            List<Notice> noticeItems = new List<Notice>();
            for (int i = 0; i < url.Length; i++)
            {
                var docWeb = web.Load(url[i]);
                var listItems = docWeb.DocumentNode.SelectNodes("//*[@id=\"table_list\"]/li").ToList();
                foreach (var item in listItems)
                {
                    string href = item.SelectSingleNode("./a").Attributes["href"].Value;
                    string title = item.InnerText;
                    string remark = item.SelectSingleNode("./span[@class=\'puber\']").InnerText;

                    var splitArr = remark.Split(' ');
                    string dep = splitArr[0].TrimStart('[');
                    string time = splitArr[1].TrimEnd(']');
                    noticeItems.Add(new Notice()
                    {
                        Href = href,
                        Title = title,
                        Dep = dep,
                        Time = time
                    });
                }
            }

            return noticeItems.Where(u => Convert.ToDateTime(u.Time).Date.Equals(DateTime.Now)).ToList();
        }
    }

比较俩日期相同
方法一
System.Data.Entity.DbFunctions.DiffDays(cs.StartTime.Value,DateTime.Now) == 0只获取当天
方法二:
XX.StartTime.Value.Date.Equals(DateTime.Now.Date)//只获取当天

img_14d472afbcba4e9e317fe231dc05bcbc.png
使用方法一.png

第三步:使用QuartZ建立一个定时任务

1.建立一个 ToExcelJob 继承 IJob接口,实现方法

img_7a3840826de2e1b3c66f624da522b0a8.png
定时方法.png

定时方法Exceute种分俩部分执行
第一部分:获取爬取后的数据
第二部分:数据保存到Excel文件

   public class ToExcelJob : IJob
    {
        private static string excelPath = ConfigurationManager.AppSettings["ExcelPath"];
        static readonly ILog Log = LogManager.GetLogger(typeof(ToExcelJob));

        public void Execute(IJobExecutionContext context)
        {
            try
            {
                if (!Directory.Exists(excelPath))
                {
                    Directory.CreateDirectory(excelPath);
                }

                var items = JKNews.GetTodayNews();
                var excel = new Excel();
                excel.CreateSheet("Sheet1");
                int rowIndex = 0;
                excel.WriteTitle(new string[] { "链接", "标题", "部门", "日期" }, 0, 0);
                rowIndex++;
                foreach (var item in items)
                {
                    excel.CreateRow(0, rowIndex);
                    excel.WriteProperty<Notice>(item, 0, rowIndex, 0);
                    rowIndex++;
                }
                excel.SetColumnWidth(0, 0, new[] { 20, 30, 10, 10 });
                string savePath = Path.Combine(excelPath, string.Format("{0}.xlsx", DateTime.Now.ToString("yyyy.MM.dd")));
                excel.WriteFile(savePath);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message, ex);
            }
        }
    }

第四步:定制TopShelf服务类,对开始和结束进行代码描述

构造函数中使用Quartz.Net 开始进行任务的创建
首先创建一个调度器
然后创建一个任务
然后创建一个触发器,这一步中我们设置了cron为每晚8点,具体使用的大家可以看cron语法
然后将任务与触发器添加到调度器中并执行
在构造函数中对当前任务(Job)进行初始化配置,然后开放俩个方法Start和Stop让便上层调用

    public class ToExcelRunner 
    {
        static readonly ILog _log = LogManager.GetLogger(typeof(ToExcelRunner));
        private readonly IScheduler scheduler;

        public ToExcelRunner()
        {
            // 创建一个调度器
            scheduler = StdSchedulerFactory.GetDefaultScheduler();
            //2、创建一个任务
            IJobDetail job = JobBuilder.Create<ToExcelJob>().WithIdentity("job1", "group1").Build();
            //3、创建一个触发器
            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .WithCronSchedule("0 0 20 ? * *")     //每天晚上8点执行
                .Build();
            //4 将任务与触发器添加到调度器中并执行
            scheduler.ScheduleJob(job, trigger);
        }

        public void Start()
        {
            try
            {
                _log.Info("服务开启");
                scheduler.Start();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        
        }

        public void Stop()
        {
            _log.Info("服务结束");
            scheduler.Shutdown(false);
        }
    }

第五步:TopShelf配置

s.ConstructUsing(name => new ToExcelRunner()); 服务使用ToExcelRunner
对服务的Started注册tc.Start()方法
对服务的Stopped注册tc.Stop()方法
使用日志记录,出错时候记录。

   class Program
   {
       static readonly ILog _log = LogManager.GetLogger(typeof(Program));

       static void Main(string[] args)
       {
           FileInfo fi = new FileInfo(AppDomain.CurrentDomain.BaseDirectory + "\\log4net.config");
           XmlConfigurator.ConfigureAndWatch(fi);
           try
           {
               HostFactory.Run(x =>
               {
                   x.Service<ToExcelRunner>(s =>
                   {
                       s.ConstructUsing(name => new ToExcelRunner());
                       s.WhenStarted(tc => tc.Start());
                       s.WhenStopped(tc => tc.Stop());
                   });
                   x.RunAsLocalSystem();

                   x.SetDescription("每天晚上8点讲当日新闻保存为Excel");
                   x.SetDisplayName("新闻保存服务");
                   x.SetServiceName("新闻保存服务");
               });

           }
           catch (Exception ex)
           {
               _log.Error(ex);
           }
       }
   }

第六步:发布为windows服务

配置运行

没错,整个程序已经开发完了,接下来,只需要简单配置一下,即可以当服务来使用了。安装很方便:
安装:JKNoticeget.exe install
启动:JKNoticeget.exe start
卸载:JKNoticeget.exe uninstall

管理员身份进入,对应路径,注册服务


img_616ac8480620d3544e7321724bd30269.png
image.png
img_82379f6a2d894446ae8cdac5c70cdbbf.png
image.png
img_8f16499b558f1ca96883eb9e8de2fdb3.png
image.png

代码链接 https://github.com/happlyfox/FoxCrawler/tree/master/%E5%AD%A6%E4%B9%A0%E7%A4%BA%E4%BE%8B/JKNoticeget

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
3月前
|
NoSQL Redis Windows
windows服务器重装系统之后,Redis服务如何恢复?
windows服务器重装系统之后,Redis服务如何恢复?
75 6
|
27天前
|
网络安全 Windows
Windows server 2012R2系统安装远程桌面服务后无法多用户同时登录是什么原因?
【11月更文挑战第15天】本文介绍了在Windows Server 2012 R2中遇到的多用户无法同时登录远程桌面的问题及其解决方法,包括许可模式限制、组策略配置问题、远程桌面服务配置错误以及网络和防火墙问题四个方面的原因分析及对应的解决方案。
|
2月前
|
边缘计算 安全 网络安全
|
2月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
106 9
|
2月前
|
应用服务中间件 Apache Windows
免安装版的Tomcat注册为windows服务
免安装版的Tomcat注册为windows服务
135 3
|
2月前
|
Java 关系型数据库 MySQL
java控制Windows进程,服务管理器项目
本文介绍了如何使用Java的`Runtime`和`Process`类来控制Windows进程,包括执行命令、读取进程输出和错误流以及等待进程完成,并提供了一个简单的服务管理器项目示例。
42 1
|
2月前
|
XML 缓存 前端开发
Electron-builder 是如何打包 Windows 应用的?
本文首发于微信公众号“前端徐徐”,作者徐徐深入解析了 electron-builder 在 Windows 平台上的打包流程。文章详细介绍了 `winPackager.ts`、`AppxTarget.ts`、`MsiTarget.ts` 和 `NsisTarget.ts` 等核心文件,涵盖了目标创建、图标处理、代码签名、资源编辑、应用签名、性能优化等内容,并分别讲解了 AppX/MSIX、MSI 和 NSIS 安装程序的生成过程。通过这些内容,读者可以更好地理解和使用 electron-builder 进行 Windows 应用的打包和发布。
176 0
|
3月前
|
消息中间件 Java Kafka
windows服务器重装系统之后,Kafka服务如何恢复?
windows服务器重装系统之后,Kafka服务如何恢复?
35 8
|
2月前
|
弹性计算 关系型数据库 网络安全
阿里云国际版无法连接和访问Windows服务器中的FTP服务
阿里云国际版无法连接和访问Windows服务器中的FTP服务
|
3月前
|
安全 Windows
电脑进入桌面后操作无响应?不妨试试禁用Windows Search服务
电脑进入桌面后操作无响应?不妨试试禁用Windows Search服务