版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、网络爬虫在信息检索与处理中有很大的作用,是收集网络信息的重要工具。接下来就介绍一下爬虫的简单实现。爬虫的工作流程如下爬虫自指定的URL地址开始下载网络资源,直到该地址和所有子地址的指定资源都下载完毕为止。下面开始逐步分析爬虫的实现。 1. 待下载集合与已下载集合为了保存需要下载的URL,同时防止重复下载,我们需要分别用了两个集合来存放将要下载的URL和已经下载的URL。因为在保存URL的同时需要保存与URL相关的一些其他信息,如深度,所以这里我采用了Dictionary来存放这些URL。具体类型是Dictionary<string, int> 其中string是Url字符串,int
2、是该Url相对于基URL的深度。每次开始时都检查未下载的集合,如果已经为空,说明已经下载完毕;如果还有URL,那么就取出第一个URL加入到已下载的集合中,并且下载这个URL的资源。 2. HTTP请求和响应C#已经有封装好的HTTP请求和响应的类HttpWebRequest和HttpWebResponse,所以实现起来方便不少。为了提高下载的效率,我们可以用多个请求并发的方式同时下载多个URL的资源,一种简单的做法是采用异步请求的方法。控制并发的数量可以用如下方法实现 1 private void DispatchWork() 2 3 if (_stop) /判断是否中止下载 4 5 retu
3、rn; 6 7 for (int i = 0; i < _reqCount; i+) 8 9 if (!_reqsBusyi) /判断此编号的工作实例是否空闲10 11 RequestResource(i); /让此工作实例请求资源12 13 14 由于没有显式开新线程,所以用一个工作实例来表示一个逻辑工作线程1 private bool _reqsBusy = null; /每个元素代表一个工作实例是否正在工作2 private int _reqCount = 4; /工作实例的数量 每次一个工作实例完成工作,相应的_reqsBusy就设为false,并调用DispatchWork,那
4、么DispatchWork就能给空闲的实例分配新任务了。 接下来是发送请求 1 private void RequestResource(int index) 2 3 int depth; 4 string url = "" 5 try 6 7 lock (_locker) 8 9 if (_urlsUnload.Count <= 0) /判断是否还有未下载的URL10 11 _workingSignals.FinishWorking(index); /设置工作实例的状态为Finished12 return;13 14 _reqsBusyindex = true;15
5、 _workingSignals.StartWorking(index); /设置工作状态为Working16 depth = _urlsUnload.First().Value; /取出第一个未下载的URL17 url = _urlsUnload.First().Key;18 _urlsLoaded.Add(url, depth); /把该URL加入到已下载里19 _urlsUnload.Remove(url); /把该URL从未下载中移除20 21 22 HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);23 req.M
6、ethod = _method; /请求方法24 req.Accept = _accept; /接受的内容25 req.UserAgent = _userAgent; /用户代理26 RequestState rs = new RequestState(req, url, depth, index); /回调方法的参数27 var result = req.BeginGetResponse(new AsyncCallback(ReceivedResource), rs); /异步请求28 ThreadPool.RegisterWaitForSingleObject(result.AsyncWa
7、itHandle, /注册超时处理方法29 TimeoutCallback, rs, _maxTime, true);30 31 catch (WebException we)32 33 MessageBox.Show("RequestResource " + we.Message + url + we.Status);34 35 第7行为了保证多个任务并发时的同步,加上了互斥锁。_locker是一个Object类型的成员变量。第9行判断未下载集合是否为空,如果为空就把当前工作实例状态设为Finished;如果非空则设为Working并取出一个URL开始下载。当所有工作实例
8、都为Finished的时候,说明下载已经完成。由于每次下载完一个URL后都调用DispatchWork,所以可能激活其他的Finished工作实例重新开始工作。第26行的请求的额外信息在异步请求的回调方法作为参数传入,之后还会提到。第27行开始异步请求,这里需要传入一个回调方法作为响应请求时的处理,同时传入回调方法的参数。第28行给该异步请求注册一个超时处理方法TimeoutCallback,最大等待时间是_maxTime,且只处理一次超时,并传入请求的额外信息作为回调方法的参数。 RequestState的定义是 1 class RequestState 2 3 private const
9、int BUFFER_SIZE = 131072; /接收数据包的空间大小 4 private byte _data = new byteBUFFER_SIZE; /接收数据包的buffer 5 private StringBuilder _sb = new StringBuilder(); /存放所有接收到的字符 6 7 public HttpWebRequest Req get; private set; /请求 8 public string Url get; private set; /请求的URL 9 public int Depth get; private set; /此次请求的
10、相对深度10 public int Index get; private set; /工作实例的编号11 public Stream ResStream get; set; /接收数据流12 public StringBuilder Html13 14 get15 16 return _sb;17 18 19 20 public byte Data21 22 get23 24 return _data;25 26 27 28 public int BufferSize29 30 get31 32 return BUFFER_SIZE;33 34 35 36 public RequestStat
11、e(HttpWebRequest req, string url, int depth, int index)37 38 Req = req;39 Url = url;40 Depth = depth;41 Index = index;42 43 TimeoutCallback的定义是 1 private void TimeoutCallback(object state, bool timedOut) 2 3 if (timedOut) /判断是否是超时 4 5 RequestState rs = state as RequestState; 6 if (rs != null) 7 8 rs
12、.Req.Abort(); /撤销请求 9 10 _reqsBusyrs.Index = false; /重置工作状态11 DispatchWork(); /分配新任务12 13 接下来就是要处理请求的响应了 1 private void ReceivedResource(IAsyncResult ar) 2 3 RequestState rs = (RequestState)ar.AsyncState; /得到请求时传入的参数 4 HttpWebRequest req = rs.Req; 5 string url = rs.Url; 6 try 7 8 HttpWebResponse res
13、 = (HttpWebResponse)req.EndGetResponse(ar); /获取响应 9 if (_stop) /判断是否中止下载10 11 res.Close();12 req.Abort();13 return;14 15 if (res != null && res.StatusCode = HttpStatusCode.OK) /判断是否成功获取响应16 17 Stream resStream = res.GetResponseStream(); /得到资源流18 rs.ResStream = resStream;19 var result = resSt
14、ream.BeginRead(rs.Data, 0, rs.BufferSize, /异步请求读取数据20 new AsyncCallback(ReceivedData), rs);21 22 else /响应失败23 24 res.Close();25 rs.Req.Abort();26 _reqsBusyrs.Index = false; /重置工作状态27 DispatchWork(); /分配新任务28 29 30 catch (WebException we)31 32 MessageBox.Show("ReceivedResource " + we.Messag
15、e + url + we.Status);33 34 第19行这里采用了异步的方法来读数据流是因为我们之前采用了异步的方式请求,不然的话不能够正常的接收数据。该异步读取的方式是按包来读取的,所以一旦接收到一个包就会调用传入的回调方法ReceivedData,然后在该方法中处理收到的数据。该方法同时传入了接收数据的空间rs.Data和空间的大小rs.BufferSize。 接下来是接收数据和处理 1 private void ReceivedData(IAsyncResult ar) 2 3 RequestState rs = (RequestState)ar.AsyncState; /获取参数
16、 4 HttpWebRequest req = rs.Req; 5 Stream resStream = rs.ResStream; 6 string url = rs.Url; 7 int depth = rs.Depth; 8 string html = null; 9 int index = rs.Index;10 int read = 0;11 12 try13 14 read = resStream.EndRead(ar); /获得数据读取结果15 if (_stop)/判断是否中止下载16 17 rs.ResStream.Close();18 req.Abort();19 retu
17、rn;20 21 if (read > 0)22 23 MemoryStream ms = new MemoryStream(rs.Data, 0, read); /利用获得的数据创建内存流24 StreamReader reader = new StreamReader(ms, _encoding);25 string str = reader.ReadToEnd(); /读取所有字符26 rs.Html.Append(str); / 添加到之前的末尾27 var result = resStream.BeginRead(rs.Data, 0, rs.BufferSize, /再次异步
18、请求读取数据28 new AsyncCallback(ReceivedData), rs);29 return;30 31 html = rs.Html.ToString();32 SaveContents(html, url); /保存到本地33 string links = GetLinks(html); /获取页面中的链接34 AddUrls(links, depth + 1); /过滤链接并添加到未下载集合中35 36 _reqsBusyindex = false; /重置工作状态37 DispatchWork(); /分配新任务38 39 catch (WebException we
19、)40 41 MessageBox.Show("ReceivedData Web " + we.Message + url + we.Status);42 43 第14行获得了读取的数据大小read,如果read>0说明数据可能还没有读完,所以在27行继续请求读下一个数据包;如果read<=0说明所有数据已经接收完毕,这时rs.Html中存放了完整的HTML数据,就可以进行下一步的处理了。第26行把这一次得到的字符串拼接在之前保存的字符串的后面,最后就能得到完整的HTML字符串。 然后说一下判断所有任务完成的处理 1 private void StartDown
20、load() 2 3 _checkTimer = new Timer(new TimerCallback(CheckFinish), null, 0, 300); 4 DispatchWork(); 5 6 7 private void CheckFinish(object param) 8 9 if (_workingSignals.IsFinished() /检查是否所有工作实例都为Finished10 11 _checkTimer.Dispose(); /停止定时器12 _checkTimer = null;13 if (DownloadFinish != null &&
21、 _ui != null) /判断是否注册了完成事件14 15 _ui.Dispatcher.Invoke(DownloadFinish, _index); /调用事件16 17 18 第3行创建了一个定时器,每过300ms调用一次CheckFinish来判断是否完成任务。第15行提供了一个完成任务时的事件,可以给客户程序注册。_index里存放了当前下载URL的个数。该事件的定义是1 public delegate void DownloadFinishHandler(int count);2 3 / <summary>4 / 全部链接下载分析完毕后触发5 / </summ
22、ary>6 public event DownloadFinishHandler DownloadFinish = null;3. 保存页面文件这一部分可简单可复杂,如果只要简单地把HTML代码全部保存下来的话,直接存文件就行了。 1 private void SaveContents(string html, string url) 2 3 if (string.IsNullOrEmpty(html) /判断html字符串是否有效 4 5 return; 6 7 string path = string.Format("01.txt", _path, _index+
23、); /生成文件名 8 9 try10 11 using (StreamWriter fs = new StreamWriter(path)12 13 fs.Write(html); /写文件14 15 16 catch (IOException ioe)17 18 MessageBox.Show("SaveContents IO" + ioe.Message + " path=" + path);19 20 21 if (ContentsSaved != null)22 23 _ui.Dispatcher.Invoke(ContentsSaved, p
24、ath, url); /调用保存文件事件24 25 第23行这里又出现了一个事件,是保存文件之后触发的,客户程序可以之前进行注册。1 public delegate void ContentsSavedHandler(string path, string url);2 3 / <summary>4 / 文件被保存到本地后触发5 / </summary>6 public event ContentsSavedHandler ContentsSaved = null; 4. 提取页面链接提取链接用正则表达式就能搞定了,不懂的可以上网搜。下面的字符串就能匹配到页面中的链接h
25、ttp:/(w-+.)+w-+(/w- ./?%&=*)?详细见代码 1 private string GetLinks(string html) 2 3 const string pattern = "http:/(w-+.)+w-+(/w- ./?%&=*)?" 4 Regex r = new Regex(pattern, RegexOptions.IgnoreCase); /新建正则模式 5 MatchCollection m = r.Matches(html); /获得匹配结果 6 string links = new stringm.Count;
26、7 8 for (int i = 0; i < m.Count; i+) 9 10 linksi = mi.ToString(); /提取出结果11 12 return links;13 5. 链接的过滤不是所有的链接我们都需要下载,所以通过过滤,去掉我们不需要的链接这些链接一般有:已经下载的链接深度过大的链接其他的不需要的资源,如图片、CSS等 1 /判断链接是否已经下载或者已经处于未下载集合中 2 private bool UrlExists(string url) 3 4 bool result = _urlsUnload.ContainsKey(url); 5 result |=
27、 _urlsLoaded.ContainsKey(url); 6 return result; 7 8 9 private bool UrlAvailable(string url)10 11 if (UrlExists(url)12 13 return false; /已经存在14 15 if (url.Contains(".jpg") | url.Contains(".gif")16 | url.Contains(".png") | url.Contains(".css")17 | url.Contains(".js")18 19 return false; /去掉一些图片之类的资源20 21 return true;22 23 24 private
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 中国老年人口失能状况及变化分析
- 人脸识别的智能防疫系统设计
- 会计职业生涯规划
- Unit3 Listening 说课稿2024-2025学年外研版七年级英语上册
- 山东省聊城市阳谷县四校2024-2025学年七年级上学期1月期末水平调研道德与法治试题(含答案)
- 二零二五年度城市停车场施工廉政管理服务合同3篇
- 贵州商学院《软装设计》2023-2024学年第一学期期末试卷
- 信息技术《使用扫描仪》说课稿
- 2025版家庭亲子教育图书订阅服务合同范本3篇
- 二零二五年度家族企业股东股权继承转让协议3篇
- 安全经理述职报告
- 福建省泉州市2023-2024学年高一上学期期末质检英语试题 附答案
- 建筑项目经理招聘面试题与参考回答(某大型集团公司)2024年
- 安保服务评分标准
- (高清版)DB34∕T 1337-2020 棉田全程安全除草技术规程
- 部编版小学语文二年级上册单元测试卷含答案(全册)
- 护理部年终总结
- 部编版三年级上册语文语文期末质量监测(含答题卡)
- KISSSOFT操作与齿轮设计培训教程
- 2024年第二季度粤港澳大湾区经济分析报告-PHBS
- 消防安全制度完整版
评论
0/150
提交评论