.NET使用分散式網路爬蟲框架DotnetSpider快速開發爬蟲功能

2023-12-08 09:00:23

前言

前段時間有同學在微信群裡提問,要使用.NET開發一個簡單的爬蟲功能但是沒有做過無從下手。今天給大家推薦一個輕量、靈活、高效能、跨平臺的分散式網路爬蟲框架(可以幫助 .NET 工程師快速的完成爬蟲的開發):DotnetSpider。

注意:為了自身安全請在國家法律允許範圍內開發網路爬蟲功能。

框架設計圖

整個爬蟲設計是純非同步的,利用訊息佇列進行各個元件的解耦,若是隻需要單機爬蟲則不需要做任何額外的設定,預設使用了一個記憶體型的訊息佇列;若是想要實現一個純分散式爬蟲,則需要引入一個訊息佇列即可,後面會詳細介紹如何實現一個分散式爬蟲。

框架原始碼

開發爬蟲需求

爬取部落格園10天推薦排行第一頁的文章標題、文章簡介和文章地址,並將其儲存到對應的txt文字中。

請求地址:https://www.cnblogs.com/aggsite/topdiggs

快速開始

建立SpiderSample控制檯

安裝DotnetSpider Nuget包

搜尋:DotnetSpider

新增Serilog紀錄檔元件

搜尋:Serilog.AspNetCore

RecommendedRankingModel

    public class RecommendedRankingModel
    {
        /// <summary>
        /// 文章標題
        /// </summary>
        public string ArticleTitle { get; set; }

        /// <summary>
        /// 文章簡介
        /// </summary>
        public string ArticleSummary { get; set; }

        /// <summary>
        /// 文章地址
        /// </summary>
        public string ArticleUrl { get; set; }
    }

RecommendedRankingSpider

    public class RecommendedRankingSpider : Spider
    {
        public RecommendedRankingSpider(IOptions<SpiderOptions> options,
            DependenceServices services,
            ILogger<Spider> logger) : base(options, services, logger)
        {
        }

        public static async Task RunAsync()
        {
            var builder = Builder.CreateDefaultBuilder<RecommendedRankingSpider>();
            builder.UseSerilog();
            builder.UseDownloader<HttpClientDownloader>();
            builder.UseQueueDistinctBfsScheduler<HashSetDuplicateRemover>();
            await builder.Build().RunAsync();
        }

        protected override async Task InitializeAsync(CancellationToken stoppingToken = default)
        {
            // 新增自定義解析
            AddDataFlow(new Parser());
            // 使用控制檯記憶體
            AddDataFlow(new ConsoleStorage());
            // 新增採集請求
            await AddRequestsAsync(new Request("https://www.cnblogs.com/aggsite/topdiggs")
            {
                // 請求超時10秒
                Timeout = 10000
            });
        }

        class Parser : DataParser
        {
            public override Task InitializeAsync()
            {
                return Task.CompletedTask;
            }

            protected override Task ParseAsync(DataFlowContext context)
            {
                var recommendedRankingList = new List<RecommendedRankingModel>();
                // 網頁資料解析
                var recommendedList = context.Selectable.SelectList(Selectors.XPath(".//article[@class='post-item']"));
                foreach (var news in recommendedList)
                {
                    var articleTitle = news.Select(Selectors.XPath(".//a[@class='post-item-title']"))?.Value;
                    var articleSummary = news.Select(Selectors.XPath(".//p[@class='post-item-summary']"))?.Value?.Replace("\n", "").Replace(" ", "");
                    var articleUrl = news.Select(Selectors.XPath(".//a[@class='post-item-title']/@href"))?.Value;

                    recommendedRankingList.Add(new RecommendedRankingModel
                    {
                        ArticleTitle = articleTitle,
                        ArticleSummary = articleSummary,
                        ArticleUrl = articleUrl
                    });
                }

                using (StreamWriter sw = new StreamWriter("recommendedRanking.txt"))
                {
                    foreach (RecommendedRankingModel model in recommendedRankingList)
                    {
                        string line = $"文章標題:{model.ArticleTitle}\r\n文章簡介:{model.ArticleSummary}\r\n文章地址:{model.ArticleUrl}";
                        sw.WriteLine(line+ "\r\n ==========================================================================================");
                    }
                }
                return Task.CompletedTask;
            }
        }
    }

Program呼叫

   internal class Program
   {
       static async Task Main(string[] args)
       {
           Console.WriteLine("Hello, World!");

           await RecommendedRankingSpider.RunAsync();

           Console.WriteLine("資料抓取完成");
       }
   }

抓取資料和頁面資料對比

抓取資料:

頁面資料:

 

專案原始碼地址

更多專案實用功能和特性歡迎前往專案開源地址檢視