搜索引擎研究---网络蜘蛛程序算法相关资料
1、解析HTML文件
这里有两个为了查找A HREF来解析HTML文件方法——一个麻烦的方法和一个简单的方法。
如果你选择麻烦的方法,你将使用Java的StreamTokenizer类创建你自己的解析规则。使用这些技术,你必须为StreamTokenizer对象指定单词和空格,接着去掉<和>符号来查找标签,属性,在标签之间分割文字。太多的工作要做。
简单的方法是使用内置的ParserDelegator类,一个HTMLEditorKit.Parser抽象类的子类。这些类在Java文档中没 有完善的文档。使用ParserDelegator有三个步骤:首先为你的URL创建一个InputStreamReader对象,接着创建一个 ParserCallback对象的实例,最后创建一个ParserDelegator对象的实例并调用它的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()接受一个InputStreamReader,一个ParseCallback对象实例和一个指定CharSet标签是否忽略的标志。 parse()方法接着读和解码HTML文件,每次完成解码一个标签或者HTML元素后调用ParserCallback对象的方法。
在示例代码中,我实现了ParserCallback作为Spider的一个内部类,这样就允许ParseCallback访问Spider的方法和属性。基于ParserCallback的类可以覆盖下面的方法:
■ handleStartTag():当遇到起始HTML标签时调用,比如>A <
■ handleEndTag():当遇到结束HTML标签时调用,比如>/A<
■ handleSimpleTag():当遇到没有匹配结束标签时调用
■ handleText():当遇到标签之间的文字时调用
在示例代码中,我覆盖了handleSimpleTag()以便我的代码可以处理HTML的BASE和IMG标签。BASE标签告诉当处理相关的URL引 用时使用什么URL。如果没有BASE标签出现,那么当前URL就用来处理相关的引用。HandleSimpleTag()接受三个参数,一个 HTML.Tag对象,一个包含所有标签属性的MutableAttributeSet,和在文件中的相应位置。我的代码检查标签来判断它是否是一个 BASE对象实例,如果是则HREF属性被提取出来并保存在页面的数据节点中。这个属性以后在处理链接站点的URL地址中被用到。每次遇到IMG标签,页 面图片数就被更新。
我覆盖了handleStartTag以便程序可以处理HTML的A和TITLE标签。方法检查t参数是否是一个事实上的A标签,如果是则HREF属性将被提取出来。
fixHref()被用作清理大量的引用(改变反斜线为斜线,添加缺少的结束斜线),链接的URL通过使用基础URL和引用创建URL对象来处理。 接着递归调用searchWeb()来处理链接。如果方法遇到TITLE标签,它就清除存储最后遇到文字的变量以便标题的结束标记具有正确的值(有时网页 的title标签之间没有标题)。
我覆盖了handleEndTag()以便HTML的TITLE结束标记可以被处理。这个结束标记指出前面的文字(存在lastText中)是页面 的标题文字。这个文字接着存在页面的数据节点中。因为添加标题信息到数据节点中将改变树中数据节点的显示,nodeChanged()方法必须被调用以便 树可以更新。
我覆盖了handleText()方法以便HTML页面的文字可以根据被搜索的任意关键字或者短语来检查。HandleText()接受一个包含一 个子符数组和该字符在文件中位置作为参数。HandleText()首先将字符数组转换成一个String对象,在这个过程中全部转换为大写。接着在搜索 列表中的每个关键字/短语根据String对象的indexof()方法来检查。如果indexof()返回一个非负结果,则关键字/短语在页面的文字中 显示。如果关键字/短语被显示,匹配被记录在匹配列表的节点中,统计数据被更新:
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;
}
}
}
}