?? 如何用c#語言構造網絡蜘蛛程序2.htm
字號:
<html>
<head>
<title>如何用C#語言構造網絡蜘蛛程序|搜索引擎,網絡蜘蛛,程序,算法,C#-中國源碼網</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta http-equiv="Refresh" content=600>
<meta name="keywords" content="搜索引擎,網絡蜘蛛,程序,算法,C#">
<meta name="description" content="如何用C#語言構造網絡蜘蛛程序">
<link rel="stylesheet" href="/templates/yobo/style/default/style.css" type="text/css" media="all" />
</head><body oncontextmenu='return false' ondragstart='return false' onselectstart ='return false' onselect='document.selection.empty()' oncopy='document.selection.empty()' onbeforecopy='return false'>
<a name="top"></a>
<!--頁面頭部信息-->
<div id="header">
<div id="topmenu">
<div class="left">
<div id="topdate"><a href="http://www.yuanma.org/rss.php" target="_blank" title="中國源碼 RSS 訂閱 "><img src="/images/rss.gif" border="0"></a>=>中國源碼:全球著名開源項目大本營</div>
</div>
<div class="right">
<div id="topnavlist">
<ul>
<li><a href="/member.php?action=reg" title="注冊會員">注冊會員</a></li>
<li><a href="/member.php?action=login" title="會員登錄">會員登錄</a></li>
<li><a href="/member.php?action=manage" title="控制面板">控制面板</a></li>
<li><a href="#" onClick="this.style.behavior= 'url(#default#homepage)';this.setHomePage ('http://www.yuanma.org');">設為首頁</a></li>
<li><a href="#" onClick="window.external.addFavorite('http://www.yuanma.org','中國源碼-全球著名開放源代碼大本營')">加入收藏</a></li>
<li><a href="http://cgi.alexa.com/client/mail_this_site/cgi-bin/mail_this_site.cgi?url=yuanma.org" title="推薦本站" target=_blank>推薦本站</a></li>
</ul>
</div>
</div>
</div>
<div id="maintop">
<div id="LogoSide1">
<a href="/blog/"><img src="/images/blog.gif" alt="博客" /></a>
<a href="/download/"><img src="/images/download.gif" alt="下載" /></a><br />
博客 下載
</div>
<div id="Logo"><a href="/"><img src="/images/logo.gif" alt="中國源碼 首頁" /></a></div>
<div id="LogoSide2">
<a href="/bbs/"><img src="/images/forum.gif" alt="論壇" /></a>
<a href="/lilina/" target=_blank><img src="/images/rss_reader.gif" alt="最新開源項目" /></a><br />
論壇 開源項目
</div>
</div>
<div class="navline"> </div>
<div class="navup">
<div id="nav-up-left"><a href="/" class="mainmenu">首頁</a> ·<a href='/data/osupdate/' target='_self' title='開源社區最新動態、新聞' class="mainmenu">開源動態</a>
·<a href='/data/osprojects/' target='_self' title='世界知名開源社區著名開源項目、軟件介紹和使用文章' class="mainmenu">應用軟件</a>
·<a href='/data/osprojectsos/' target='_self' title='開放源代碼操作系統 Linux FreeBSD OpenBSD..' class="mainmenu">開源操作系統</a>
·<a href='/data/osprojectssd/' target='_self' title='介紹程序設計方法、事例、教程
software development' class="mainmenu">程序設計</a>
·<a href='/data/osarticles/' target='_self' title='開放源代碼社區文章、評論' class="mainmenu">開源文章</a>
·<a href='/data/yuanmaprotocol/' target='_self' title='介紹網絡協議、RFC及安全' class="mainmenu">網絡協議與安全</a>
·<a href="/data/special/" class="mainmenu">專題</a>·<a href="/mypage.php?action=picture" class="mainmenu">圖片文章</a>·<a href="/search.php" title="搜索" class="mainmenu">搜索</a>· <a href="/contribute.php" title="投稿" class="mainmenu">投稿</a> </div>
</div>
<div class="navline"> </div>
</div>
<SCRIPT language=javascript type=text/javascript>
var currentpos,timer;
function initialize()
{
timer=setInterval("scrollwindow()",2);
}
function sc(){
clearInterval(timer);
}
function scrollwindow()
{
currentpos=document.body.scrollTop;
window.scroll(0,++currentpos);
if (currentpos != document.body.scrollTop)
sc();
}
document.onmousedown=sc
document.ondblclick=initialize
</SCRIPT>
<script language="JavaScript">
function fontZoom(size)
{
document.getElementById('fontzoom').style.fontSize=size+'px'
}
function doCheck(){
// 檢測表單的有效性
// 如:標題不能為空,內容不能為空,等等....
if (myform.username.value=="") {
alert("請輸入姓名!");
myform.username.focus();
return false;
}
if (myform.content.value=="") {
alert("請輸入評論內容!");
myform.content.focus();
return false;
}
if (myform.checkcode.value=="") {
alert("請輸入驗證碼!");
myform.checkcode.focus();
return false;
}
return true;
}
</script>
<div class="mainline"> </div>
<div class="maincolumn">
<div class="navadimg">
<script type="text/javascript"><!--
google_ad_client = "pub-4357927283882197";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "image";
google_ad_channel = "";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
</div>
<div class="mainline"> </div>
<div class="maincolumn">
<div id="flist">
<div class="ftitleico"> </div>
<div class="ftitlebg">
<div class="ftitlename">當前位置: <a href='/' class='position'>首頁</a> >> <a href='/data/osprojectssd/' class='position'>程序設計</a> >> 如何用C#語言構造網絡蜘蛛程序</div>
</div>
<div class="clear"> </div>
<div id="newsview">
<div class="title">
<h1>如何用C#語言構造網絡蜘蛛程序</h1>
<h2><strong>作者:</strong><a href="/member.php?action=show&username=webmaster" target="_blank"></a> <strong>來源:</strong><a href="http://blog.csdn.net/smildlzj/archive/2006/09/21/1260758.aspx" target="_blank">zz</a> <strong>發表時間:</strong>2006-09-21
<strong>瀏覽次數:</strong>
<script language=Javascript src="/view.php?articleid=1570"></script>
<strong>字號:</strong><a href="javascript:fontZoom(16)" class=black>大</a> <a href="javascript:fontZoom(14)" class=black>中</a> <a href="javascript:fontZoom(12)" class=black>小</a></h2>
</div>
<div id="fontzoom" class="content">
<p><BR>這里,searchWeb()公平的確定它是否有值得搜索的URL,接著它為搜索樹創建一個新節點,添加到樹中,打開一個輸入流解析文件。下面的章節涉及很多關于解析HTML文件,處理相關URL和控制遞歸的細節。<BR><BR>1、解析HTML文件<BR><BR>這里有兩個為了查找A HREF來解析HTML文件方法——一個麻煩的方法和一個簡單的方法。<BR><BR>如果你選擇麻煩的方法,你將使用Java的StreamTokenizer類創建你自己的解析規則。使用這些技術,你必須為StreamTokenizer對象指定單詞和空格,接著去掉<和>符號來查找標簽,屬性,在標簽之間分割文字。太多的工作要做。<BR><BR>簡單的方法是使用內置的ParserDelegator類,一個HTMLEditorKit.Parser抽象類的子類。這些類在Java文檔中沒有完善的文檔。使用ParserDelegator有三個步驟:首先為你的URL創建一個InputStreamReader對象,接著創建一個ParserCallback對象的實例,最后創建一個ParserDelegator對象的實例并調用它的public方法parse():<BR><BR><BR><BR>UrlTreeNode newnode = new UrlTreeNode(url); // Create the data node <BR>InputStream in = url.openStream(); // Ask the URL object to create an input stream<BR>InputStreamReader isr = new InputStreamReader(in); // Convert the stream to a reader<BR>DefaultMutableTreeNode treenode = addNode(parentnode, newnode); <BR>SpiderParserCallback cb = new SpiderParserCallback(treenode); // Create a callback object<BR>ParserDelegator pd = new ParserDelegator(); // Create the delegator<BR>pd.parse(isr,cb,true); // Parse the stream<BR>isr.close(); // Close the stream<BR>parse()接受一個InputStreamReader,一個ParseCallback對象實例和一個指定CharSet標簽是否忽略的標志。parse()方法接著讀和解碼HTML文件,每次完成解碼一個標簽或者HTML元素后調用ParserCallback對象的方法。<BR><BR>在示例代碼中,我實現了ParserCallback作為Spider的一個內部類,這樣就允許ParseCallback訪問Spider的方法和屬性。基于ParserCallback的類可以覆蓋下面的方法:<BR><BR>■ handleStartTag():當遇到起始HTML標簽時調用,比如>A <<BR><BR>■ handleEndTag():當遇到結束HTML標簽時調用,比如>/A<<BR><BR>■ handleSimpleTag():當遇到沒有匹配結束標簽時調用<BR><BR>■ handleText():當遇到標簽之間的文字時調用<BR><BR><BR>在示例代碼中,我覆蓋了handleSimpleTag()以便我的代碼可以處理HTML的BASE和IMG標簽。BASE標簽告訴當處理相關的URL引用時使用什么URL。如果沒有BASE標簽出現,那么當前URL就用來處理相關的引用。HandleSimpleTag()接受三個參數,一個HTML.Tag對象,一個包含所有標簽屬性的MutableAttributeSet,和在文件中的相應位置。我的代碼檢查標簽來判斷它是否是一個BASE對象實例,如果是則HREF屬性被提取出來并保存在頁面的數據節點中。這個屬性以后在處理鏈接站點的URL地址中被用到。每次遇到IMG標簽,頁面圖片數就被更新。<BR><BR>我覆蓋了handleStartTag以便程序可以處理HTML的A和TITLE標簽。方法檢查t參數是否是一個事實上的A標簽,如果是則HREF屬性將被提取出來。<BR><BR>fixHref()被用作清理大量的引用(改變反斜線為斜線,添加缺少的結束斜線),鏈接的URL通過使用基礎URL和引用創建URL對象來處理。接著遞歸調用searchWeb()來處理鏈接。如果方法遇到TITLE標簽,它就清除存儲最后遇到文字的變量以便標題的結束標記具有正確的值(有時網頁的title標簽之間沒有標題)。<BR><BR>我覆蓋了handleEndTag()以便HTML的TITLE結束標記可以被處理。這個結束標記指出前面的文字(存在lastText中)是頁面的標題文字。這個文字接著存在頁面的數據節點中。因為添加標題信息到數據節點中將改變樹中數據節點的顯示,nodeChanged()方法必須被調用以便樹可以更新。<BR><BR>我覆蓋了handleText()方法以便HTML頁面的文字可以根據被搜索的任意關鍵字或者短語來檢查。HandleText()接受一個包含一個子符數組和該字符在文件中位置作為參數。HandleText()首先將字符數組轉換成一個String對象,在這個過程中全部轉換為大寫。接著在搜索列表中的每個關鍵字/短語根據String對象的indexof()方法來檢查。如果indexof()返回一個非負結果,則關鍵字/短語在頁面的文字中顯示。如果關鍵字/短語被顯示,匹配被記錄在匹配列表的節點中,統計數據被更新:<BR><BR>public class SpiderParserCallback extends HTMLEditorKit.ParserCallback {<BR><BR>/**<BR><BR>* Inner class used to html handle parser callbacks<BR><BR>*/<BR><BR><BR>public class SpiderParserCallback extends HTMLEditorKit.ParserCallback {<BR><BR>/** URL node being parsed */<BR><BR>private UrlTreeNode node;<BR><BR>/** Tree node */<BR><BR>private DefaultMutableTreeNode treenode;<BR><BR>/** Contents of last text element */<BR><BR>private String lastText = "";<BR><BR>/**<BR><BR>* Creates a new instance of SpiderParserCallback<BR><BR>* @param atreenode search tree node that is being parsed<BR>*/<BR><BR>public SpiderParserCallback(DefaultMutableTreeNode atreenode) {<BR><BR>treenode = atreenode;<BR>node = (UrlTreeNode)treenode.getUserObject();<BR><BR>}<BR><BR>/**<BR>* Handle HTML tags that don't have a start and end tag<BR>* @param t HTML tag<BR>* @param a HTML attributes<BR>* @param pos Position within file<BR>*/ <BR>public void handleSimpleTag(HTML.Tag t,<BR><BR>MutableAttributeSet a,<BR>int pos)<BR><BR>{<BR>if(t.equals(HTML.Tag.IMG))<BR><BR>{<BR>node.addImages(1);<BR>return;<BR>}<BR><BR>if(t.equals(HTML.Tag.BASE))<BR>{<BR>Object value = a.getAttribute(HTML.Attribute.HREF);<BR><BR>if(value != null)<BR>node.setBase(fixHref(value.toString())); <BR>} <BR>}<BR><BR>/**<BR><BR>* Take care of start tags<BR><BR>* @param t HTML tag<BR><BR>* @param a HTML attributes<BR><BR>* @param pos Position within file<BR>*/<BR>public void handleStartTag(HTML.Tag t,<BR><BR>MutableAttributeSet a,<BR><BR>int pos)<BR>{<BR>if(t.equals(HTML.Tag.TITLE))<BR>{<BR><BR>lastText="";<BR>return;<BR><BR>}<BR><BR>if(t.equals(HTML.Tag.A))<BR><BR>{<BR><BR>Object value = a.getAttribute(HTML.Attribute.HREF);<BR>if(value != null)<BR>{<BR>node.addLinks(1); <BR>String href = value.toString();<BR>href = fixHref(href);<BR>try{<BR>URL referencedURL = new URL(node.getBase(),href);<BR>searchWeb(treenode, referencedURL.getProtocol()+"://"+referencedURL.getHost()+referencedURL.getPath());<BR>}<BR>catch (MalformedURLException e)<BR><BR>{<BR>messageArea.append(" Bad URL encountered : "+href+"\n\n"); return; <BR>}<BR>}<BR>}<BR>}<BR>/**<BR>* Take care of start tags<BR>* @param t HTML tag<BR>* @param pos Position within file<BR><BR>*/<BR>public void handleEndTag(HTML.Tag t,<BR>int pos)<BR><BR>{<BR>if(t.equals(HTML.Tag.TITLE) && lastText != null)<BR>{<BR>node.setTitle(lastText.trim());<BR>DefaultTreeModel tm = (DefaultTreeModel)searchTree.getModel();<BR><BR>tm.nodeChanged(treenode);<BR><BR>}<BR><BR>}<BR><BR>/**<BR><BR>* Take care of text between tags, check against keyword list for matches, if<BR>* match found, set the node match status to true<BR>* @param data Text between tags<BR>* @param pos position of text within Webpage<BR>*/<BR>public void handleText(char[] data, int pos)<BR>{<BR><BR>lastText = new String(data);<BR>node.addChars(lastText.length());<BR>String text = lastText.toUpperCase();<BR>for(int i = 0; i < keywordList.length; i++)<BR>{<BR>if(text.indexOf(keywordList) >= 0)<BR>{<BR>if(!node.isMatch())<BR>{<BR>sitesFound++;<BR>updateStats();<BR>}<BR>node.setMatch(keywordList); <BR>return;<BR>}<BR>}<BR>}<BR><BR>}<BR><BR>2、處理和補全URL<BR><BR>當遇到相關頁面的鏈接,你必須在它們基礎URL上創建完整的鏈接。基礎URL可能通過BASE標簽在頁面中明確的定義,或者暗含在當前頁面的鏈接中。Java的URL對象為你解決這個問題提供了構造器,提供了根據它的鏈接結構創建相似的。<BR>URL(URL context, String spec)接受spec參數的鏈接和context參數的基礎鏈接。如果spec是一個相關鏈接,構建器將使用context來創建一個完整引用的URL對象。URL它推薦URL遵循嚴格的(Unix)格式。使用反斜線,在Microsoft Windows中,而不是斜線,將是錯誤的引用。如果spec或者context指向一個目錄(包含index.html或default.html),而不是一個HTML文件,它必須有一個結束斜線。fixHref()方法檢查這些引用并且修正它們:<BR><BR><BR>public static String fixHref(String href)<BR>{<BR><BR>String newhref = href.replace('\\', '/'); // Fix sloppy Web references<BR><BR>int lastdot = newhref.lastIndexOf('.');<BR><BR>int lastslash = newhref.lastIndexOf('/');<BR>if(lastslash > lastdot)<BR>{<BR>if(newhref.charAt(newhref.length()-1) != '/')<BR>newhref = newhref+"/"; // Add missing /<BR><BR>}<BR>return newhref; <BR><BR>}<BR><BR><BR>3、 控制遞歸<BR><BR>searchWeb()開始是為了搜索用戶指定的起始Web地址而被調用的。它接著在遇到HTML鏈接時調用自身。這形成了深度優先搜索的基礎,也帶來了兩種問題。首先非常危險的內存/堆棧溢出問題將因為太多的遞歸調用而產生。如果出現環形的引用,這個問題就將發生,也就是說,一個頁面鏈接另外一個鏈接回來的連接,這是WWW中常見的事情。為了預防這種現象,searchWeb()檢查搜索樹(通過urlHasBeenVisited()方法)來確定是否引用的頁面已經存在。如果已經存在,這個鏈接將被忽略。如果你選擇實現一個沒有搜索樹的蜘蛛,你仍然必須維護一個以訪問站點的列表(在Vector或數組中)以便你可以判斷是否你正在重復訪問站點。<BR><BR>遞歸的第二個問題來自深度優先的搜索和WWW的結構。根據選擇的入口,深度優先的搜索在初始頁面的初始鏈接在完成處理以前造成大量的遞歸調用。這就造成了兩種不需要的結果:首先內存/堆棧溢出可能發生,第二被搜索過的頁面可能很久才被從初始入口眾多的結果中刪除。為了控制這些,我為蜘蛛添加了最大搜索深度設置。用戶可以選擇可以達到的深度等級(鏈接到鏈接到鏈接),當遇到每個鏈接時,當前深度通過調用depthLimitExceeded()方法進行檢查。如果達到限制,鏈接就被忽略。測試僅僅檢查JTree中節點的級別。<BR><BR>示例程序也增加了站點限制,用戶來指定,可以在特定數目的URL被檢查以后停止搜索,這樣確保程序可以最后停止!站點限制通過一個簡單的數字計數器sitesSearched來控制,這個數字每次調用searchWeb()后都被更新和檢查。<BR><BR>4、UrlTreeNode和UrlNodeRenderer<BR><BR>UrlTreeNode和UrlNodeRenderer是用來在SpiderControl用戶界面中創建JTree中個性化的樹節點的類。UrlTreeNode包含每個搜索過的站點鐘的URL信息和統計數據。UrlTreeNode以作為用戶對象屬性的標準DefaultMutableTreeNode對象形式存儲在JTree中。數據包括節點中跟蹤關鍵字出現的能力,節點的URL,節點的基礎URL,鏈接的數量,圖片的數量和字符的個數,以及節點是否符合搜索規則。<BR><BR>UrlTreeNodeRenderer是DefaultTreeCellRenderer界面的實現。UrlTreeNodeRenderer使節點包含匹配關鍵字顯示為藍色。UrlTreeNodeRenderer也為JtreeNodes加入了個性化的圖標。個性化的顯示通過覆蓋getTreeCellRendererComponent()方法(如下)實現。這個方法在樹中創建了一個Component對象。大部分的Component屬性通過子類來進行設置,UrlTreeNodeRenderer改變了文字的顏色(前景色)和圖標:<BR><BR><BR><BR>public Component getTreeCellRendererComponent(<BR>JTree tree,<BR>Object value,<BR>boolean sel,<BR>boolean expanded,<BR>boolean leaf,<BR>int row,<BR>boolean hasFocus) {<BR><BR>super.getTreeCellRendererComponent(<BR><BR>tree, value, sel,<BR>expanded, leaf, row,<BR>hasFocus);<BR>UrlTreeNode node = (UrlTreeNode)(((DefaultMutableTreeNode)value).getUserObject());<BR>if (node.isMatch()) // Set color<BR>setForeground(Color.blue);<BR>else <BR>setForeground(Color.black);<BR><BR>if(icon != null) // Set a custom icon<BR>{<BR>setOpenIcon(icon);<BR>setClosedIcon(icon);<BR>setLeafIcon(icon);<BR>}<BR>return this;<BR>}<BR><BR>5、 總結<BR><BR>這篇文章向你展示了如何創建網絡蜘蛛和控制它的用戶界面。用戶界面使用JTree來跟蹤蜘蛛的進展和記錄訪問過的站點。當然,你也可以使用Vector來記錄訪問過的站點和使用一個簡單的計數器來顯示進展。其他增強可以包含通過數據庫記錄關鍵字和站點的接口,增加通過多個入口搜索的能力,用大量或者很少的文字內容來顯現站點,以及為搜索引擎提供同義搜索的能力。<BR><BR>這篇文章中展示的Spider類使用遞歸調用搜索程序,當然,一個新蜘蛛的獨立線程可以在遇到每個鏈接時開始。這樣的好處是允許鏈接遠程URL并發執行,提高速度。然而記住那些叫做DefaultMutableTreeNode的JTree對象,不是線程安全的,所以程序員必須自己實現同步。 </p>
</div>
<div class="content">
<p align="center">[<a href=/data/2006/0921/article_1570.htm>1</a>] <b>[2]</b> </p>
</div>
<div class="content">
<p align="right">責任編輯 webmaster</p>
</div>
<div class="mainline"> </div>
<div class="maincolumn">
<div class="navadimg">
<script type="text/javascript"><!--
google_ad_client = "pub-4357927283882197";
google_ad_width = 728;
google_ad_height = 90;
google_ad_format = "728x90_as";
google_ad_type = "image";
google_ad_channel = "";
//--></script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
</div>
<div class="content">
<p align="left"><b>相關鏈接</b><br>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -