C#多线程网页采集器(Spider)
来源:互联网 发布:张孝祥java面试大全 编辑:程序博客网 时间:2024/05/27 20:05
这是一个C#语言编写的多线程网页自动采集程序。下面展示了主要类的代码。完整代码请点此下载。
转自:http://www.cnblogs.com/closetome/articles/1711764.html
- /**
- 软件工程过程实践:
- --------------------------------------------
- 用例->数据模型->描述系统功能的接口->实际编码->测试->交付
- 文字 逻辑设计 顺序图(通讯图) 定制
- 图 sql实现 类图(接口方法) 配置
- c#实现
- 用例UC1: 网页采集
- ----------------------------------------------
- 范围: WSE应用
- 级别: 用户目标
- 主要参与者: 采集员
- 涉众及其关注点:
- ——采集员: 希望能够增加,删除监控URL,启动,停止监控URL,指定监控类型,查看监控URL的列表
- ——站长: 希望采集活动不要影响正常用户访问
- 前置条件: 采集员必须经过确认和认证
- 成功保证(或后置条件): 存储采集数据,确保没有重复的URL
- 主成功场景(或基本流程):
- 1. 采集员增加新的监控URL,设定采集方式(本页,历遍本页,历遍网站),设定采集速度
- 2. 采集员启动采集
- 3. 采集员停止采集(如果有必要)
- 4. 采集员删除某监控URL(如果有必要)
- 5. 采集员浏览监控URL列表(如果有必要)
- PageInfo数据模型
- ----------------------------
- 标识符 | id
- 创建时间 | createdTime
- 修改时间 | modifiedTime
- 创建人 | createdUser
- 修改人 | modifiedUser
- |
- 网址 | URL
- 网址128位MD5 | UrlMD5
- IP地址 | IP
- 采集内容 | content
- 页面类型 | type
- |
- 采集流程图
- -------------------------------
- 初始化:载入已经采集的UrlMD5
- |-------------------------------------------------------------------------------------------------------|
- |Spider类 |
- | |---------------------------------------------------------------------| |----------------| |
- | |--| |采集通道(线程) ------------------------------|--->| 已采集UrlMD5池 | |
- | |种| | |---------| |--------| |---|------| |--------| | |----------------| |
- | |子|---|---|->| URL队列 |--->| 采集器 |--->| | | |---->| 分析器 |---| | |
- | |队| | | |---------| |--------| |------|---| |--------| | | |
- | |列| | | | | | |
- | |--| | |--------------------------------------|----------------------| | |----------------| |
- | |---<| ---------------------------|--->| 已采集内容队列 | |
- | | |---------------------------------------------------------------------| |--------|-------| |
- | | | |
- | | |---------| | |
- | |---<|存储线程 |<------------------------------------------------------------------------| |
- | | |---------| |
- | | |
- | | |---------| |
- | |--->|日志线程 | |
- | |---------| |
- | |
- |-------------------------------------------------------------------------------------------------------|
- 类设计
- -------------------------------
- 控制器类
- SpiderHandler -- 控制台入口
- 采集核心类
- Spider 核心
- PageInfo 基础--数据结构
- Gatherer 基础--网页采集器
- Analyser 基础--url分析器
- 外部接口
- IStorage 数据存储接口
- ISpiderUI 用户界面
- ILogger 日志接口
- */
- //==================================================================
- //
- // 该软件是一个由C#编写的基于控制台的多线程网页自动采集程序。
- // 又称之为蜘蛛,机器人,爬行器等。
- //
- // Copyright(C) 2009 themz.cn All rights reserved
- // author: xml
- // email: 191081370@qq.com
- // blog: http://programmingcanruinyourlife.themz.cn/
- // since: .net2.0
- // version: 1.0
- // created: 2009-08-06
- // modified: 2009-10-10
- //
- // 版权与免责声明:本软件所有权归原作者,用户可自由免费使用于任何非商业环境。
- // 如果转载本文代码请不要删除这段版权声明。
- // 如果由于使用本软件而造成自己或他人的任何损失,均与本软件作者无关。
- // 特此声明!
- //
- //==================================================================
- // 简单使用帮助:
- // 1. 将下面代码保存到一个.cs后缀的文件中
- // 2. 用.net2.0的编译环境编译成一个exe文件后,双击打开
- // 3. 用 addSeeds命令添加采集种子, 例如: addSeeds http://url/
- // 4. 用 start 命令开始采集
- // 5. 反复使用 getContents 命令查看已采集到的内容
- // 6. pause 命令可暂停采集, start 命令继续
- // 7. stop 命令停止采集
- // 8. exit 命令退出本软件
- //
- //
- using System;
- using System.Collections.Generic;
- using System.Data;
- using System.Data.Common;
- using System.IO;
- using System.Net;
- using System.Text;
- using System.Text.RegularExpressions;
- using System.Threading;
- //using System.Configuration;
- //using System.Diagnostics;
- //[Serializable()]
- namespace My.WSE.Spider
- {
- #region 线程模式接口
- /**
- 线程类模式
- 接口 参数
- 队列 属性
- 线程 属性
- 入队 方法
- 出队 方法
- 增加/启动 方法
- 暂停 方法
- 停止 方法
- */
- public interface IThread
- {
- //T Queue{ get; }
- //List<Thread> Threads{ get; }
- //
- //void Enqueue( T t );
- //T Dequeue();
- Thread AddThread();
- void RemoveThread();
- void RequestThreadPause();
- void RequestThreadPause( bool pauseOrContinue );
- void RequestThreadStop();
- }
- #endregion
- #region 外部接口
- // 采集接口
- public interface IGatherer
- {
- void Download( ref PageInfo info,string contentType,int timeout );
- void Download( ref PageInfo info,int timeout );
- }
- // 存储接口
- public interface IStorage
- {
- List<string> GetIndexeds(); //取得所有已下载的URL的MD5值
- List<SeedInfo> GetSeeds();
- int AddSeed( SeedInfo info );
- void RemoveSeed( SeedInfo info );
- void SaveContents( List<PageInfo> info ); //保存采集到的内容
- }
- // 日志接口
- public interface ILogger
- {
- void Write( string content );
- string Read( string filename );
- string ToString( Exception ex );
- }
- #endregion
- #region 异常类
- public class ContentTypeException : Exception
- {
- public ContentTypeException( string message ) : base( message ){}
- }
- public class ContentSizeException : Exception
- {
- public ContentSizeException( string message ) : base( message ){}
- }
- public class NotOnlyException : Exception
- {
- public NotOnlyException( string message ) : base( message ){}
- }
- public class KeyHasExistsException : Exception
- {
- public KeyHasExistsException( string message ) : base( message ){}
- }
- #endregion
- #region PageInfo队列
- public class PageQueue
- {
- // 构造函数1
- public PageQueue()
- {
- _queue = new LinkedList<string>();
- }
- // 构造函数2
- public PageQueue( ref LinkedList<string> queue ) : this()
- {
- if( null != queue ){
- _queue = queue;
- }
- }
- #region 队列方法
- public int Count
- {
- get{ return _queue.Count; }
- }
- public bool Contains( PageInfo info )
- {
- return _queue.Contains( info.UrlMD5 );
- }
- public void Enqueue( PageInfo info ) //等同于AddLast
- {
- AddLast( info );
- }
- public PageInfo Dequeue() //等同于RemoveFirst
- {
- return RemoveFirst();
- }
- public void AddFirst( PageInfo info )
- {
- lock( _queue ){
- _queue.AddFirst( info.UrlMD5 );
- AddData( info );
- Monitor.Pulse( _queue );
- }
- }
- public void AddLast( PageInfo info )
- {
- lock( _queue ){
- _queue.AddLast( info.UrlMD5 );
- AddData( info );
- Monitor.Pulse( _queue );
- }
- }
- public PageInfo RemoveFirst()
- {
- PageInfo info = null;
- lock( _queue ){
- LinkedListNode<string> node = _queue.First;
- if( null == node ){
- Monitor.Wait( _queue );
- node = _queue.First;
- }
- string key = node.Value;
- _queue.RemoveFirst();
- info = GetData(key);
- RemoveData(key); // 释放内存中的数据
- }
- return info;
- }
- public PageInfo RemoveLast()
- {
- PageInfo info = null;
- lock( _queue ){
- LinkedListNode<string> node = _queue.First;
- if( null == node ){
- Monitor.Wait( _queue );
- }
- else{
- string key = node.Value;
- _queue.RemoveFirst();
- info = GetData(key);
- RemoveData(key); // 释放内存中的数据
- }
- }
- return info;
- }
- public PageInfo Remove( PageInfo info )
- {
- lock( _queue ){
- if( _queue.Remove(info.UrlMD5) ){
- info = GetData(info.UrlMD5);
- RemoveData(info.UrlMD5); // 释放内存中的数据
- }
- else{
- info = null;
- }
- }
- return info;
- }
- public Dictionary<string,PageInfo> ToDictionary()
- {
- Dictionary<string,PageInfo> dict = new Dictionary<string,PageInfo>();
- lock( _queue ){
- LinkedListNode<string> node = _queue.First;
- while( null != node ){
- dict[node.Value] = GetData(node.Value);
- node = node.Next;
- }
- }
- return dict;
- }
- #endregion
- #region 词典方法
- public PageInfo GetData( string key )
- {
- lock( _s_pages ){
- if( _s_pages.ContainsKey(key) ){
- return _s_pages[key];
- }else{
- _log.Enqueue( string.Format( "wse.spider.cs GetData,Dictionary键{0}没有找到",key) );
- return null;
- }
- }
- }
- public void AddData( PageInfo info )
- {
- lock( _s_pages ){
- _s_pages[info.UrlMD5] = info;
- }
- }
- public void RemoveData( string key )
- {
- lock( _s_pages ){
- if( _s_pages.ContainsKey(key) ){
- _s_pages.Remove(key);
- }
- }
- }
- public bool ContainsData( PageInfo info )
- {
- return _s_pages.ContainsKey(info.UrlMD5);
- }
- #endregion
- #region Private Members
- private LinkedList<string> _queue = null;
- private static Dictionary<string,PageInfo> _s_pages = new Dictionary<string,PageInfo>();
- private EventLogger _log = new EventLogger();
- #endregion
- }
- #endregion
- #region 采集线程类
- public class PageGatherer : IThread
- {
- #region 构造函数
- // 构造函数1
- public PageGatherer(){}
- // 构造函数2
- public PageGatherer( IGatherer gather )
- {
- _log = new EventLogger();
- _store = new PageStorage();
- _gather = gather;
- _queue = new PageQueue(); // 每个队列可以
- _threads = new List<Thread>(); // 有多个线程
- _shouldPause = new ManualResetEvent(true);
- _shouldStop = false;
- }
- #endregion
- #region Public Property
- // 静态成员公开
- public Dictionary<string,string> IndexedPool
- {
- get{ return _s_indexedPool; }
- }
- public PageQueue SeedQueue
- {
- get{ return _s_seedQueue; }
- }
- // 当前采集队列
- public PageQueue Queue
- {
- get{ return _queue; }
- }
- public List<Thread> Threads
- {
- get{ return _threads; }
- }
- // 线程总数
- public int ThreadCount
- {
- get{ return _threadCount; }
- }
- #endregion
- #region 线程方法(Thread Method)
- // 增加线程
- public Thread AddThread()
- {
- Thread t = new Thread( new ThreadStart(ThreadRun) );
- t.IsBackground = true;
- t.Start();
- _threads.Add(t);
- _threadCount++;
- return t;
- }
- // 减少线程
- public void RemoveThread()
- {
- // 尚未实现
- }
- // 请求线程暂停
- public void RequestThreadPause()
- {
- }
- // 请求线程继续
- public void RequestThreadPause( bool pauseOrContinue )
- {
- if( !pauseOrContinue ){
- _shouldPause.Set();
- }else{
- _shouldPause.Reset();
- }
- }
- // 请求线程停止
- public void RequestThreadStop()
- {
- _shouldStop = true;
- }
- #endregion
- #region Private Methods
- // 采集线程方法
- private void ThreadRun()
- {
- PageInfo info = null;
- // 循环: URL->下载->存储->分析->|URL->下载....
- while( !_shouldStop )
- {
- _shouldPause.WaitOne(); // 是否暂停
- if( _queue.Count < 1 ){
- _queue.Enqueue( _s_seedQueue.Dequeue() ); // 自动取得种子
- }
- info = _queue.Dequeue();
- if( null == info ){ continue; }
- //1 下载
- string url = info.URL;
- try{
- _gather.Download(ref info,"text/html",90000);
- }
- catch( Exception ex ){
- _log.Enqueue( info.URL + " " + ex.ToString() );
- continue;
- }
- //2 把当前url加入_s_indexedPool
- AddIndexed( info.UrlMD5 );
- //3 保存:加入_dataPool
- _store.Queue.Enqueue( info );
- //4 分析:加入下载队列queue
- AnalyzeToQueue( info, ref _queue );
- }
- }
- // 分析出页面中的url,并把它们加进队列中
- private void AnalyzeToQueue( PageInfo info, ref PageQueue queue )
- {
- PageQueue _queue = queue;
- List<string[]> urls = Analyzer.ParseToURLs(info);
- PageInfo newInfo = null;
- for( int i=0,len=urls.Count; i<len; i++ ){
- newInfo = new PageInfo( urls[i][0],info.SeedID );
- if( !_queue.ContainsData(newInfo) && !_s_indexedPool.ContainsKey(newInfo.UrlMD5) ){
- newInfo.Title = urls[i][1];
- newInfo.Referer = info.URL;
- _queue.Enqueue( newInfo );
- }
- }
- }
- // 加入已采集队列
- private void AddIndexed( string urlMD5 )
- {
- lock( _s_indexedPool ){
- if( !_s_indexedPool.ContainsKey(urlMD5) ){
- _s_indexedPool.Add( urlMD5, null );
- }
- }
- }
- #endregion
- #region Private Members
- private EventLogger _log = null;
- private PageStorage _store = null;
- private IGatherer _gather = null; // 接口
- private PageQueue _queue; // 每个队列可以
- private List<Thread> _threads; // 有多个线程
- private ManualResetEvent _shouldPause; // 暂停
- private bool _shouldStop; // 停止
- private static Dictionary<string,string> _s_indexedPool = new Dictionary<string,string>(); // 已采集的URL
- private static PageQueue _s_seedQueue = new PageQueue(); // 种子队列
- private static int _threadCount = 0; // 运行的线程的总数
- #endregion
- }
- #endregion
- #region 存储线程类
- public class PageStorage : IThread
- {
- #region 构造函数
- // 构造函数1
- public PageStorage(){}
- // 构造函数2
- public PageStorage( IStorage store )
- {
- _log = new EventLogger();
- _store = store;
- _shouldStop = false;
- }
- #endregion
- #region Public Property
- // 对列对象
- public PageQueue Queue
- {
- get{ return _s_queue; }
- }
- // 线程对象集合
- public List<Thread> Threads
- {
- get{ return _threads; }
- }
- #endregion
- #region 线程方法(Thread Method)
- // 增加线程
- public Thread AddThread()
- {
- Thread t = new Thread( new ThreadStart(ThreadRun) );
- t.IsBackground = true;
- t.Start();
- return t;
- }
- // 减少线程
- public void RemoveThread()
- {
- // 尚未实现
- }
- // 请求线程暂停
- public void RequestThreadPause()
- {
- // 尚未实现
- }
- // 请求线程继续
- public void RequestThreadPause( bool pauseOrContinue )
- {
- // 尚未实现
- }
- // 请求线程停止
- public void RequestThreadStop()
- {
- _shouldStop = true;
- }
- #endregion
- #region Private Methods
- // 线程方法
- private void ThreadRun()
- {
- if( null == _store ){ return; }
- int count = 10;
- List<PageInfo> infos = null;
- while( !_shouldStop )
- {
- infos = DequeueSome( count );
- try{
- _store.SaveContents( infos );
- }
- catch( Exception ex ){
- _log.Enqueue( ex.ToString() );
- }
- }
- }
- // 队列方法
- private List<PageInfo> DequeueSome( int count )
- {
- List<PageInfo> infos = new List<PageInfo>();
- for( int i=0; i<count; i++ ) // 按每10条记录一组进行存储
- {
- infos.Add( _s_queue.Dequeue() );
- }
- return infos;
- }
- #endregion
- #region Private Members
- private EventLogger _log; //日志
- private IStorage _store; //接口
- private static PageQueue _s_queue = new PageQueue(); //队列
- private List<Thread> _threads = new List<Thread>(); //线程
- private bool _shouldStop;
- #endregion
- }
- #endregion
- #region 日志线程类
- public class EventLogger : IThread
- {
- // 构造函数1
- public EventLogger(){}
- // 构造函数2
- public EventLogger( ILogger logger )
- {
- _logger = logger;
- _shouldStop = false;
- _selfCheckInterval = 300000; // 5分钟
- }
- #region Public Properties
- public Queue<string> Queue
- {
- get{ return _s_queue; }
- }
- public List<Thread> Threads
- {
- get{ return _threads; }
- }
- #endregion
- #region 队列方法(Queue Method)
- public void Enqueue( string s )
- {
- lock( _s_queue ){
- _s_queue.Enqueue( s );
- Monitor.Pulse( _s_queue );
- }
- }
- public string Dequeue()
- {
- lock( _s_queue )
- {
- if( 1 > _s_queue.Count ){
- Monitor.Wait( _s_queue );
- }
- return _s_queue.Dequeue();
- }
- }
- #endregion
- #region 线程方法(Thread Method)
- //
- public Thread AddThread()
- {
- Thread t = new Thread( new ThreadStart(ThreadRun) );
- t.IsBackground = true;
- t.Start();
- _threads.Add(t);
- return t;
- }
- // 减少线程
- public void RemoveThread()
- {
- // 尚未实现
- }
- // 请求线程暂停
- public void RequestThreadPause()
- {
- // 尚未实现
- }
- // 请求线程继续
- public void RequestThreadPause( bool pauseOrContinue )
- {
- // 尚未实现
- }
- // 请求线程停止
- public void RequestThreadStop()
- {
- _shouldStop = true;
- }
- // 增加自检线程
- public void AddSelfCheckThread()
- {
- if( false == _isSelfCheckRun ){
- Thread t = new Thread( new ThreadStart(SelfCheck) );
- t.IsBackground = true;
- t.Start();
- _isSelfCheckRun = true;
- }
- }
- #endregion
- #region Private Methods
- // 日志主线程函数
- private void ThreadRun()
- {
- if( null == _logger ){ return; }
- while( !_shouldStop )
- {
- try{
- _logger.Write( Dequeue() );
- }
- catch( Exception ex ){
- Console.WriteLine( string.Format( "警告:日志写入发生错误{0}",ex.ToString() ) );
- }
- }
- }
- // 日志自检子线程函数
- private void SelfCheck()
- {
- if( null == _logger ){ return; }
- while( !_shouldStop )
- {
- try{
- _logger.Write( "日志自检完成" );
- Thread.Sleep( _selfCheckInterval );
- }
- catch( Exception ex ){
- Console.WriteLine( string.Format( "警告:日志自检发生错误{0}",ex.ToString() ) );
- }
- }
- }
- #endregion
- #region Private Members
- private ILogger _logger = null; // 接口
- private static Queue<string> _s_queue = new Queue<string>(); // 一些标志性事件(异常或成功)
- private List<Thread> _threads = new List<Thread>(); // 一个队列可以有多个线程
- private bool _shouldStop;
- private int _selfCheckInterval; // 日志模块自检间隔
- private static bool _isSelfCheckRun = false;
- #endregion
- }
- #endregion
- } // end namespace My.WSE
0 0
- C#多线程网页采集器(Spider)
- C#多线程网页采集器(Spider)
- C#多线程网页采集器(Spider,网页爬虫)
- python 多线程采集网页
- C# 网页图片采集
- C#采集网页代码
- 网页采集c#
- 采集程序(spider)
- C# WEB网页内容采集
- C# WEB网页内容采集
- C# WEB网页内容采集
- C# WEB网页内容采集
- python 多线程采集网页完善版
- java采集网页数据方法【多线程数据采集之一】
- java采集网页数据方法【多线程数据采集之一】
- 网页采集器-八爪鱼采集器
- C# 网页信息采集(数据访问)
- C# 网页信息采集(Form.cs)
- Swift基础知识
- Android存储的实现
- gc函数
- 2002
- 适配器模式
- C#多线程网页采集器(Spider)
- sscanf函数 和cin流的问题
- 敏捷开发之srcum
- 生成验证码图片
- scrollTop兼容各个浏览器的办法
- 1. Two Sum
- .Net/C# 实现 中国移动 CMPP v3.0 ISMG <-> SP 收发短信的 SP 客户端 (CMPP SP Client)
- 雅虎股票接口 转载
- spring mvc + mybatis 整合框架