解析HTML文件 這里有兩個(gè)為了查找A HREF來(lái)解析HTML文件方法——一個(gè)麻煩的方法和一個(gè)簡(jiǎn)單的方法。 如果你選擇麻煩的方法,你將使用Java的StreamTokenizer類創(chuàng)建你自己的解析規(guī)則。使用這些技術(shù),你必須為StreamTokenizer對(duì)象指定單詞和空格,接著去掉<和>符號(hào)來(lái)查找標(biāo)簽,屬性,在標(biāo)簽之間分割文字。太多的工作要做。 簡(jiǎn)單的方法是使用內(nèi)置的ParserDelegator類,一個(gè)HTMLEditorKit.Parser抽象類的子類。這些類在Java文檔中沒(méi)有完善的文檔。使用ParserDelegator有三個(gè)步驟:首先為你的URL創(chuàng)建一個(gè)InputStreamReader對(duì)象,接著創(chuàng)建一個(gè)ParserCallback對(duì)象的實(shí)例,最后創(chuàng)建一個(gè)ParserDelegator對(duì)象的實(shí)例并調(diào)用它的public方法parse(): UrlTreeNode newnode = new UrlTreeNode(url); // Create the data node InputStream in = url.openStream(); // Ask the URL object to create an input stream InputStreamReader isr = new InputStreamReader(in); // Convert the stream to a reader DefaultMutableTreeNode treenode = addNode(parentnode, newnode); SpiderParserCallback cb = new SpiderParserCallback(treenode); // Create a callback object ParserDelegator pd = new ParserDelegator(); // Create the delegator pd.parse(isr,cb,true); // Parse the stream isr.close(); // Close the stream parse()接受一個(gè)InputStreamReader,一個(gè)ParseCallback對(duì)象實(shí)例和一個(gè)指定CharSet標(biāo)簽是否忽略的標(biāo)志。parse()方法接著讀和解碼HTML文件,每次完成解碼一個(gè)標(biāo)簽或者HTML元素后調(diào)用ParserCallback對(duì)象的方法。 在示例代碼中,我實(shí)現(xiàn)了ParserCallback作為Spider的一個(gè)內(nèi)部類,這樣就允許ParseCallback訪問(wèn)Spider的方法和屬性。基于ParserCallback的類可以覆蓋下面的方法: ■ handleStartTag():當(dāng)遇到起始HTML標(biāo)簽時(shí)調(diào)用,比如>A < ■ handleEndTag():當(dāng)遇到結(jié)束HTML標(biāo)簽時(shí)調(diào)用,比如>/A< ■ handleSimpleTag():當(dāng)遇到?jīng)]有匹配結(jié)束標(biāo)簽時(shí)調(diào)用 ■ handleText():當(dāng)遇到標(biāo)簽之間的文字時(shí)調(diào)用 在示例代碼中,我覆蓋了handleSimpleTag()以便我的代碼可以處理HTML的BASE和IMG標(biāo)簽。BASE標(biāo)簽告訴當(dāng)處理相關(guān)的URL引用時(shí)使用什么URL。如果沒(méi)有BASE標(biāo)簽出現(xiàn),那么當(dāng)前URL就用來(lái)處理相關(guān)的引用。HandleSimpleTag()接受三個(gè)參數(shù),一個(gè)HTML.Tag對(duì)象,一個(gè)包含所有標(biāo)簽屬性的MutableAttributeSet,和在文件中的相應(yīng)位置。我的代碼檢查標(biāo)簽來(lái)判斷它是否是一個(gè)BASE對(duì)象實(shí)例,如果是則HREF屬性被提取出來(lái)并保存在頁(yè)面的數(shù)據(jù)節(jié)點(diǎn)中。這個(gè)屬性以后在處理鏈接站點(diǎn)的URL地址中被用到。每次遇到IMG標(biāo)簽,頁(yè)面圖片數(shù)就被更新。 我覆蓋了handleStartTag以便程序可以處理HTML的A和TITLE標(biāo)簽。方法檢查t參數(shù)是否是一個(gè)事實(shí)上的A標(biāo)簽,如果是則HREF屬性將被提取出來(lái)。 fixHref()被用作清理大量的引用(改變反斜線為斜線,添加缺少的結(jié)束斜線),鏈接的URL通過(guò)使用基礎(chǔ)URL和引用創(chuàng)建URL對(duì)象來(lái)處理。接著遞歸調(diào)用searchWeb()來(lái)處理鏈接。如果方法遇到TITLE標(biāo)簽,它就清除存儲(chǔ)最后遇到文字的變量以便標(biāo)題的結(jié)束標(biāo)記具有正確的值(有時(shí)網(wǎng)頁(yè)的title標(biāo)簽之間沒(méi)有標(biāo)題)。 我覆蓋了handleEndTag()以便HTML的TITLE結(jié)束標(biāo)記可以被處理。這個(gè)結(jié)束標(biāo)記指出前面的文字(存在lastText中)是頁(yè)面的標(biāo)題文字。這個(gè)文字接著存在頁(yè)面的數(shù)據(jù)節(jié)點(diǎn)中。因?yàn)樘砑訕?biāo)題信息到數(shù)據(jù)節(jié)點(diǎn)中將改變樹(shù)中數(shù)據(jù)節(jié)點(diǎn)的顯示,nodeChanged()方法必須被調(diào)用以便樹(shù)可以更新。 我覆蓋了handleText()方法以便HTML頁(yè)面的文字可以根據(jù)被搜索的任意關(guān)鍵字或者短語(yǔ)來(lái)檢查。HandleText()接受一個(gè)包含一個(gè)子符數(shù)組和該字符在文件中位置作為參數(shù)。HandleText()首先將字符數(shù)組轉(zhuǎn)換成一個(gè)String對(duì)象,在這個(gè)過(guò)程中全部轉(zhuǎn)換為大寫(xiě)。接著在搜索列表中的每個(gè)關(guān)鍵字/短語(yǔ)根據(jù)String對(duì)象的indexof()方法來(lái)檢查。如果indexof()返回一個(gè)非負(fù)結(jié)果,則關(guān)鍵字/短語(yǔ)在頁(yè)面的文字中顯示。如果關(guān)鍵字/短語(yǔ)被顯示,匹配被記錄在匹配列表的節(jié)點(diǎn)中,統(tǒng)計(jì)數(shù)據(jù)被更新: public class SpiderParserCallback extends HTMLEditorKit.ParserCallback { /** * Inner class used to html handle parser callbacks */ public class SpiderParserCallback extends HTMLEditorKit.ParserCallback { /** URL node being parsed */ private UrlTreeNode node; /** Tree node */ private DefaultMutableTreeNode treenode; /** Contents of last text element */ private String lastText = ""; /** * Creates a new instance of SpiderParserCallback * @param atreenode search tree node that is being parsed */ public SpiderParserCallback(DefaultMutableTreeNode atreenode) { treenode = atreenode; node = (UrlTreeNode)treenode.getUserObject(); } /** * Handle HTML tags that don‘t have a start and end tag * @param t HTML tag * @param a HTML attributes * @param pos Position within file */ public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) { if(t.equals(HTML.Tag.IMG)) { node.addImages(1); return; } if(t.equals(HTML.Tag.BASE)) { Object value = a.getAttribute(HTML.Attribute.HREF); if(value != null) node.setBase(fixHref(value.toString())); } } /** * Take care of start tags * @param t HTML tag * @param a HTML attributes * @param pos Position within file */ public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) { if(t.equals(HTML.Tag.TITLE)) { lastText=""; return; } if(t.equals(HTML.Tag.A)) { Object value = a.getAttribute(HTML.Attribute.HREF); if(value != null) { node.addLinks(1); String href = value.toString(); href = fixHref(href); try{ URL referencedURL = new URL(node.getBase(),href); searchWeb(treenode, referencedURL.getProtocol()+"://"+referencedURL.getHost()+referencedURL.getPath()); } catch (MalformedURLException e) { messageArea.append(" Bad URL encountered : "+href+"\n\n"); return; } } } } /** * Take care of start tags * @param t HTML tag * @param pos Position within file */ public void handleEndTag(HTML.Tag t, int pos) { if(t.equals(HTML.Tag.TITLE) && lastText != null) { node.setTitle(lastText.trim()); DefaultTreeModel tm = (DefaultTreeModel)searchTree.getModel(); tm.nodeChanged(treenode); } } /** * Take care of text between tags, check against keyword list for matches, if * match found, set the node match status to true * @param data Text between tags * @param pos position of text within Webpage */ public void handleText(char[] data, int pos) { lastText = new String(data); node.addChars(lastText.length()); String text = lastText.toUpperCase(); for(int i = 0; i < keywordList.length; i++) { if(text.indexOf(keywordList) >= 0) { if(!node.isMatch()) { sitesFound++; updateStats(); } node.setMatch(keywordList); return; } } } } |
引用 報(bào)告 回復(fù) ![]() |
admin 管理員 ![]() ![]() ![]() UID 1 精華 0 積分 0 帖子 418 閱讀權(quán)限 200 注冊(cè) 2007-5-8 狀態(tài) 離線 |
|
聯(lián)系客服