zoukankan      html  css  js  c++  java
  • 非常经典的网络蜘蛛示例

    以前写了篇“百度视频采集"的思路简介,看到唯一一个人留言希望我总结一下新闻采集。今天就拿博客园的热门文章采集做个例子。说明前我得声明一点,经过在 博客园混了几个月后,发现博客园首页发布的文章一般都是高手,很有参考价值。可我是一个新手,我请大家此文章的任何质疑直接留言,因为您发现问题不说出 来,可能我永远会认为自己写的是正确的。
          下面进入正题。首先需要注意的是采集网页上数据的唯一方式是必须获取需要采 集页面的源代码,这点想必大家很清楚。因为我们不知道对方网站的数据库服务器连接方式,我们只能在页面的源代码中找寻我们想要的东西。 这无疑就是对大量字符串进行处理,那么我们如何处理这些含有大量html标记与内容的代码呢?可能解决问题的方式有很多种,但我认为用正 则表达式来解决这个问题会很好。
          通过上面的话,我谈到了两个知识点,我们来总结一下流程。
          1.获取需要采集页面的源代码。
          2.利用正则表达式处理这些代码中我们想要的内容。
          下面做一些准备工作,写一个实体类存储文章的信息。例如:标题、作者、发布时间、浏览次数,等。

    using System;
    using System.Collections.Generic;
    using System.Text;

    namespace Plug.Article.Entity
    {
        
    /// <summary>
        
    /// 采集文章信息,部分属性可留空。标题与地址如为空则默认赋值时引发异常
        
    /// </summary>

        [Serializable]
        
    public class Article
        
    {
            
    private string category;

            
    /// <summary>
            
    /// 文章类别
            
    /// </summary>

            public string Category
            
    {
                
    get return category; }
                
    set { category = value; }
            }

            
    private string url;
            
    /// <summary>
            
    /// 文章连接地址
            
    /// </summary>

            public string Url
            
    {
                
    get
                
    {
                    
    return url;
                }

                
    set
                
    {
                    
    if (value == "" || value.Length <= 0)
                    
    {
                        
    throw new ApplicationException("文章的连接地址不能为空!");
                    }

                    url 
    = value;
                }

            }

            
    private string title;
            
    /// <summary>
            
    /// 文章标题
            
    /// </summary>

            public string Title
            
    {
                
    get
                
    {
                    
    return title;
                }

                
    set
                
    {
                    
    if (value == "" || value.Length <= 0)
                    
    {
                        
    throw new ApplicationException("文章的标题不能为空!");
                    }

                    title 
    = value;
                }

            }

            
    private int views;
            
    /// <summary>
            
    /// 文章浏览次数
            
    /// </summary>

            public int Views
            
    {
                
    get
                
    {
                    
    return views;
                }

                
    set
                
    {
                    views 
    = value;
                }

            }

            
    private int replys;
            
    /// <summary>
            
    /// 文章评论次数
            
    /// </summary>

            public int Replys
            
    {
                
    get
                
    {
                    
    return replys;
                }

                
    set
                
    {
                    replys 
    = value;
                }

            }

            
    private string datatime;
            
    /// <summary>
            
    /// 文章发布日期
            
    /// </summary>

            public string Datatime
            
    {
                
    get
                
    {
                    
    return datatime;
                }

                
    set
                
    {
                    datatime 
    = value;
                }

            }

            
    private string author;
            
    /// <summary>
            
    /// 文章作者
            
    /// </summary>

            public string Author
            
    {
                
    get
                
    {
                    
    return author;
                }

                
    set
                
    {
                    author 
    = value;
                }

            }

            
    private string site;
            
    /// <summary>
            
    /// 文章作者网站、文章采集网站
            
    /// </summary>

            public string Site
            
    {
                
    get
                
    {
                    
    return site;
                }

                
    set
                
    {
                    site 
    = value;
                }

            }

        }

    }


          获取采集网页源代码的方式,也很简单,我单独做成了一个类。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Net;

    namespace Plug.Article
    {
        
    /// <summary>
        
    /// 网页操作类
        
    /// </summary>

        public class HTML
        
    {
            
    /// <summary>
            
    /// 获取网页源代码
            
    /// </summary>
            
    /// <param name="url">URL路径</param>
            
    /// <returns></returns>

            public string GetHTML(string url)
            
    {
                WebClient web 
    = new WebClient();
                
    byte[] buffer = web.DownloadData(url);
                
    return Encoding.Default.GetString(buffer);
            }

        }

    }
          拿到源代码,该进入关键步骤了,写正则表达式采集数据。在采集之前我们需要了解网页源代码的特征,如果都不知道我们想要什么,恐怕无法写出正则表达式。我 们要采集的页面是 http://www.cnblogs.com/TopPosts.aspx 这个页面,博客园文章阅读排行榜。今日阅读排行、 昨日阅读排行 等信息。但我们要得到的只是如下信息:

    · 我在外资公司的2个月 (阅读:1909) (评 论:21) (2008-6-25 13:44) yesry
    · 为什么尽量避免使用触发器? (阅 读:1490) (评论:15) (2008-6-25 03:35) 凉面
    · Discuz!NT 系统架构分析 (阅 读:1391) (评论:18) (2008-6-25 12:35) 韩龙
    · 硬盘那点事儿 (阅读:1342) (评 论:15) (2008-6-25 11:16) 李战

    只 需要得到标题、阅读次数、评论、时间、作者即可。那么我们就来分析一下关键信息的源代码特征。

            <tr>
                
    <td style="80%">
                    · 
    <id="ctl00_cphMain_TopPostsPaged1_PostsRepeater_ctl01_lnkTitle" href="http://www.cnblogs.com/yesry/archive/2008/06/25/1229587.html" target="_blank">我在外资公司的2个月</a>&nbsp;<span class="title">(阅读:1909) (评论:21) (2008-6-25 13:44)</span>

                
    </td>
                
    <td height="20">
                    
    <id="ctl00_cphMain_TopPostsPaged1_PostsRepeater_ctl01_lnkAuthor" href="http://yesry.cnblogs.com/">yesry</a>
                
    </td>
            
    </tr>

    这就是我们需要采集信息的源代码。在开始写正则表达式之前我需要说明一点,我们都知道,这些 内容也是动态产生的。所以它们的格式肯定是固定的。这样我们就可以利用一个正则表达式正确的采集到该页面所有信息。我觉得没必要在这片文章中详细解释正则 表达式的含义,因为这需要多练习。
    Regex regexarticles = new Regex(".+· <a\\s+id=\".+\" href=\"(?<url>.+)\"\\s+target=\"_blank\">(?<title>.+)</a>&nbsp;<span\\s+class=\".+\">\\(阅读: (?<views>\\d+)\\).*\\(评论:(?<reply>\\d+)\\).* \\((?<time>.+)\\)</span>\\s*</td>\\s*<td\\s+height=\"\\d+\">\\s+<a\\s+id=\".+\" href=\"(?<blog>.+)\">(?<author>.+)</a>");

    这些让您可能阅读起来很吃力,但我想学过正则表达式的人会嘲笑我,因为我的正则写 的不够灵活。我要为没有接触过正则表达式的朋友简单介绍下,我也只是刚入门。正则表 达式就是通过描述字符串的特征来进行匹配。这也是我们为什么需要分析页面源代码的原因。至于怎么去匹配,其实也不难,我提供一些文章给各位 参考。
    正则表达式学习笔记:
    http://hedong.3322.org/archives/000244.html
    正 则表达式30分钟入门:http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng- se.htm

    我就是通过这两篇文章入门,并利用正则表达式写出了我喜欢的程序。至于更多的文章可以去网络寻找。

    上面说到 的是关键的正则表达式,下面还需要说一下怎么去取。


                //网页操作对象,我用来获取网页源码
                HTML html = new HTML();

                
    //对博客园每日排行数据进行采集
                string htmlcode = html.GetHTML("http://www.cnblogs.com/TopPosts.aspx","utf-8");

                
    //提取博客园排行文章信息的正则表达式
                Regex regexarticles = new Regex(".+· <a\\s+id=\".+\" href=\"(?<url>.+)\"\\s+target=\"_blank\">(?<title>.+)</a>&nbsp;<span\\s+class=\".+\">\\(阅读: (?<views>\\d+)\\).*\\(评论:(?<reply>\\d+)\\).* \\((?<time>.+)\\)</span>\\s*</td>\\s*<td\\s+height=\"\\d+\">\\s+<a\\s+id=\".+\" href=\"(?<blog>.+)\">(?<author>.+)</a>");

                
    //所有匹配表达式的内容
                MatchCollection marticles = regexarticles.Matches(htmlcode);   
     
                
    ///遍历匹配内容
                foreach (Match m in marticles)
                
    {
                    Entity.Article test 
    = new Entity.Article();
                    test.Category 
    = "博客园热门文章";           //设置分类
                    test.Title = m.Groups["title"].Value;       //设置标题
                    test.Url = m.Groups["url"].Value;           //设置连接
                    test.Views = int.Parse(m.Groups["views"].Value);    //设置浏览次数
                    test.Replys = int.Parse(m.Groups["reply"].Value);  //设置评论次数
                    test.Datatime = m.Groups["time"].Value;             //设置发布时间
                    test.Author = m.Groups["author"].Value;             //设置作者
                    test.Site = m.Groups["blog"].Value;                 //设置文章出处
                    list.Add(test);
                }

          MatchCollection marticles = regexarticles.Matches(htmlcode);
          通过此句代码获取多个匹配的内容。
          foreach (Match m in marticles)
          循环时需要用Match类取一条匹配内容,m.Groups["title"].Value  取出指定分组中的信息,这个分组是指(?<title>.+) ,“?<title>”这就是给匹配内容分组为title的代码。代码就是这样了,没有什么技术含量,来总结一 下做采集的一个流程吧。
          1.取指定页面的源代码
          2.分析源代码中我们想要获得内容的特征
          3.通过特征写出正则表达式进行匹配
          4.遍历匹配内容装入集合

          流程就是这样,我把整个案例的代码打包供大家参考,如有什么问题请留言。
         
    源码下载
          采集出的数据可能与博客园显示顺序不太一致,因为是整个页面的文章,没有做分类处理。但数据绝对是一致的。
  • 相关阅读:
    添加yum源
    tar命令
    tomcat压力测试、优化
    vi命令
    Linux简单命令
    Linux简单命令
    vi命令
    tomcat压力测试、优化
    tar命令
    动态加载 CSS 文件
  • 原文地址:https://www.cnblogs.com/top5/p/1671703.html
Copyright © 2011-2022 走看看