四、网络蜘蛛的程序构架
用ASP构造网络蜘蛛
那么如何用ASP构建网络蜘蛛呢?答案是:Internet transfer control (ITC)。这个由 微软提供的控件,将使你能够通过ASP程序访问Internet资源。你可以用ITC搜寻Web页面,访问FTP服务器,甚 至可以发送邮件标题。在本文里,我们将着重讨论搜寻Web页面的功能。
有几个缺陷必须先说明一下。第一,ASP无权访问Windows的注册表,这就使某些ITC正常存储的常量和数 值不可用。通常你可以通过设置ITC为“不使用默认值”来解决这个问题,这就需要你在运行过程中指明每一 次的值。
另一个更严重的问题是关于许可证书的。由于ASP不具备调用License Manager(一项Windows中的功 能,可以保证组件和控件的合法使用)的功能,那么当License Manager检查当前组件的密钥密码,并将 其与Windows注册表进行比较后,如果发现它们不同,该组件将不会工作。因此,当你想把ITC配置到另一台没 有所需密钥的计算机上时,将导致ITC崩溃。解决的办法之一是将ITC捆绑到另一个VB组件中,由VB组件复制 ITC的路径和工具,从而进行配置。这项工作很麻烦,但不幸的是,它是必不可少的。
下面是一些例子:
你可以用下面的编码建立ITC:
set Inet1 = CreateObject("InetCtls.Inet")
Inet1.protocol = 4 'HTTP
Inet1.accesstype = 1 'Direct connection to internet
Inet1.requesttimeout = 60'in seconds
Inet1.URL = strURL
strHTML = Inet1.OpenURL'grab HTML page
现在strHTML保存着strURL指向的整个页面的HTML内容。要建立一个常规网络蜘蛛,你现在只需要调用 instr() 功能来看看你寻找的串是否在当前位置即可。你也可以按照href标记寻找,解析当前的 URL,然后把它设置到Internet 控件的属性中去,接着再继续打开另一个页面。用来查看所有链接的最 好方法是使用递归。
要注意的是,尽管这种方法很易于实行,却不是非常准确和强大。今天的许多搜索引擎都可以进行额外的 逻辑检查,例如计算一个页面中某一短语重复的次数,相关字词的近似程度等,有些甚至可以用来判断所搜寻 的语段与上下文的关系。
用VB构造网络蜘蛛
蜘蛛程序网站层次及其工作原理描述:
序号网站层次父序号
1http://www.netfox.cn/ 10
2http://www.sina.com.cn/21
3http://www.cnnic.cn/21
4http://www.baidu.cn/32
5http://www.yahoo.cn/32
蜘蛛程序首先从层次1(http://www.netfox.cn/)开始提取所有的网站链接,把所有网站链接记录到数据库(或者大数组等),并把这些网站链接标识为层次2;
当把层次2全部记录到数据库后即硬愦中顺序为第一的(这里指序号为2的网站)网站链接开始提取其下面的的所有链接记录到数据库,并把这些网站链接标识为层次3;然后依次把层次为2的网站的所有链接记录到数据库,同时把他们的层次标识为层次3;
当层次3全部记录数据库后,开始从层次3中顺序为第一的网站链接开始提取,依次类推即可!
注意:程序要保留一个指针记录当前正在操作的序号!另外您也可以增加一个父序号字段来记录他们之间的继承关系!
层次1表示为网络种子;我们这里把网络种子放在第一层,根据需要您可以设置一个或者多个网络种子,实际上我们通过这个层次图可以很显然地看出来,低层次的网址就是高层次的网络种子。也就是说只要有一个或者几个网络种子,我们就可以通过他们的链接找到更多的网络种子。只要这样我们的蜘蛛才能永远地运行下去!
层次2是通过层次1(即网络种子)抓取到的链接;
层次3是通过层次2抓取到的链接;
依次类推,构成一棵大树!
蜘蛛程序关键代码:
这里使用VB实现核心部分的代码,当然您也可以很简单地转换成其他语言代码。在这里了为了简单起见,我们这里不对数据库操作,我们建立一个二维数组存放我们的网址!
Dim Web(4,10000)‘//建立数组
Dim Pointer‘//建立指针,记录当前种子
Dim Id ‘//建立序号,记录当前抓区网站的序号
Dim Layer‘//建立层次,记录当前正在运行种子的层次
Dim Running‘//建立是否运行的标志,
Private Function NewworkSeed_Set() As Boolean ‘//用来设置网络种子,为演示方便我们把种子放在数组,
'//当然您也可以根据需要把他们直接放到数据库中
Web(0,0) = 1 ‘//序号
Web(1,0) = “ http://www.netfox.cn/” ‘//网站
Web(2,0) = 1 ‘//层次
Web(3,0) = 0 ‘//父序号,0表示为网络原始种子
Web(4,0) = “奈福网络”
‘//当然这里可以设置多个网络原始种子
Web(0,1) = 1
Web(1,1) = “ http://www.aspfaq.cn/”
Web(2,1) = 1
Web(3,1) = 0
Web(4,1) = “asp技术站”
‘//设置网络种子后,记录种子序号开始后的序号,这里设置了2个种子,所以Id=2开始
Id = 2
End Function
Private Sub Spider_Work()‘//蜘蛛工作程序,抓取网站并记录到数组
‘//根据需要可以把他们放到数据库中
Dim A
For Each A In WebBrowser.Document.All
If UCase(A.tagName) = "A" Then
If IsValidWeb(A.href) Then
Id = Id + 1
Web(0, Id) = Id‘//记录当前网站的序号
Web(1, Id) = A.href ‘//记录当前网站
Web(2, Id) = Layer ‘//记录当前网站的层次
If Web(2,Pointer)<> Layer Then Layer = Layer + 1‘//当指针层次与当前层次不同的话
‘//则说明层次已经发生了增加
Web(3, Id) = Pointer ‘//记录当前网站的父序号
Web(4,Id) = A.innerText‘//记录当前网站的名称
End If
End If
Next
Pointer = Pointer + 1
WebBrowser.Navigate Web(1, Pointer-1) ‘//抓取当前种子完毕后,自动跳转到下一个种子
If Running = False Then‘//运行为否,退出运行
Exit Sub
End If
End Sub
Private Function Spider_Init() As Boolean‘//蜘蛛程序初始化函数
Pointer = 1 ‘//指针设置为1,表示从第一个序号开始运行
Id = 2‘//序号设置为2,以后可以读取记录
Layer = 0‘//层次设置为0,表示蜘蛛第一次运行
‘//以上指针,序号,层次都可以记录并且方便以后读取
If IsValidWeb(Web(1, Pointer-1)) Then‘//判断种子是否正确,如果正确初始化成功,否则失败
Running = True
Spider_Init = True
WebBrowser.Navigate Web(1, Pointer-1)
Else
Running = False
Spider_Init = False
Exit Function
End If
End Function
Private Sub WebBrowser_DocumentComplete(ByVal pDisp As Object, URL As Variant) ‘//WebBrowser控件
Call Spider_Work()
End Sub
Private Function IsValidWeb(_href) As Boolean ‘//判断是否是cn域名函数
‘//通过该函数可以实现抓取指定网站或数据
If InStr(_href, " http://www.") > 0 And InStr(_href, ".cn/") > 0 And Len(_href) < 60 Then
IsValidWeb = True
Else
IsValidWeb = False
End If
End Function
Private Sub InitCommand_Click()‘//Init初始化 命令控件
If Spider_Init() Then
Msgbox “蜘蛛初始化成功并开始运行了”
Else
Msgbox “蜘蛛初始化失败”
End If
End Private
Private Sub StopCommand_Click()‘//Stop停止 命令控件
Running = False ‘//停止运行
End Private
Private Sub RunCommand_Click() ‘//Run运行 命令控件
Running = True‘//继续运行
Call Spider_Work()‘//蜘蛛运行主程序
End Private
特定网络蜘蛛
相对的,一个特定网络蜘蛛要复杂一些。如我们早先提到的,一个特定网络蜘蛛会搜寻一个页面的特定部 分,因而要求预先知道该部分相关的情况。让我们先看看下面的HTML:
<HTML>
<HEAD>
<TITLE>My News Page</TITLE>
<META Name="keywords" Content="News, headlines">
<META Name="descr iption" Content="The current news headlines.">
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF3300 "VLINK="#CC0000" ALINK="#0000FF">
<p><h3>Headlines&l t;/h3></p>
<!--put headlines here-->
<a href="/news/8094.asp _fcksavedurl=""/news/8094.asp" ">Stocks prices fall</a><a href="/news/8095.asp">New movies today</a><ahref="/news/8096.asp">Bush and&nb sp;Gore to debate tonight</a><a href="/news/8097.asp"> Fall TV lineup</a>
<!--end headlines-->
</BODY>
</HTML>
在这个页面内,我们只关心位于“put headlines here”和 “end headlines”这 两个标记之间的东西。你可以构建一个只返回该区域查找结果的功能设置:
Function GetText(strText, strStartTag, strEndTag)
dim intStart
intStart = instr(1, strText, strStartTag, vbtextcompare)
if intStart then
intStart = intStart + len(strStartTag)
intEnd = InStr(intStart + 1, strText, strEndTag, vbtextcompar e)
GetText = Mid(strText, intStart + 1, intEnd - intStart&n bsp;- 1)
else
GetText = " "
end if
End Function
按照上面构建ITC控件的例子,你可以很容易地将strHTML中的“ <!--put headlines here-->”和 “<!--end headlines-->”作为参数传 送到GetText中。
要注意,用于开始和结束的标记都不一定要是实际的HTML专用标记——它们可以是你想使用的任何文本界 定符。在通常情况下,你不容易找到好的HTML标记来界定搜寻区域。你只能使用比较方便称手的标记——例如 ,你的首尾标记可以分别如下:
strStartTag = "/td><td><font face="arial" size=&q uot;2"><p><b><u>"
strEndTag = "<p></td></tr><tr><td><ums>&quo t;
一定要确定搜索的是HTML页中比较独特的标识,这样你才可以准确地获得你需要的东西。你也可以按照你 所返回的文本部分中的链接进行搜寻,不过如果你不知道那些页面的格式,你的网络蜘蛛将无功而返。