C#采集CSDN单个博客所有文章

本文介绍了使用C#语言通过HtmlAgilityPack库解析HTML,实现采集CSDN个人博客所有文章的步骤。首先,从博客首页获取总页数;接着,构造每一页的文章URL进行循环遍历;最后,详细阐述如何获取单篇文章的内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原理:

通过HtmlAgilityPack解析html源码得到所需的数据。

1、首先通过http://blog.csdn.net/gdjlc 底部的“xx条数据 共xx页”,获取得总页数;

2、获取每一页的所有文章URL,每一页的URL如下所示: http://blog.csdn.net/gdjlc/article/list/当前页索引,从1一直循环到总页数即可得.

3、获取单个文章的内容。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Net;
using HtmlAgilityPack;

namespace Demo
{
    public partial class FrmCSDN : Form
    {       
        const string BLOGUSER = "gdjlc"; //博客用户名
        const string BLOGURL = "http://blog.csdn.net";
        const string PAGECOUNTPATH = "//div[@id='papelist']/span[1]";//总页数PATH
        const string ARTICLEURLPATH = "//span[@class='link_title']/a[1]"; //文章URL的PATH    
        const string ARTICLETITLEPATH = "//div[@class='article_title']/h3/span/a";//文章标题PATH
        const string POSTDATEPATH = "//span[@class='link_postdate']"; //文章创建日期PATH
        const string ARTICLECONTENTPATH = "//div[@id='article_content']"; //文章内容PATH
        List<string> articleUrlList = new List<string>(); //所有文章的URL
        private object moniter = new object();
        Stopwatch stopwatch = new Stopwatch();
        int cnt = 0;

        public FrmCSDN()
        {
            InitializeComponent();
        }

        //获取总页数
        private int GetPageCount(string pageCountUrl)
        {         
            HtmlNode rootNode = GetHtmlNodeByUrl(pageCountUrl, Encoding.UTF8);
            if (rootNode == null)
                return 0;            
            //形如“177条数据 共12页”
            string pageCountText = GetNodeInnerText(rootNode, PAGECOUNTPATH);
            int firstIndex = pageCountText.LastIndexOf("共") + 1;
            int lastIndex = pageCountText.LastIndexOf("页");
            string result = pageCountText.Substring(firstIndex, lastIndex - firstIndex);
            return Convert.ToInt32(result);
        }
        //开始采集按钮
        private void btnCollect_Click(object sender, EventArgs e)
        {
            stopwatch.Restart();         
            Task.Factory.StartNew(() =>
            {
                cnt = 0;
                int pageCount = GetPageCount(BLOGURL + "/" + BLOGUSER);
                if (pageCount == 0) 
                    return;
                
                //所有文章的URL
                for (int pageIndex = 1; pageIndex <= pageCount; pageIndex++)
                {
                    string pageIndexUrl = BLOGURL + "/" + BLOGUSER + "/article/list/" + pageIndex.ToString();
                    HtmlNode rootNode = GetHtmlNodeByUrl(pageIndexUrl, Encoding.UTF8);
                    if (rootNode == null)
                        continue;

                    HtmlNodeCollection ArticleUrlList = rootNode.SelectNodes(ARTICLEURLPATH);
                    foreach (HtmlNode articleUrlNode in ArticleUrlList)
                    {
                        string articleUrl = BLOGURL + articleUrlNode.Attributes["href"].Value;
                        articleUrlList.Add(articleUrl);
                    }
                }
            }).ContinueWith((x) =>
            {
                TaskFactory taskFactory = new TaskFactory();
                Task[] tasks = new Task[articleUrlList.Count];
                for (int i = 0; i < articleUrlList.Count; i++)
                {
                    tasks[i] = new Task(CollectArticle, articleUrlList[i]);
                    tasks[i].Start();
                }
                taskFactory.ContinueWhenAll(tasks, TaskEnded, TaskContinuationOptions.None);
            });
        }
        /// <summary>
        /// 单篇文章采集
        /// </summary>
        /// <param name="state"></param>
        void CollectArticle(object state)
        {
            Interlocked.Increment(ref cnt);
            lock (moniter)
            {
                SetStatuText(string.Format("总共{0}篇文章, 正在采集中第{1}篇.", articleUrlList.Count, cnt));
                 string articleUrl = (string)state;
                 string firstArticleHtml = GetHtmlSource(articleUrl, Encoding.UTF8);
                 if (string.IsNullOrEmpty(firstArticleHtml)) return;
                 HtmlNode rootNode = GetHtmlNodeByHtml(firstArticleHtml);
                 string articleTitle = GetNodeInnerText(rootNode, ARTICLETITLEPATH);
                 string postDate = GetNodeInnerText(rootNode, POSTDATEPATH);
                 string articleContent = GetNodeInnerText(rootNode, ARTICLECONTENTPATH);
                 //采集结果处理:保存到数据库或其它......
                 string blogFile = BLOGUSER + ".txt";
                 using (StreamWriter sw = new StreamWriter(blogFile, true))
                 {
                     sw.WriteLine(articleUrl);
                     sw.WriteLine(articleTitle);
                     sw.WriteLine(postDate);
                     sw.WriteLine(articleContent);
                 }         
            }                     
        }
        
        private void TaskEnded(Task[] task)
        {
            SetStatuText("采集结束,耗时 " + stopwatch.Elapsed.Minutes + "分" + stopwatch.Elapsed.Seconds + "秒");
        }
        //通过网页URL获取HtmlNode
        private HtmlNode GetHtmlNodeByUrl(string url, Encoding encoding)
        {
            string html = GetHtmlSource(url, encoding);
            if (string.IsNullOrEmpty(html)) return null;

            HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
            document.LoadHtml(html);
            HtmlNode rootNode = document.DocumentNode;
            return rootNode;
        }
        //通过网页html源代码获取HtmlNode
        private HtmlNode GetHtmlNodeByHtml(string htmlSource)
        {
            HtmlAgilityPack.HtmlDocument document = new HtmlAgilityPack.HtmlDocument();
            document.LoadHtml(htmlSource);
            HtmlNode rootNode = document.DocumentNode;
            return rootNode;
        }
        /// <summary>
        /// 获取网页源代码
        /// </summary>      
        private string GetHtmlSource(string url, Encoding encoding)
        {
            string result = "";
            try
            {
                WebRequest request = WebRequest.Create(url);
                using (WebResponse response = request.GetResponse())               
                    using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding))                   
                        result = reader.ReadToEnd(); 
            }
            catch
            {
                result = "";
            }
            return result;
        }
        private string GetNodeInnerText(HtmlNode srcNode, string path)
        {
            HtmlNode temp = srcNode.SelectSingleNode(path);
            if (temp == null)
                return null;
            return temp.InnerText;
        }
        private void SetStatuText(string s)
        {
            this.SafeCall(() =>
            {
                lblStatusInfo.Text = s;
            });
        }         
    }
    public static class Extenstions
    {
        public static void SafeCall(this Control ctrl, Action callback)
        {
            if (ctrl.InvokeRequired)
                ctrl.Invoke(callback);
            else
                callback();
        }
    }
}


预览图片见:http://www.cnblogs.com/xxpyeippx/archive/2008/03/31/1131211.html运行环境windows nt/xp/2003 or above.net Framework 1.1SqlServer 2000 开发环境 VS 2003目的学习了网络编程,总要做点什么东西才好。于是想到要做一个网页内容采集器。作者主页: http://www.fltek.com.cn使用方式测试数据采用自cnBlog。见下图用户首先填写“起始网页”,即从哪一页开始采集。然后填写数据库连接字符串,这里是定义了采集到的数据插入到哪个数据库,后面选择表名,不必说了。网页编码,不出意外的话,中国大陆都可以采用UTF-8爬取文件名的正则:呵呵 这个工具明显是给编程人员用的。正则都要直接填写啦。比如说cnblogs的都是数字的,所以写了\d建表帮助:用户指定要建立几个varchar型的,几个text型的,主要是放短数据和长数据啊。如果你的表里本来就有列,那就免啦。程序里面没有做验证哦。网页设置里面:采集内容前后标记:比如说都有 xxx,如果我要采集xxx就写“到”,意思,当然就是到之间的内容啦。后面的几个文本框是显示内容的。点击“获取URL”可以查看它捕获的Url对不对的。点击“采集”,可以把采集内容放到数据库,然后就用 Insert xx () (select xx) 可以直接插入目标数据了。程序代码量非常小(也非常简陋),需要的改动一下啦。不足 应用到了正则表达式、网络编程由于是最简单的东西,所以没有用多线程,没有用其他的优化方法,不支持分页。测试了一下,获取38条数据,用了700M内存啊。。。。如果有用的人 ,可以改一下使用啦。方便程序员用,免写很多代码。Surance Yin@ Surance Center 转载请注明出处
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值