狠狠色丁香婷婷综合尤物/久久精品综合一区二区三区/中国有色金属学报/国产日韩欧美在线观看 - 国产一区二区三区四区五区tv

LOGO OA教程 ERP教程 模切知識交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C#簡化工作之實現(xiàn)網(wǎng)頁爬蟲獲取數(shù)據(jù)

freeflydom
2023年11月28日 15:51 本文熱度 981

1、需求

想要獲取網(wǎng)站上所有的氣象信息,網(wǎng)站如下所示:

目前總共有67頁,隨便點開一個如下所示:

需要獲取所有天氣數(shù)據(jù),如果靠一個個點開再一個個復(fù)制粘貼那么也不知道什么時候才能完成,這個時候就可以使用C#來實現(xiàn)網(wǎng)頁爬蟲獲取這些數(shù)據(jù)。

2、效果

先來看下實現(xiàn)的效果,所有數(shù)據(jù)都已存入數(shù)據(jù)庫中,如下所示:

總共有4萬多條數(shù)據(jù)。

3、具體實現(xiàn)

構(gòu)建每一頁的URL

第一頁的網(wǎng)址如下所示:

最后一頁的網(wǎng)址如下所示:

可以發(fā)現(xiàn)是有規(guī)律的,那么就可以先嘗試構(gòu)建出每個頁面的URL

    // 發(fā)送 GET 請求
   string url = "https://cj.msa.gov.cn/xxgk/xxgkml/aqxx/qxyg/";
   HttpResponseMessage response = await httpClient.GetAsync(url);

   // 處理響應(yīng)
   if (response.IsSuccessStatusCode)
   {
       string responseBody = await response.Content.ReadAsStringAsync();
       doc.LoadHtml(responseBody);
       //獲取需要的數(shù)據(jù)所在的節(jié)點
       var node = doc.DocumentNode.selectSingleNode("//div[@class=\"page\"]/script");
       string rawText = node.InnerText.Trim();
       // 使用正則表達(dá)式來匹配頁數(shù)數(shù)據(jù)
       Regex regex = new Regex(@"\b(\d+)\b");
       Match match = regex.Match(rawText);
       if (match.Success)
       {
           string pageNumber = match.Groups[1].Value;
           Urls = GetUrls(Convert.ToInt32(pageNumber));
           MessageBox.Show($"獲取每個頁面的URL成功,總頁面數(shù)為:{Urls.Length}");
       }

   }

//構(gòu)造每一頁的URL
public string[] GetUrls(int pageNumber)
{
    string[] urls = new string[pageNumber];
    for (int i = 0; i < urls.Length; i++)
    {
        if (i == 0)
        {
            urls[i] = "https://cj.msa.gov.cn/xxgk/xxgkml/aqxx/qxyg/index.shtml";
        }
        else
        {
            urls[i] = $"https://cj.msa.gov.cn/xxgk/xxgkml/aqxx/qxyg/index_{i}.shtml";
        }
    }
    return urls;
}

這里使用了HtmlAgilityPack

HtmlAgilityPack(HAP)是一個用于處理HTML文檔的.NET庫。它允許你方便地從HTML文檔中提取信息,修改HTML結(jié)構(gòu),并執(zhí)行其他HTML文檔相關(guān)的操作。HtmlAgilityPack 提供了一種靈活而強(qiáng)大的方式來解析和處理HTML,使得在.NET應(yīng)用程序中進(jìn)行網(wǎng)頁數(shù)據(jù)提取和處理變得更加容易。

 // 使用HtmlAgilityPack解析網(wǎng)頁內(nèi)容
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml("需要解析的Html");
//獲取需要的數(shù)據(jù)所在的節(jié)點
var node = doc.DocumentNode.selectSingleNode("XPath");

那么XPath是什么呢?

XPath(XML Path Language)是一種用于在XML文檔中定位和選擇節(jié)點的語言。它是W3C(World Wide Web Consortium)的標(biāo)準(zhǔn),通常用于在XML文檔中執(zhí)行查詢操作。XPath提供了一種簡潔而強(qiáng)大的方式來導(dǎo)航和操作XML文檔的內(nèi)容。

構(gòu)建每一天的URL

獲取到了每一頁的URL之后,我們發(fā)現(xiàn)在每一頁的URL都可以獲取關(guān)于每一天的URL信息,如下所示:

可以進(jìn)一步構(gòu)建每一天的URL,同時可以根據(jù)a的文本獲取時間,當(dāng)然也可以通過其他方式獲取時間,但是這種可以獲取到11點或者17點。

代碼如下所示:

    for (int i = 0; i < Urls.Length; i++)
   {
       // 發(fā)送 GET 請求
       string url2 = Urls[i];
       HttpResponseMessage response2 = await httpClient.GetAsync(url2);
       // 處理響應(yīng)
       if (response2.IsSuccessStatusCode)
       {
           string responseBody2 = await response2.Content.ReadAsStringAsync();
           doc.LoadHtml(responseBody2);
           var nodes = doc.DocumentNode.selectNodes("//div[@class=\"lie\"]/ul/li");
           for (int j = 0; j < nodes.Count; j++)
           {
               var name = nodes[j].ChildNodes[3].InnerText;
               //只有name符合下面的格式才能成功轉(zhuǎn)換為時間,所以這里需要有一個判斷
               if (name != "" && name.Contains("氣象預(yù)告"))
               {
                   var dayUrl = new DayUrl();
                   //string format;
                   //DateTime date;
                   // 定義日期時間格式
                   string format = "yyyy年M月d日H點氣象預(yù)告";
                   // 解析字符串為DateTime
                   DateTime date = DateTime.ParseExact(name, format, null);
                   var a = nodes[j].ChildNodes[3];
                   string urlText = a.GetAttributeValue("href", "");
                   string newValue = "https://cj.msa.gov.cn/xxgk/xxgkml/aqxx/qxyg/";
                   string realUrl = "";
                   realUrl = newValue + urlText.Substring(1);
                   dayUrl.Date = date;
                   dayUrl.Url = realUrl;
                   dayUrlList.Add(dayUrl);
               }
               else
               {
                   Debug.WriteLine($"在{name}處,判斷不符合要求");
               }

           }
       }
   }
   // 將數(shù)據(jù)存入SQLite數(shù)據(jù)庫
   db.insertable(dayUrlList.OrderBy(x => x.Date).ToList()).executeCommand();
   MessageBox.Show($"獲取每天的URL成功,共有{dayUrlList.Count}條");
}

在這一步驟需要注意的是XPath的書寫,以及每一天URL的構(gòu)建,以及時間的獲取。

XPath的書寫:

 var nodes = doc.DocumentNode.selectNodes("//div[@class=\"lie\"]/ul/li");

表示一個類名為"lie"的div下的ul標(biāo)簽下的所有l(wèi)i標(biāo)簽,如下所示:

構(gòu)建每一天的URL:

 var a = nodes[j].ChildNodes[3];
string urlText = a.GetAttributeValue("href", "");
string newValue = "https://cj.msa.gov.cn/xxgk/xxgkml/aqxx/qxyg/";
string realUrl = "";
realUrl = newValue + urlText.Substring(1);

這里獲取li標(biāo)簽下的a標(biāo)簽,如下所示:

string urlText = a.GetAttributeValue("href", "");

這段代碼獲取a標(biāo)簽中href屬性的值,這里是./202311/t20231127_3103490.shtml。

 string urlText = a.GetAttributeValue("href", "");
string newValue = "https://cj.msa.gov.cn/xxgk/xxgkml/aqxx/qxyg/";
string realUrl =  newValue + urlText.Substring(1);

這里是在拼接每一天的URL。

var name = nodes[j].ChildNodes[3].InnerText;
// 定義日期時間格式
string format = "yyyy年M月d日H點氣象預(yù)告";
// 解析字符串為DateTime
DateTime date = DateTime.ParseExact(name, format, null);

這里是從文本中獲取時間,比如文本的值也就是name的值為:“2023年7月15日17點氣象預(yù)告”,name獲得的date就是2023-7-15 17:00。

    // 將數(shù)據(jù)存入SQLite數(shù)據(jù)庫
   db.insertable(dayUrlList.OrderBy(x => x.Date).ToList()).executeCommand();
   MessageBox.Show($"獲取每天的URL成功,共有{dayUrlList.Count}條");

這里是將數(shù)據(jù)存入數(shù)據(jù)庫中,ORM使用的是SQLSugar,類DayUrl如下:

internal class DayUrl
{
   [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int Id { get; set; }
   public DateTime Date { get; set; }
   public string Url { get; set; }
}

最后獲取每一天URL的效果如下所示:

獲取溫度數(shù)據(jù)

需要獲取的內(nèi)容如下:

設(shè)計對應(yīng)的類如下:

internal class WeatherData
{
   [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
   public int Id { get; set; }
   public string? StationName { get; set; }
   public string? Weather {  get; set; }
   public string? Tem_Low {  get; set; }
   public string? Tem_High { get; set; }
   public string? Wind {  get; set; }
   public string? Visibility_Low { get; set; }
   public string? Visibility_High { get; set; }
   public string? Fog { get; set; }
   public string? Haze { get; set; }
   public DateTime Date { get; set; }
}

增加了一個時間,方便以后根據(jù)時間獲取。

獲取溫度數(shù)據(jù)的代碼如下:

    var list = db.Queryable<DayUrl>().ToList();
   for (int i = 0; i < list.Count; i++)
   {
       HttpResponseMessage response = await httpClient.GetAsync(list[i].Url);
       // 處理響應(yīng)
       if (response.IsSuccessStatusCode)
       {
           string responseBody2 = await response.Content.ReadAsStringAsync();
           doc.LoadHtml(responseBody2);
           var nodes = doc.DocumentNode.selectNodes("//table");
           if (nodes != null)
           {
               var table = nodes[5];
               var trs = table.selectNodes("tbody/tr");
               for (int j = 1; j < trs.Count; j++)
               {
                   var tds = trs[j].selectNodes("td");
                   switch (tds.Count)
                   {
                       case 8:
                           var wd8 = new WeatherData();
                   wd8.StationName = tds[0].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Weather = tds[1].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Tem_Low = tds[2].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Tem_High = tds[3].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Wind = tds[4].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Visibility_Low = tds[5].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Visibility_High = tds[6].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Fog = tds[7].InnerText.Trim().Replace("&nbsp;", "");
                           wd8.Date = list[i].Date;
                           weatherDataList.Add(wd8);
                           break;
                       case 9:
                           var wd9 = new WeatherData();
                           wd9.StationName = tds[0].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Weather = tds[1].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Tem_Low = tds[2].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Tem_High = tds[3].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Wind = tds[4].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Visibility_Low = tds[5].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Visibility_High = tds[6].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Fog = tds[7].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Haze = tds[8].InnerText.Trim().Replace("&nbsp;", "");
                           wd9.Date = list[i].Date;
                           weatherDataList.Add(wd9);
                           break;
                       default:
                           break;
                   }


               }
           }
           else
           {
               
             
           }
       }
       // 輸出進(jìn)度提示
       Debug.WriteLine($"已處理完成第{i}個URL");
   }
   // 將數(shù)據(jù)存入SQLite數(shù)據(jù)庫
   db.insertable(weatherDataList.OrderBy(x => x.Date).ToList()).executeCommand();
   MessageBox.Show($"獲取天氣數(shù)據(jù)成功,共有{weatherDataList.Count}條");

}

這里使用swith case是因為網(wǎng)頁的格式并不是一層不變的,有時候少了一列,沒有霾的數(shù)據(jù)。

 wd9.StationName = tds[0].InnerText.Trim().Replace("&nbsp;", "");

這里對文本進(jìn)行這樣處理是因為原始的數(shù)據(jù)是“\n內(nèi)容&nbsp\n”,C#中String.Trim()方法會刪除字符串前后的空白,string.Replace("a","b")方法會將字符串中的a換成b。

效果如下所示:

將數(shù)據(jù)全部都存入數(shù)據(jù)庫中了。

4、最后

通過這個實例說明了其實C#也是可以實現(xiàn)網(wǎng)頁爬蟲的,對于沒有反爬的情況下是完全適用的,再配合linq做數(shù)據(jù)處理也是可以的。


作者:mingupupup

原文鏈接:https://www.cnblogs.com/mingupupu/p/17860491.html


該文章在 2023/11/28 15:51:32 編輯過
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點晴ERP是一款針對中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國內(nèi)大量中小企業(yè)的青睞。
點晴PMS碼頭管理系統(tǒng)主要針對港口碼頭集裝箱與散貨日常運作、調(diào)度、堆場、車隊、財務(wù)費用、相關(guān)報表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點,圍繞調(diào)度、堆場作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點晴WMS倉儲管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購管理,倉儲管理,倉庫管理,保質(zhì)期管理,貨位管理,庫位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號管理軟件。
點晴免費OA是一款軟件和通用服務(wù)都免費,不限功能、不限時間、不限用戶的免費OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved