博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
网络爬虫+HtmlAgilityPack+windows服务从博客园爬取20万博文
阅读量:5886 次
发布时间:2019-06-19

本文共 10115 字,大约阅读时间需要 33 分钟。

 

1.前言

最新在公司做一个项目,需要一些文章类的数据,当时就想到了用网络爬虫去一些技术性的网站爬一些,当然我经常去的就是博客园,于是就有下面的这篇文章。

2.准备工作

我需要把我从博客园爬取的数据,保存起来,最好的方式当然是保存到数据库中去了,好了我们先建一个数据库,在来一张表,保存我们的数据,其实都很简单的了啊,如下图所示

BlogArticleId博文自增ID,BlogTitle博文标题,BlogUrl博文地址,BlogAuthor博文作者,BlogTime博文发布时间,BlogMotto作者座右铭,BlogDepth蜘蛛爬虫爬取的深度,IsDeleted是否删除。

数据库表也创建好了,我们先来一个数据库的帮助类。

///     /// 数据库帮助类    ///     public class MssqlHelper    {        #region 字段属性        ///         /// 数据库连接字符串        ///         private static string conn = "Data Source=.;Initial Catalog=Cnblogs;User ID=sa;Password=123";        #endregion        #region DataTable写入数据        public static void GetData(string title, string url, string author, string time, string motto, string depth, DataTable dt)        {            DataRow dr;            dr = dt.NewRow();            dr["BlogTitle"] = title;            dr["BlogUrl"] = url;            dr["BlogAuthor"] = author;            dr["BlogTime"] = time;            dr["BlogMotto"] = motto;            dr["BlogDepth"] = depth;            //2.0 将dr追加到dt中            dt.Rows.Add(dr);        }        #endregion        #region 插入数据到数据库        ///         /// 插入数据到数据库        ///         public static void InsertDb(DataTable dt)        {            try            {                using (System.Data.SqlClient.SqlBulkCopy copy = new System.Data.SqlClient.SqlBulkCopy(conn))                {                    //3.0.1 指定数据插入目标表名称                    copy.DestinationTableName = "BlogArticle";                    //3.0.2 告诉SqlBulkCopy对象 内存表中的 OrderNO1和Userid1插入到OrderInfos表中的哪些列中                    copy.ColumnMappings.Add("BlogTitle", "BlogTitle");                    copy.ColumnMappings.Add("BlogUrl", "BlogUrl");                    copy.ColumnMappings.Add("BlogAuthor", "BlogAuthor");                    copy.ColumnMappings.Add("BlogTime", "BlogTime");                    copy.ColumnMappings.Add("BlogMotto", "BlogMotto");                    copy.ColumnMappings.Add("BlogDepth", "BlogDepth");                    //3.0.3 将内存表dt中的数据一次性批量插入到OrderInfos表中                    copy.WriteToServer(dt);                    dt.Rows.Clear();                }            }            catch (Exception)            {                dt.Rows.Clear();            }        }        #endregion    }

3.日志

来个日志,方便我们查看,代码如下。

///     /// 日志帮助类    ///     public class LogHelper    {        #region 写入日志        //写入日志        public static void WriteLog(string text)        {            //StreamWriter sw = new StreamWriter(AppDomain.CurrentDomain.BaseDirectory + "\\log.txt", true);            StreamWriter sw = new StreamWriter("F:" + "\\log.txt", true);            sw.WriteLine(text);            sw.Close();//写入        }        #endregion    }

4.爬虫

我的网络蜘蛛爬虫,用的一个第三方类库,代码如下。

 
AddUrlEventArgs.cs
 
BloomFilter.cs
 
CrawlErrorEventArgs.cs
 
CrawlExtension.cs
 
CrawlMaster.cs
 
CrawlSettings.cs
 
CrawlStatus.cs
 
DataReceivedEventArgs.cs
 
SecurityQueue.cs
 
UrlInfo.cs
 
UrlQueue.cs

5.创建windows服务.

这些工作都准备完成后,终于要来我们的重点了,我们都知道控制台程序非常不稳定,而我们的这个从博客园上面爬取文章的这个事情需要长期的进行下去,这个需要 很稳定的进行下去,所以我想起了windows服务,创建好我们的windows服务,代码如下。

using Feng.SimpleCrawler;using Feng.DbHelper;using Feng.Log;using HtmlAgilityPack;namespace Feng.Demo{    ///     /// windows服务    ///     partial class FengCnblogsService : ServiceBase    {        #region 构造函数        ///         /// 构造函数        ///         public FengCnblogsService()        {            InitializeComponent();        }         #endregion        #region 字段属性        ///         /// 蜘蛛爬虫的设置        ///         private static readonly CrawlSettings Settings = new CrawlSettings();        ///         /// 临时内存表存储数据        ///         private static DataTable dt = new DataTable();        ///         /// 关于 Filter URL:http://www.cnblogs.com/heaad/archive/2011/01/02/1924195.html        ///         private static BloomFilter
filter; #endregion #region 启动服务 ///
/// TODO: 在此处添加代码以启动服务。 /// ///
protected override void OnStart(string[] args) { ProcessStart(); } #endregion #region 停止服务 ///
/// TODO: 在此处添加代码以执行停止服务所需的关闭操作。 /// protected override void OnStop() { } #endregion #region 程序开始处理 ///
/// 程序开始处理 /// private void ProcessStart() { dt.Columns.Add("BlogTitle", typeof(string)); dt.Columns.Add("BlogUrl", typeof(string)); dt.Columns.Add("BlogAuthor", typeof(string)); dt.Columns.Add("BlogTime", typeof(string)); dt.Columns.Add("BlogMotto", typeof(string)); dt.Columns.Add("BlogDepth", typeof(string)); filter = new BloomFilter
(200000); const string CityName = ""; #region 设置种子地址 // 设置种子地址 Settings.SeedsAddress.Add(string.Format("http://www.cnblogs.com/{0}", CityName)); Settings.SeedsAddress.Add("http://www.cnblogs.com/artech"); Settings.SeedsAddress.Add("http://www.cnblogs.com/wuhuacong/"); Settings.SeedsAddress.Add("http://www.cnblogs.com/dudu/"); Settings.SeedsAddress.Add("http://www.cnblogs.com/guomingfeng/"); Settings.SeedsAddress.Add("http://www.cnblogs.com/daxnet/"); Settings.SeedsAddress.Add("http://www.cnblogs.com/fenglingyi"); Settings.SeedsAddress.Add("http://www.cnblogs.com/ahthw/"); Settings.SeedsAddress.Add("http://www.cnblogs.com/wangweimutou/"); #endregion #region 设置 URL 关键字 Settings.HrefKeywords.Add("a/"); Settings.HrefKeywords.Add("b/"); Settings.HrefKeywords.Add("c/"); Settings.HrefKeywords.Add("d/"); Settings.HrefKeywords.Add("e/"); Settings.HrefKeywords.Add("f/"); Settings.HrefKeywords.Add("g/"); Settings.HrefKeywords.Add("h/"); Settings.HrefKeywords.Add("i/"); Settings.HrefKeywords.Add("j/"); Settings.HrefKeywords.Add("k/"); Settings.HrefKeywords.Add("l/"); Settings.HrefKeywords.Add("m/"); Settings.HrefKeywords.Add("n/"); Settings.HrefKeywords.Add("o/"); Settings.HrefKeywords.Add("p/"); Settings.HrefKeywords.Add("q/"); Settings.HrefKeywords.Add("r/"); Settings.HrefKeywords.Add("s/"); Settings.HrefKeywords.Add("t/"); Settings.HrefKeywords.Add("u/"); Settings.HrefKeywords.Add("v/"); Settings.HrefKeywords.Add("w/"); Settings.HrefKeywords.Add("x/"); Settings.HrefKeywords.Add("y/"); Settings.HrefKeywords.Add("z/"); #endregion // 设置爬取线程个数 Settings.ThreadCount = 1; // 设置爬取深度 Settings.Depth = 55; // 设置爬取时忽略的 Link,通过后缀名的方式,可以添加多个 Settings.EscapeLinks.Add("http://www.oschina.net/"); // 设置自动限速,1~5 秒随机间隔的自动限速 Settings.AutoSpeedLimit = false; // 设置都是锁定域名,去除二级域名后,判断域名是否相等,相等则认为是同一个站点 Settings.LockHost = false; Settings.RegularFilterExpressions.Add(@"http://([w]{3}.)+[cnblogs]+.com/"); var master = new CrawlMaster(Settings); master.AddUrlEvent += MasterAddUrlEvent; master.DataReceivedEvent += MasterDataReceivedEvent; master.Crawl(); } #endregion #region 打印Url ///
/// The master add url event. /// ///
/// The args. /// ///
/// The
. ///
private static bool MasterAddUrlEvent(AddUrlEventArgs args) { if (!filter.Contains(args.Url)) { filter.Add(args.Url); Console.WriteLine(args.Url); if (dt.Rows.Count > 200) { MssqlHelper.InsertDb(dt); dt.Rows.Clear(); } return true; } return false; // 返回 false 代表:不添加到队列中 } #endregion #region 解析HTML ///
/// The master data received event. /// ///
/// The args. /// private static void MasterDataReceivedEvent(SimpleCrawler.DataReceivedEventArgs args) { // 在此处解析页面,可以用类似于 HtmlAgilityPack(页面解析组件)的东东、也可以用正则表达式、还可以自己进行字符串分析 HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(args.Html); HtmlNode node = doc.DocumentNode.SelectSingleNode("//title"); string title = node.InnerText; HtmlNode node2 = doc.DocumentNode.SelectSingleNode("//*[@id='post-date']"); string time = node2.InnerText; HtmlNode node3 = doc.DocumentNode.SelectSingleNode("//*[@id='topics']/div/div[3]/a[1]"); string author = node3.InnerText; HtmlNode node6 = doc.DocumentNode.SelectSingleNode("//*[@id='blogTitle']/h2"); string motto = node6.InnerText; MssqlHelper.GetData(title, args.Url, author, time, motto, args.Depth.ToString(), dt); LogHelper.WriteLog(title); LogHelper.WriteLog(args.Url); LogHelper.WriteLog(author); LogHelper.WriteLog(time); LogHelper.WriteLog(motto == "" ? "null" : motto); LogHelper.WriteLog(args.Depth + "&dt.Rows.Count=" + dt.Rows.Count); //每次超过100条数据就存入数据库,可以根据自己的情况设置数量 if (dt.Rows.Count > 100) { MssqlHelper.InsertDb(dt); dt.Rows.Clear(); } } #endregion }}

这里我们用爬虫从博客园爬取来了博文,我们需要用这个HtmlAgilityPack第三方工具来解析出我们需要的字段,博文标题,博文作者,博文URL,等等一些信息。同时我们可以设置服务的一些信息

在网络爬虫中,我们要设置一些参数,设置种子地址,URL关键字,还有爬取的深度等等,这些工作都完成后,我们就只需要安装我们的windows服务,就大功告成了。嘿嘿...

 6.0安装windows服务

在这里我们采用vs自带的工具来安装windows服务。

安装成功后,打开我们的windows服务就可以看到我们安装的windows服务。

同时可以查看我们的日志文件,查看我们爬取的博文解析出来的信息。如下图所示。

这个时候去查看我们的数据库,我的这个服务已经运行了一天。。。

转载:http://www.cnblogs.com/fenglingyi/p/4708006.html

转载于:https://www.cnblogs.com/armyfai/p/4709714.html

你可能感兴趣的文章
mysql中的事务和锁_MySQL - 事务和锁中的互斥?
查看>>
mysql statement讲解_Statement接口详解
查看>>
mysql_print_default_知识点:MySQL常用工具介绍(十 二)——实用程序my_print_defaults、perror...
查看>>
mysql怎么会报错_MySQL启动报错怎么办?
查看>>
mysql中常用动词_MySQL 常用
查看>>
mysql如何匹配_如何在mysql中匹配
查看>>
python编译exe用于别的电脑上_Python安装教程(推荐一款不错的Python编辑器)
查看>>
flash back mysql_mysqlbinlog flashback 使用最佳实践
查看>>
hive中如何把13位转化为时间_sqoop1 导入 hive parquet 表中 时间戳调整为日期
查看>>
mysql书外键_[转] mysql 外键(Foreign Key)的详解和实例
查看>>
mysql存储引擎模式_MySQL存储引擎
查看>>
python入门小游戏代码_【Python】Python代码实现“FlappyBird”小游戏
查看>>
pytorch增加一维_pytorch 数据维度变换
查看>>
ie includes语法报错_HTML5基础:JS有哪些变态语法
查看>>
php的mysql的分区_详细介绍mysql中的分区
查看>>
云服务器怎么卸载mysql数据库_mysql 删除数据库脚本
查看>>
mysql 5.5.57互为主从_MYSQL 5.5.18 互为主从配置成功
查看>>
mysql5002_mysql新手进阶02
查看>>
python类 del_全面了解Python类的内置方法
查看>>
前后端传图片用base64好吗_前后端分离 前台传base64的图片 tp5.1.1进行处理
查看>>