您的位置:首页 > 理论基础 > 计算机网络

ASP.NET网络爬虫小研究 HtmlAgilityPack基础,爬取数据保存在数据库中再显示再自己的网页中

2018-01-26 21:15 666 查看
1、什么是网络爬虫

  关于爬虫百度百科这样定义的:网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。从搜索引擎开始,爬虫应该就出现了,爬虫所做的事情就是分析URL、下载WebServer返回的HTML、分析HTML内容、构建HTTP请求的模拟、在爬虫过程中存储有用的信息等等。简单点说,就是把别人网站上的东西爬下来,至于爬做什么用就看你自己了。

  写网络爬虫很多语言都可以写,比如众所周知的Python以及、PHP、C、Java等等。今天我就基于.Net中的HtmlAgilityPack类写一个简单的爬虫。

 

2、HtmlAgilityPack类

  HtmlAgilityPack 是 .NET 下的一个 HTML 解析类库。支持用 XPath 来解析 HTML 。命名空间: HtmlAgilityPack,下载地址:http://htmlagilitypack.codeplex.com/releases/view/90925

 

2.1基本属性

 

Attributes             获取节点的属性集合

ChildNodes            获取子节点集合(包括文本节点)

Closed              该节点是否已关闭(</xxx>)

ClosingAttributes         在关闭标签的属性集合

FirstChild             获取第一个子节点

HasAttributes           判断该节点是否含有属性

HasChildNodes          判断该节点是否含有子节点

HasClosingAttributes       判断该节点的关闭标签是否含有属性(</xxx class="xxx">)

Id                 获取该节点的Id属性

InnerHtml             获取该节点的Html代码

InnerText             获取该节点的内容,与InnerHtml不同的地方在于它会过滤掉Html代码,而InnerHtml是连Html代码一起输出

LastChild             获取最后一个子节点

Line                获取该节点的开始标签或开始代码位于整个HTML源代码的第几行(行号)

LinePosition            获取该节点位于第几列

Name               Html元素名

NextSibling            获取下一个兄弟节点

NodeType             获取该节点的节点类型

OriginalName           获取原始的未经更改的元素名

OuterHtml             整个节点的代码

OwnerDocument         节点所在的HtmlDocument文档

ParentNode            获取该节点的父节点

PreviousSibling          获取前一个兄弟节点

StreamPosition          该节点位于整个Html文档的字符位置

XPath               根据节点返回该节点的XPath

2.2方法

 

IEnumerable<HtmlNode> Ancestors();               返回此元素的所有上级节点的集合。

IEnumerable<HtmlNode> Ancestors(string name);
          返回此元素参数名字匹配的所有上级节点的集合。

IEnumerable<HtmlNode> AncestorsAndSelf();       
    返回此元素的所有上级节点和自身的集合。

IEnumerable<HtmlNode> AncestorsAndSelf(string name);
     返回此元素的名字匹配的所有上级节点和自身的集合。

HtmlNode AppendChild(HtmlNode newChild);       
      将参数元素追加到为调用元素的子元素(追加在最后)

void AppendChildren(HtmlNodeCollection newChildren);      
将参数集合中的元素追加为调用元素的子元素(追加在最后)

HtmlNode PrependChild(HtmlNode newChild);              将参数中的元素作为子元素,放在调用元素的最前面

void PrependChildren(HtmlNodeCollection newChildren);
      将参数集合中的所有元素作为子元素,放在调用元素前面

static bool CanOverlapElement(string name);
            确定是否可以保存重复的元素

IEnumerable<HtmlAttribute> ChildAttributes(string name);
    获取所有子元素的属性(参数名要与元素名匹配)

HtmlNode Clone();                         
本节点克隆到一个新的节点

HtmlNode CloneNode(bool deep);                  节点克隆到一个新的几点,参数确定是否连子元素一起克隆

HtmlNode CloneNode(string newName);               克隆的同时更改元素名

HtmlNode CloneNode(string newName, bool deep);          克隆的同时更改元素名。参数确定是否连子元素一起克隆

void CopyFrom(HtmlNode node);
e7b2
                  创建重复的节点和其下的子树。

void CopyFrom(HtmlNode node, bool deep);             创建节点的副本。

XPathNavigator CreateNavigator();                 
返回的一个对于此文档的XPathNavigator 

static HtmlNode CreateNode(string html);               静态方法,允许用字符串创建一个新节点

XPathNavigator CreateRootNavigator();               创建一个根路径的XPathNavigator 

IEnumerable<HtmlNode> DescendantNodes();           
获取所有子代节点

IEnumerable<HtmlNode> DescendantNodesAndSelf();
       获取所有的子代节点以及自身

IEnumerable<HtmlNode> Descendants();              获取枚举列表中的所有子代节点

IEnumerable<HtmlNode> Descendants(string name);
       获取枚举列表中的所有子代节点,注意元素名要与参数匹配

IEnumerable<HtmlNode> DescendantsAndSelf();
         获取枚举列表中的所有子代节点以及自身

IEnumerable<HtmlNode> DescendantsAndSelf(string name);    获取枚举列表中的所有子代节点以及自身,注意元素名要与参数匹配

HtmlNode Element(string name);                   根据参数名获取一个元素

IEnumerable<HtmlNode> Elements(string name);
         根据参数名获取匹配的元素集合

bool GetAttributeValue(string name, bool def);
           帮助方法,用来获取此节点的属性的值(布尔类型)。如果未找到该属性,则将返回默认值。

int GetAttributeValue(string name, int def);
             帮助方法,用来获取此节点的属性的值(整型)。如果未找到该属性,则将返回默认值。

string GetAttributeValue(string name, string def);
         帮助方法,用来获取此节点的属性的值(字符串类型)。如果未找到该属性,则将返回默认值。

HtmlNode InsertAfter(HtmlNode newChild, HtmlNode refChild);
    将一个节点插入到第二个参数节点的后面,与第二个参数是兄弟关系

HtmlNode InsertBefore(HtmlNode newChild, HtmlNode refChild);
  讲一个节点插入到第二个参数节点的后面,与第二个参数是兄弟关系

static bool IsCDataElement(string name);               确定是否一个元素节点是一个 CDATA 元素节点。

static bool IsClosedElement(string name);              确定是否封闭的元素节点

static bool IsEmptyElement(string name);                确定是否一个空的元素节点。

static bool IsOverlappedClosingElement(string text);
         确定是否文本对应于一个节点可以保留重叠的结束标记。

void Remove();                            从父集合中移除调用节点

void RemoveAll();                           移除调用节点的所有子节点以及属性

void RemoveAllChildren();                       移除调用节点的所有子节点

HtmlNode RemoveChild(HtmlNode oldChild);              移除调用节点的指定名字的子节点

HtmlNode RemoveChild(HtmlNode oldChild, bool keepGrandChildren);移除调用节点调用名字的子节点,第二个参数确定是否连孙子节点一起移除

HtmlNode ReplaceChild(HtmlNode newChild, HtmlNode oldChild);  
将调用节点原有的一个子节点替换为一个新的节点,第二个参数是旧节点

HtmlNodeCollection SelectNodes(string xpath);           根据XPath获取一个节点集合

HtmlNode SelectSingleNode(string xpath);              根据XPath获取唯一的一个节点

HtmlAttribute SetAttributeValue(string name, string value);
     设置调用节点的属性

string WriteContentTo();                        将该节点的所有子级都保存到一个字符串中。

void WriteContentTo(TextWriter outText);              将该节点的所有子级都保存到指定的 TextWriter。

string WriteTo();                           将当前节点保存到一个字符串中。

void WriteTo(TextWriter outText);                  将当前节点保存到指定的 TextWriter。

void WriteTo(XmlWriter writer);

 

3、第一个爬虫程序

3.1在VS2017中建立一个web项目拖个服务器控件按钮上去(我VS是用2017的)

 

 

3.2后台代码及解释

复制代码

/// <summary>

        /// 博客园精华单机按钮

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        protected void btntwo_Click(object sender, EventArgs e)

        {

            int sum = 0;

            for (int i = 1; i < 2; i++)

            {

               

                SqlDB sb = new SqlDB();

                HtmlWeb wb = new HtmlWeb();

                string webaddress= "";

                if (i==1)

                {

                    webaddress="http://www.cnblogs.com/pick/";//为啥http://www.cnblogs.com/pick/#p10进去还是第一页

                    string webbbb = GetHTML(webaddress);

                }

                else

                {

                    webaddress = string.Format("http://www.cnblogs.com/pick/{0}", ("#p"+i.ToString()).ToString());

                    string webbbb = GetHTML(webaddress);

                }

                try

                {

                    HtmlDocument doc = wb.Load(webaddress);

               

                HtmlNode node = doc.GetElementbyId("post_list");

                if (node != null)

                {

                    foreach (HtmlNode hnode in node.ChildNodes)

                    {

                        if (hnode.Attributes["class"] == null || hnode.Attributes["class"].Value != "post_item")

                            continue;

                        HtmlNode hn = HtmlNode.CreateNode(hnode.OuterHtml);

                        //推荐

                        int recommend = Convert.ToInt32((hn.SelectSingleNode("//*[@class=\"diggnum\"]").InnerText).Trim());

                        //标题

                        string title = hn.SelectSingleNode("//*[@class=\"titlelnk\"]").InnerText;

                        //网址

                        string webhref = hn.SelectSingleNode("//*[@class=\"titlelnk\"]").Attributes["href"].Value.ToString();

                        //介绍

                        string introduce = hn.SelectSingleNode("//*[@class=\"post_item_summary\"]").InnerText;

                        string articletimetest = hn.SelectSingleNode("//*[@class=\"post_item_foot\"]").InnerText;

                            //发表时间(陈树义  发布于 2017 - 11 - 15 10:13  评论(41)阅读(7372)

                            string articletime = ((hn.SelectSingleNode("//*[@class=\"post_item_foot\"]").InnerText).Trim()).Replace("\r\n", "+");

                        //分割字符串

                        string[] st = articletime.Split('+');

                        //取出(发布于 2017 - 11 - 15 10:13)

                        string pp = (st[1].ToString()).Trim();

                        //分割字符串

                        string[] qq = pp.Split(' ');

                        //取出(2017/11/15 10 :13)

                        DateTime gg = Convert.ToDateTime(qq[1].ToString() + " " + qq[2].ToString());

                        try

                        {

                            string sql = string.Format(@"insert into CnblogsList( Recommend, Title,Contents, Introduce, WebHref, ArticleTime) values({0},'{1}','{2}','{3}','{4}','{5}')", recommend, title, GetContentsString(webhref), introduce, webhref, gg);

                            sb.ExecuteNonQuery(sql);

                            sum++;

                        }

                        catch (www.dfgjpt.com Exception ex)

                        {

                            Response.Write(ex.Message);

                        }

                            Response.Write(GetContentsString(webhref)+"<hr /> <hr />");

                        // 陈树义  发布于 2017 - 11 - 15 10:13  评论(41)阅读(7372)

                        Response.Write("推荐:" + (hn.SelectSingleNode("//*[@class=\"diggnum\"]").InnerText)+"<br />");

                         Response.Write("标题:" + (hn.SelectSingleNode("//*[@class=\"titlelnk\"]").InnerText) + "<br />");

                        Response.Write("标题对应的网址:" + (hn.SelectSingleNode("//*[@class=\"titlelnk\"]").Attributes["href"].Value.ToString()) + "<br />");

                         Response.Write("介绍:" + (hn.SelectSingleNode("//*[@class=\"post_item_summary\"]").InnerText) + "<br />");

                         Response.Write("时间:" + (hn.SelectSingleNode("//*[@class=\"post_item_foot\"]").InnerText) + "<br /><hr />");

                    }

                }

                else

                {

                    Response.Write("节点为空  +++++  出错节点Iiiii是:" + i.ToString() + "<br />  网址:" + webaddress.ToString() + "<br />  插入数据:"+ sum +"条");

                    return;

                }

                }

                catch (Exception esz)

                {

                    Response.Write(esz.Message);

                }

            }

        }

复制代码

 

这是获取网页源码的代码

复制代码

/// <summary>

        /// 获取网页源码

        /// </summary>

        /// <param name="url"></param>

        /// <returns></returns>

        public string GetHTML(string url)

        {

            WebClient web = new WebClient(www.qwj127.com   );

            web.Encoding = Encoding.UTF8;

            string  buffer = web.DownloadString(url);

            return buffer;

        }

复制代码

 

上面的for循环目的是获取精华区后面页数的内容,但是效果并不是这样的

 

 

 

 

我早谷歌上F12调试发现并不是这样的额  请求地址不对。为以为在后面加?PageIndex= XX就可以实现  还是不可以 因为这是经过处理的,在Header上面有地址https://www.cnblogs.com/mvc/AggSite/PostList.aspx你们仔细就可以看到。这样做了如果页数写多了就会重复出现第一页的内容 数据库中是保存的  数据库的表结构我上图

 

 

我一弄才发现原来这个地址是博客园里面的内容时刻更新的。经过处理取出精华区的。一次去可以取出2天的内容  不管是发布在博客园首页的还是没有发布在首页的都有。我就爬虫爬了一次 试试看 这是第二个按钮的源码

复制代码

 /// <summary>

        /// 博客园数据最近大约2天

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        protected void BtnNowTowDay_Click(object sender, EventArgs e)

        {

            int sum = 0;

            for (int i = 1; i < 200; i++)

            {

                //这是SqlDB类

                SqlDB sb = new SqlDB();

                //实例HtmlWdb

                HtmlWeb wb = new HtmlWeb();

                //网址

                string webaddress = "";

                    webaddress = string.Format("https://www.cnblogs.com/mvc/AggSite/PostList.aspx?PageIndex={0}", + i);

                //网页源码 有html的

                    string webbbb = GetHTML(webaddress);

                try

                {

                    HtmlDocument doc = wb.Load(webaddress);

                    //获取div[@class='post_item的上级目录

                    //这个可以根据节点 ID选择 建议多看一下Xpath 就好理解了

                    HtmlNode node = doc.DocumentNode.SelectSingleNode("//div[@class='post_item']").SelectSingleNode("..");

                    //HtmlNode node = doc.GetElementbyId("#id");

                    

                    if (node != null)

                    {

                        foreach (HtmlNode hnode in node.ChildNodes)

                        {

                            if (hnode.Attributes["class"] == null || hnode.Attributes["class"].Value != "post_item")

                                continue;

                            HtmlNode hn = HtmlNode.CreateNode(hnode.OuterHtml);

                            //推荐

                            int recommend = Convert.ToInt32((hn.SelectSingleNode("//*[@class=\"diggnum\"]").InnerText).Trim());

                            //标题

                            string title = hn.SelectSingleNode("//*[@class=\"titlelnk\"]").InnerText;

                            //网址

                            string webhref = hn.SelectSingleNode("//*[@class=\"titlelnk\"]").Attributes["href"].Value.ToString();

                            //介绍

                            string introduce = hn.SelectSingleNode("//*[@class=\"post_item_summary\"]").InnerText;

                            string articletimetest = hn.SelectSingleNode("//*[@class=\"post_item_foot\"]").InnerText;

                            //发表时间(陈树义  发布于 2017 - 11 - 15 10:13  评论(41)阅读(7372)

                            string articletime = ((hn.SelectSingleNode("//*[@class=\"post_item_foot\"]").InnerText).Trim()).Replace("\r\n", "+");

                            //分割字符串

                            string[] st = articletime.Split('www.huange157.com +');

                            //取出(发布于 2017 - 11 - 15 10:13)

                            string pp = (st[1].ToString()).Trim(www.huayu521.com  );

                            //分割字符串

                            string[] qq = pp.Split(' ');

                            //取出(2017/11/15 10 :13)

                            DateTime gg = Convert.ToDateTime(qq[1].ToString() + " " + qq[2].ToString());

                            try

                            {

                                string sql = string.Format(@"insert into CnblogsList( Recommend, Title,Contents, Introduce, WebHref, ArticleTime) values({0},'{1}','{2}','{3}','{4}','{5}')", recommend, title, GetContentsString(webhref), introduce, webhref, gg);

                                sb.ExecuteNonQuery(sql);

                                sum++;

                            }

                            catch (Exception ex)

                            {

                                Response.Write(ex.Message);

                            }

                        }

                    }

                    else

                    {

                        Response.Write("节点为空  www.huayuyulee.cn+++++  出错节点Iiiii是:" + i.ToString() + "<br />  网址:" + webaddress.ToString() + "<br />  插入数据:" + sum + "条");

                        return;

                    }

                }

                catch (Exception esz)

                {

                    Response.Write(esz.Message);

                }

            }

        }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐