用C#實現網絡爬蟲(二)


 

上一篇《用C#實現網絡爬蟲(一)》我們實現了網絡通信的部分,接下來繼續討論爬蟲的實現

 

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("{0}\\{1}.txt", _path, _index++); //生成文件名
 8 
 9     try
10     {
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, path, 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. 提取頁面鏈接

提取鏈接用正則表達式就能搞定了,不懂的可以上網搜。

下面的字符串就能匹配到頁面中的鏈接

http://([\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 string[m.Count]; 
 7 
 8     for (int i = 0; i < m.Count; i++)
 9     {
10         links[i] = m[i].ToString(); //提取出結果
11     }
12     return links;
13 }


5. 鏈接的過濾

不是所有的鏈接我們都需要下載,所以通過過濾,去掉我們不需要的鏈接

這些鏈接一般有:

  • 已經下載的鏈接
  • 深度過大的鏈接
  • 其他的不需要的資源,如圖片、CSS等
 1 //判斷鏈接是否已經下載或者已經處於未下載集合中
 2 private bool UrlExists(string url) 
 3 {
 4     bool result = _urlsUnload.ContainsKey(url);
 5     result |= _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 void AddUrls(string[] urls, int depth)
25 {
26     if (depth >= _maxDepth)
27     {
28         return; //深度過大
29     }
30     foreach (string url in urls)
31     {
32         string cleanUrl = url.Trim(); //去掉前后空格
33         cleanUrl = cleanUrl.TrimEnd('/'); //統一去掉最后面的'/'
34         if (UrlAvailable(cleanUrl))
35         {
36             if (cleanUrl.Contains(_baseUrl))
37             {
38                 _urlsUnload.Add(cleanUrl, depth); //是內鏈,直接加入未下載集合
39             }
40             else
41             {
42                 // 外鏈處理
43             }
44         }
45     }
46 }

 第34行的_baseUrl是爬取的基地址,如http://news.sina.com.cn/,將會保存為news.sina.com.cn,當一個URL包含此字符串時,說明是該基地址下的鏈接;否則為外鏈。

 

_baseUrl的處理如下,_rootUrl是第一個要下載的URL

 1 /// <summary>
 2 /// 下載根Url
 3 /// </summary>
 4 public string RootUrl
 5 {
 6     get
 7     {
 8         return _rootUrl;
 9     }
10     set
11     {
12         if (!value.Contains("http://"))
13         {
14             _rootUrl = "http://" + value;
15         }
16         else
17         {
18             _rootUrl = value;
19         }
20         _baseUrl = _rootUrl.Replace("www.", ""); //全站的話去掉www
21         _baseUrl = _baseUrl.Replace("http://", ""); //去掉協議名
22         _baseUrl = _baseUrl.TrimEnd('/'); //去掉末尾的'/'
23     }
24 }


至此,基本的爬蟲功能實現就介紹完了。

最后附上源代碼和DEMO程序,爬蟲的源代碼在Spider.cs中,DEMO是一個WPF的程序,Test里是一個控制台的單線程版版本。

PageExtractor.zip

 

在下一期中,我們將介紹一些提取出網頁中有效信息的方法,敬請期待。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM