C#簡單爬取數據(.NET使用HTML解析器NSoup和正則兩種方式匹配數據)

1、獲取數據

想弄一個數據庫,因爲須要一些人名,因此就去百度一下,而後發現了360圖書館中有不少人名html

而後就像去複製一下,發現複製不了,須要登錄正則表達式

此時f12查看源碼是能夠複製的,不過就算能夠複製想要插入數據也是很麻煩的。既然複製走不通,因而我抱着探索知識的精神,打開了Visual Studio數據庫

首先咱們須要先拿到整個頁面的數據,此時的話可使用WebClient對象來獲取數據(HttpWebRequest方式稍微有點麻煩),而後使用byte數組來接受一下返回值

public static void GetData(String address)
{
    WebClient wc = new WebClient();
    byte[] htmlData = wc.DownloadData(address);
}

此時須要將htmlData對象解碼爲String對象,而後咱們在網站中f12看一下解碼方式編程

能夠看到charset=utf-8,說明須要用utf-8來解碼,而後使用Encoding對象來解碼數組

string html = Encoding.UTF8.GetString(htmlData);

咱們輸出一下html有沒有值學習

static void Main(string[] args)
{
    //將地址複製過來
    GetData("http://www.360doc.com/content/18/1010/13/642066_793541226.shtml");
    Console.ReadKey();
}

public static void GetData(String address)
{
    WebClient wc = new WebClient();
    //地址由調用時傳入
    byte[] htmlData = wc.DownloadData(address);

    string html = Encoding.UTF8.GetString(htmlData);

    Console.WriteLine(html);

}

輸出:網站

2、Regex匹配

接下來就是匹配的問題了,首先看一下html文檔的結構url

就是說只須要匹配到全部的p標籤,而後拿到其中的內容就好了spa

第一種想到的就是使用正則表達式匹配:code

public static void GetData(String address)
{
    WebClient wc = new WebClient();
    //地址由調用時傳入
    byte[] htmlData = wc.DownloadData(address);

    string html = Encoding.UTF8.GetString(htmlData);

    //使用正則表達式匹配    <p或P>非空字符至少100個<P或p>
    Regex reg = new Regex("<[pP]>\\S{100,}</[Pp]>");
    //接受全部匹配到的項
    MatchCollection result = reg.Matches(html);
    //循環輸出
    foreach (Match item in result)
    {
        Console.WriteLine(item.Value);
    }
}

調用不變,啓動:

匹配到是匹配到了,可是咱們把<p></p>標籤也匹配出來了,因此把正則表達式改進一下,使用組匹配,將p標籤中的內容單獨匹配出來(固然也能夠截取字符串)。也就是說在寫正則表達式時,將想要單獨匹配出來的數據用括號"(想要單獨匹配出來的數據)"括起來,來看一下怎麼寫:

Regex reg = new Regex("<[pP]>(\\S{100,})</[Pp]>");

而後若是想要拿數據的話,須要使用Match對象的Groups屬性經過索引來獲取匹配到的組:

public static void GetData(String address)
{
    WebClient wc = new WebClient();
    //地址由調用時傳入
    byte[] htmlData = wc.DownloadData(address);

    string html = Encoding.UTF8.GetString(htmlData);

    //使用正則表達式組匹配    <p或P>(非空字符至少100個)<P或p>
    Regex reg = new Regex("<[pP]>(\\S{100,})</[Pp]>");
    
    //接受全部匹配到的項
    MatchCollection result = reg.Matches(html);
    //循環輸出
    foreach (Match item in result)
    {
        //0的話是總體匹配到的字符串對象
        //1就是第一個匹配到的組(\\S{100,)
        Console.WriteLine(item.Groups[1]);
    }
}

輸出結果:

此次p標籤就沒有被匹配進入組中(若是經過item.Groups[0]拿到的回是和上面匹配到同樣的數據,會帶p標籤)

匹配到了以後就可使用item.Groups[1].Split('、')來將字符串分割爲String數組,而後循環寫入數據庫,或者進行其餘操做。

3、HTML解析器NSoup

雖然正則表達式也能夠匹配,可是若是對正則表達式比較陌生的話,可能就不是友好了。若是有方法能夠像用js操做html元素同樣,用C#操做html字符串,就很是棒了。NSoup就是能夠作到解析html字符串,變成可操做的對象。

首先使用前先在管理NuGet程序包中添加:NSoup,直接就能夠搜索到,添加完成以後接下來就看一下如何使用

使用NSoupClient.Parse(放入html代碼:<html>....</html>)建立一個聲明Docuemnt文檔對象:

//聲明Document對象
Document doc = NSoupClient.Parse(html);

第二種就是使用Document doc = NSoupClient.Connect(放入url)    .Get()/.Post(),而後他就會自動獲取url地址的html代碼,而且根據html代碼加載一個Document對象

//經過url自動加載Document對象
Document doc = NSoupClient.Connect(address).Get();

固然還有其餘方式獲取,而後咱們看一下如何使用Document對象

//經過id獲取元素
//獲取id爲form的元素
Element form = doc.GetElementById("form");
//經過標籤名獲取元素
//獲取全部的p標籤
Elements p = doc.GetElementsByTag("p");
//經過類樣式獲取元素 
//獲取類樣式爲btn的元素
Elements c = doc.GetElementsByClass("btn");
//經過屬性獲取
//獲取包含style屬性的元素
Elements attr =  doc.GetElementsByAttribute("style");

也能夠本身組合一些其餘的嵌套操做,例如:

獲取id爲artContent下的全部p標籤

//使用鏈式編程
//獲取id爲artContent下的全部p標籤
Elements ps = doc.GetElementById("artContent").GetElementsByTag("p");
//等同於
//Element artContent = doc.GetElementById("artContent");
//Elements ps = artContent.GetElementsByTag("p");

元素方法的使用:

//Elements是Element元素的集合     多了個s
//Element對象的方法
Element id = doc.GetElementById("id");
//獲取或設置id元素的文本
id.Text();
//獲取或設置id元素的html代碼
id.Html();
//獲取或設置id元素的value值
id.Val();

都是像js操做html元素同樣的方法,並且方法的名字也很人性,基本上一看就會知道方法是什麼意思,方法也太多了就不一一講了。

而後咱們來使用NSoup獲取全部的名字,來試一下就會發現很簡單了:

 方式一:

public static void GetData(String address)
{
    WebClient wc = new WebClient();

    byte[] htmlData = wc.DownloadData(address);

    string html = Encoding.UTF8.GetString(htmlData);

    Document doc = NSoupClient.Parse(html);
    //先獲取id爲artContent的元素,再獲取全部的p標籤
    Elements p = doc.GetElementById("artContent").GetElementsByTag("p");

    foreach (Element item in p)
    {
        Console.WriteLine(item.Text());
    }

}

方式二:

public static void GetData(String address)
{
    //直接經過url來獲取Document對象
    Document doc = NSoupClient.Connect(address).Get();
    //先獲取id爲artContent的元素,再獲取全部的p標籤
    Elements p = doc.GetElementById("artContent").GetElementsByTag("p");

    foreach (Element item in p)
    {
        Console.WriteLine(item.Text());
    }

}

運行結果都是同樣的

總結:效率的話不太瞭解就不作評價了,就簡單說一下優缺點:使用正則表達式的話,須要對正則表達式有必定的熟悉,而後匹配數據的話也是很方便的,可是修改、添加、刪除的話就不是太方便了;使用HTMl解析器(HtmlAgilityPack、NSoup)的話操做起來明顯更方便一些,若是對js有必定的基礎,html解析器根本不須要大學習就能夠熟練使用,而後對元素進行修改、添加、刪除、獲取都是很是方便的,不過若是對於未知的html結構就不是太友好了,例如:若是獲取頁面上全部的http://www.baidu.com這類的地址的話,使用正則就會更好一些。

 

相關文章
相關標籤/搜索