网站程序自带的采集器采集文章(如何制作一只简单的Web爬虫的基础知识系统?-八维教育)

优采云 发布时间: 2021-11-10 19:06

  网站程序自带的采集器采集文章(如何制作一只简单的Web爬虫的基础知识系统?-八维教育)

  在前面的章节中,我们已经陆续介绍了使用C#制作爬虫的基础知识,现在我们应该对如何制作一个简单的网络爬虫有了更好的了解。

  本节我们搭建一个完整的爬虫系统,将之前的零散事物连接起来,可以作为一个爬虫项目运行过程的初步探索。但是,在实际项目中,还有其他问题需要解决。我们将在后续章节中继续修炼。:)

  先看一下解决方案的整体结构:

  

  我们也希望我们的爬虫框架可以应用到跨平台的项目中,所以这个项目以.Net Core Framework为基础。

  根据上图,项目结构还是很简单的。爬虫框架部分与上一章的内容相比没有太大变化。本节主要看应用中如何将一只小蚂蚁扩展为一群小蚂蚁。

  本样例项目以采集某部网络小说网站为例,特此对小说网站说一句话:如有冒犯,敬请谅解,如有引流,请赐教奖励:P

  好了,步入正文,现在我们来看看应用入口(MikeWare.Crawler.EBooks)项目,是怎么做的。

  

  

   1 namespace MikeWare.Crawlers.EBooks

2 {

3 using MikeWare.Crawlers.EBooks.Bizs;

4 using MikeWare.Crawlers.EBooks.Entities;

5 using System;

6

7 class Program

8 {

9 static void Main(string[] args)

10 {

11 var lastUpdateTime = DateTime.MinValue;

12

13 BooksList.Start(1, lastUpdateTime);

14

15 Console.Read();

16 }

17 }

18 }

  入门项目-程序类

  这个项目非常简单。它使用项目的初始 Program 类。Main方法中构造了一个DateTime lastUpdateTime变量,然后启动采集任务。

  关于lastUpdateTime变量,我们可以理解为,在采集的过程中,我们可能需要对数据源反复执行采集才能获取更新的数据。在实际情况下,可能会更新数据源。并非所有数据都在变化。例如,本例中的小说。小说的作者昨天写了一些章节。那么这些章节在今天甚至今生都不会改变。又改了,所以我们不需要每次采集都采集小说的所有章节,也就是我们只对较新的小说感兴趣,那么如何区分新的数据呢?与旧数据相比,这取决于数据源为我们提供了什么样的特征。可以从中找到一个或多个合适的特征作为我们的地标。在这种情况下,使用小说的更新时间。可以根据具体情况自定义lastUpdateTime的起源,达到采集递增的目的。

  所以第一次采集,我们不妨再采集整个网站的所有小说。那么,这时候可以将lastUpdateTime的初始值设置为DateTime.MinValue,这样即使一本小说再老,它的更新时间也不会早于这个标志位,达到< @采集 所有小说;那么对于另一个采集,我们可以先统计最后一个采集的结果,把最近的更新时间作为这个采集的lastUpdateTime。所以第一次采集或者再次采集,逻辑可以合并为“获取上次采集的最后更新时间”,这个逻辑内部会判断,如果有一条采集记录,返回最近的更新时间,如果没有则返回DateTime.MinValue,这样一切就统一了。

  同时,这个项目其实只是为采集任务的启动提供了一个触发点。我尽量让它很轻,以便它可以很容易地移植。或许 WinForm 项目的 Button_Click 事件或 WebApplication 项目的 Page_Load 事件是其入口点。Anywhere 和 Main 方法中的内容,复制过去就好了 :) View 部分暂时不多说。

  接下来我们简单介绍一下(MikeWare.Crawlers.EBooks.Entities)项目

  

  

   1 namespace MikeWare.Crawlers.EBooks.Entities

2 {

3 using System;

4 using System.Collections.Generic;

5

6 public class Book

7 {

8 public int Id { get; set; }

9 public string Name { get; set; }

10 public string PhotoUrl { get; set; }

11 public Dictionary Sections { get; set; }

12 public Dictionary SectionContents { get; set; }

13

14 public string Author { get; set; }

15 public DateTime LastUpdateTime { get; set; }

16 }

17 }

  实体类-Book

  这个项目也很简单。只提供一门课(书)。在这个类中,定义了一本书的ID、名称、封面图片的URL、作者、最后更新时间和章节内容等属性。用于描述一本书的基本特征。但是,我没有采集书评和评分内容,一、数据源不提供书评数据;二、 希望实现自己的评分和评价体系,不依赖于数据源的评分;这里我只想说明一下,实体的定义是针对业务服务的,大家可以根据自己的需求进行自定义;当然,如果你想要数据完整,我们应该采集过来做。坚持。如果你在未来的某一天突然想再次使用这部分数据怎么办?采集 再次?哈哈……打你脑袋的东西总是防不胜防。

  好的,接下来介绍一下(MikeWare.Crawlers.EBooks.Bizs)项目

  

  

<p> 1 namespace MikeWare.Crawlers.EBooks.Bizs

2 {

3 using MikeWare.Core.Components.CrawlerFramework;

4 using System;

5 using System.Net;

6 using System.Text;

7 using System.Text.RegularExpressions;

8 using System.Threading;

9 using System.Threading.Tasks;

10

11 public class BooksList

12 {

13 private static Encoding encoding = new UTF8Encoding(false);

14 private static int total_page = -1;

15 private static Regex regex_list = new Regex(@"[^尾页</a>.+?", RegexOptions.Singleline);

17

18 public static void Start(int pageIndex, DateTime lastUpdateTime)

19 {

20 new WorkerAnt()

21 {

22 AntId = (uint)Math.Abs(DateTime.Now.ToString("yyyyMMddHHmmssfff").GetHashCode()),

23 OnJobStatusChanged = (sender, args) =>

24 {

25 Console.WriteLine($"{args.EventAnt.AntId} said: {args.Context.JobName} entered status '{args.Context.JobStatus}'.");

26 switch (args.Context.JobStatus)

27 {

28 case TaskStatus.Created:

29 if (string.IsNullOrEmpty(args.Context.JobName))

30 {

31 Console.WriteLine($"Can not execute a job with no name.");

32 args.Cancel = true;

33 }

34 else

35 Console.WriteLine($"{args.EventAnt.AntId} said: job {args.Context.JobName} created.");

36 break;

37 case TaskStatus.Running:

38 if (null != args.Context.Memory)

39 Console.WriteLine($"{args.EventAnt.AntId} said: {args.Context.JobName} already downloaded {args.Context.Memory.Length} bytes.");

40 break;

41 case TaskStatus.RanToCompletion:

42 if (null != args.Context.Buffer && 0 lastUpdateTime)

84 {

85 Thread.Sleep(5);

86 BookSectionsList.Start(id);

87 }

88 else

89 return;

90 }

91 }

92

93 if (-1 == total_page)

94 {

95 var match = regex_page.Match(context);

96 if (null != match && match.Success && int.TryParse(match.Groups["totalPage"].Value, out total_page)) ;

97

98 }

99

100 if (pageIndex

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线