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这类的地址的话,使用正则就会更好一些。

 

相关文章
相关标签/搜索