升值英文-delicatessen
网络爬虫实验报告
院系:国际教育学院
班级:互联网
12
—
< br>02
姓名:陈赛赛
学号:
541212010202
“
网络蜘
蛛
”
或者说
“
网络爬虫
”
,
是一种能访问网站并跟踪
链接的程序,
通过它,
可快
速地画出一
个网站所包含的网页地图信息。
本文主要讲述如何使用
Java
编程来构建一个
“
蜘
< br>蛛
”
,我们会先以一个可复用的蜘蛛类包装一个基本的<
/p>
“
蜘蛛
”
,并在
示例程序中演示如何创
建一个特定的
“
蜘蛛
”
来扫描相关网站并找出死链接。
Java
语言在此非常适合构建一个
“
蜘蛛
”
程序,其内建了对
HTTP
协议的支持,通过它可以
传输大部分的网页
信息;
其还内建了一个
HTML
解析器
,
正是这两个原因使
Java
语言成为
本文构建
“
蜘蛛
”
程序的首选。
文章后面例
1
的示例程序,将会扫描一个网站,并寻找死链接。使用这个程序时需
先输入
一个
URL
并单击
“Begin”
按钮,程序开始之后,
“Begin
”
按钮会变成
“Cancel”
按钮。
在程
序扫描网站期间,会在
“Cancel”
< br>按钮之下显示进度,且在检查当前网页时,也会显示相关
正常链接与死链接的数目
,死链接将显示在程序底部的滚动文本框中。单击
“Cancel”
按钮
会停止扫描过程,之后可以输入一个新的
URL
;如果期间没有单击
“Cancel”
,程序
将会一
直运行直到查找完所有网页,此后,
“Cancel”<
/p>
按钮会再次变回
“Begin”
,表示程
序已停止。
下面将演示示例程序是如何与可复用
“Spider”
类交互的,示例程序包含在例
1<
/p>
的
CheckLi
nks
类中,这个类实现了
ISpiderReportable
接口,如例
2
所示,正是通过这个接口,蜘
蛛类才能与示例程序相交互。在这个接口中,定义了三个方法:第一个方法是
“
spiderFou
ndURL”
,它在每次程序定位一个
p>
URL
时被调用,如果方法返回
true<
/p>
,表示程序应继续执
行下去并找出其中的链接;
< br>第二个方法是
“spiderURLError”
,
p>
它在每次程序检测
URL
导致
错误时被调用(如
“404
页面未找到
”
);第三个方法是
“spiderFoundE
Mail”
,它在每次发
现电子邮件地址时被调用。有了这三个
方法,
Spider
类就能把相关信息反馈给创建它的程
序了。
在
begi
n
方法被调用后,
“
蜘蛛
”
就开始工作了;为允许程序重绘其用户界面,
“<
/p>
蜘蛛
”
是作
为一
个单独的线程启动的。点击
“Begin”
按钮会开始这个后台
线程,当后台线程运行之后,
又会调用
“CheckLinks
”
类的
run
方法,而
run
方法是由
Spider
对象实例化时启动的,如
下所示:
spider
=
new
Spider(this);
();
base
=
new
URL(t());
(base);
();
首先,一个新的
Spider
对象被实例化,在此,需要传递一个
“ISpiderReportable”
对象给
Spider
对象的构造函数,
因为
“CheckL
inks”
类实现了
“ISpiderReportable”
接口,
只需简
单地把它作为当前对象(
可由关键字
this
表示)传递给构造函数即可;其次,在程序
中维
护了一个其访问过的
URL
列表,
而
“clear”
方法的调用则是为了确保程序开始时
URL
列表
为空,程序开始运行之前必须添加一
个
URL
到它的待处理列表中,此时用户输入的
URL
则是添加到列表中的第一个,程序就由扫描这个网页开始,并找到与这个
起始
URL
相链接
的其他页面;最后,
调用
“begin”
方法开始运行
“<
/p>
蜘蛛
”
,这个方法直到
< br>“
蜘蛛
”
工作完毕或用
户取消才会返回。
当
“
蜘蛛
”
运行时,
可以调用由
“ISpiderReportable”
接口
实现的三个方法来报告程序当前状
态,
程序的大部分工作都是由
“spiderFoundURL”
方法来完成的,
当
“
蜘蛛
”
发现一个新的
U
RL
时,它
首先检查其是否有效,如果这个
URL
导致一个错误,就会把它
当作一个死链接;
如果链接有效,
就会继续检查它是否在一个不
同的服务器上,
如果链接在同一服务器上,
“s
piderFoundURL”
返回
true
,表示
“
蜘蛛
”
应继续跟踪这个
URL
并找出其他链接,如果
链接
在另外的服务器上,就不会扫描是否还有其他链接,因为这会导致
< br>“
蜘蛛
”
不断地浏览
Inter
net
,寻找更多、更多的网站,所以
,示例程序只会查找用户指定网站上的链接。
构造
Spider
类
前面已
经讲了如何使用
Spider
类,请看例
3
中的代码。使用
Spider
类及
“ISpiderRepor
table”
接口能方便地为某一程序添加
“
蜘蛛
”
功能,下面继续讲解
Spider
类是怎样工作的。
Spider
类必
须保持对其访问过的
URL
的跟踪,
这
样做的目的是为了确保
“
蜘蛛
”
不会访问同
一
URL
一次以上;进一步来说,
“
蜘蛛
”
p>
必须把
URL
分成三组,第一组存储在
p>
“workload
Waiting”
属性
中,包含了一个未处理的
URL
列表,
“
蜘蛛
”
要访问的第一个
URL
也存在其
中;第二组存储在
< br>“workloadProcessed”
中,它是
“<
/p>
蜘蛛
”
已经处理过且无需再次访问的
p>
U
RL
;第三组存储在
“workloadError”
中,包含了发生错误的
U
RL
。
Begin
< br>方法包含了
Spider
类的主循环,
< br>其一直重复遍历
“workloadWaiting”
,
并处理其中
的每一个页面,当然我们也想到了,在这些页面被处
理时,很可能有其他的
URL
添加到
“
w
orkloadWaiting”
中,所以,
begin
方法一直继续此过程,直到调用
Spide
r
类的
cancel
方法,或
“workloadWaiting”
中已不再剩有
URL
。这个过程如下:
cancel
=
false;
while
(
!getWorkloadWaiting().isEmpty()
&&
!cancel
)
{
Object
list[]
=
getWorkloadWaiting().toArray();
for
(
int
i=0;
(i<)&&!CANCEL;
)
i++>
processURL((URL)list[i]);
}
当上述代码遍历
“workloa
dWaiting”
时,它把每个需处理的
URL
都传递给
“processURL”
方法,而这个方
法才是真正读取并解析
URL
中
HTM
L
信息的。
读取并解析
HTML
Java
同时支持访问
URL
内容及解析
HTML
,而这正是
“processURL”
p>
方法要做的。在
Jav
a
< br>中读取
URL
内容相对还比较简单,下面就是
“processURL”
方法实现此功能的代码:
URLConnection
connection
=
nnection();
if
(
(tentType()!=null)
&&!tentTy
pe().to
LowerCase().startsWith(
)
{
getWorkloadWaiting().remove(url);
getWorkloadProcessed().add(url);
log(
processing
because
content
type
is:
+
tentType()
);
return;
}
首先
,
为每个传递进来的变量
url
中存储
的
URL
构造一个
“URLConne
ction”
对象,
因为网
站上会有多
种类型的文档,而
“
蜘蛛
”
只对那些包含
HTML
,尤其是基于文本的文档感
兴趣。
前述代码是为了确保文档内容以
“text/”
打头,如果文档类型为非文本,会从等待区移除此
URL
,并把它添加到已处理区,这也是为了保证不会再次访问此
URL
。在对特定
URL
建立
连接
之后,接下来就要解析其内容了。下面的代码打开了
URL
连接
,并读取内容:
InputStream
is
=
utStream();
Reader
r
=
new
InputStreamReader(is);
现在,我们有了一个
Reader
对象,可以用
它来读取此
URL
的内容,对本文中的
“
蜘
蛛
”
来说
,
只需简单地把其内容传递给
HTML
解析器就可以了。
本例中使用的
HTML
解析器
为
Swing
HTML
p>
解析器,其由
Java
内置,但由于
Java
对
HTML
解析的支持力度不够,
所以必须重载一个类来实现对
HTML<
/p>
解析器的访问,这就是为什么我们要调用
“HTMLEdit
p>
orKit”
类中的
“getParser
”
方法。但不幸的是,
Sun
公司把这
个方法置为
protected
,唯一
的解决办法就是创建自己的类并重载
“getParser”
方
法,并把它置为
public
,这由
“
HTMLP
arse”
类来实现,请看例
4
:
import
.*;
public
class
HTMLParse
extends
HTMLEditorKit
{
public
getParser()
{
return
ser();
}
}
这个类用在
< br>Spider
类的
“processURL”
方法中,我们也会看到,
Reader
对象会用于
读取传递到
“”
中网页的内容:
parse
=
new
HTMLParse().getParser();
(r,new
Parser(url),true);
< br>请留意,这里又构造了一个新的
Parser
类,这个<
/p>
Parser
类是一个
Spider
p>
类中的内
嵌类,而且还是一个回调类,它包含了对应于每种
HTML
tag
将要调用的特定方法。在本<
/p>
文中,我们只需关心两类回调函数,它们分别对应一个简单
tag
(即不带结束
tag
的
tag
,
如
)
和一个开始
tag
,
这两类回调函数名为
“handleSimpleTag”
和
“handleStartTag”
。
因为每种的处理过程都是一样的,所以
“handleStartTag
”
方法仅是简单地调用
“handleSi
mpleTag”
,而
“handleSimpleTag
”
则会负责从文档中取出超链接,这些超链接将会用于
定位
p>
“
蜘蛛
”
要访问的
其他页面。在当前
tag
被解析时,
“
handleSimpleTag”
会检查是否存
在一个
“href”
或超文本引用:
String
href
=
(String)ribute();
if(
(href==null)
&&
(t==)
)
href
=
(String)ribute();
if
(
href==null
)
return;
如果不存在
“href”
属性,会继续检查当前
p>
tag
是否为一个
Frame
,
Frame
会使用一
个<
/p>
“src”
属性指向其他页面,一个典型的超链接通常为以下形式
:
上面链接中的
“href”
属性指向其链接到的页面,但是
“”
不是一个
地
址,它只是指定了这个
Web
服务器
上一个页面上的某处,这称为相对
URL
,相对
URL
必
须被解析为绝对
UR
L
,而这由以下代码完成:
URL
url
=
new
URL(base,str);
这
又会构造一个
URL
,
str
为相对
URL
,
bas
e
为这个
URL
上的页面,这种形式的
U
RL
类构造函数可构造一个绝对
p>
URL
。在
URL
变为正确的绝对形式之后,通过检查它是否
在等待区,
来确认此
URL
是否已经被处理过。
如果此
p>
URL
没有被处理过,
它会添加到等待
p>
区,之后,它会像其他
URL
一样被处理。
相关的代码如下所示:
import
.*;
import
.*;
import
.*;
import
.*;
public
class
CheckLinks
extends
implements
Runnable,ISpiderReportable
{
/**
*
The
constructor.
Perform
setup
here.
*/
public
CheckLinks()
{
//{{INIT_CONTROLS
setTitle(
Broken
Links
getContentPane().setLayout(null);
setSize(405,288);
setVisible(true);
t(
a
URL:
getContentPane().add(label1);
nds(12,12,84,12);
t(
ionCommand(
getContentPane().add(begin);
nds(12,36,84,24);
getContentPane().add(url);
nds(108,36,288,24);
oscrolls(true);
izontalScrollBarPolicy(.
NTAL_SCROLLBAR_ALWAYS);
ticalScrollBarPolicy(.
AL_SCROLLBAR_ALWAYS);
que(true);
getContentPane().add(errorScroll);
nds(12,120,384,156);
table(false);
wport().add(errors);
nds(0,0,366,138);
t(
Processing:
getContentPane().add(current);
nds(12,72,384,12);
t(
Links:
0
getContentPane().add(goodLinksLabel);
nds(12,96,192,12);
t(
Links:
0
getContentPane().add(badLinksLabel);
nds(216,96,96,12);
//}}
//{{INIT_MENUS
//}}
//{{REGISTER_LISTENERS
SymAction
lSymAction
=
new
SymAction();
ionListener(lSymAction);
//}}
}
/**
*
Main
method
for
the
application
*
*
@param
args
Not
used
*/
static
public
void
main(String
args[])
{
(new
CheckLinks()).setVisible(true);
}
/**
*
Add
notifications.
*/
public
void
addNotify()
{
//
Record
the
size
of
the
window
prior
to
calling
parent's
//
addNotify.
Dimension
size
=
getSize();
ify();
if
(
frameSizeAdjusted
)
return;
frameSizeAdjusted
=
true;
//
Adjust
size
of
frame
according
to
the
insets
and
menu
bar
Insets
insets
=
getInsets();
ar
menuBar
=
getRootPane().getJMenuBar();
int
menuBarHeight
=
0;
if
(
menuBar
!=
null
)
menuBarHeight
=
ferredSize().height;
setSize(
+
+
,
+
+
+
menuBarHeight);
}
//
Used
by
addNotify
boolean
frameSizeAdjusted
=
false;
//{{DECLARE_CONTROLS
label1
=
new
();
/**
*
The
begin
or
cancel
button
*/
n
begin
=
new
n();
/**
*
The
URL
being
processed
*/
ield
url
=
new
ield();
/**
*
Scroll
the
errors.
*/
lPane
errorScroll
=
new
lPane();
/**
*
A
place
to
store
the
errors
created
*/
rea
errors
=
new
rea();
current
=
new
();
goodLinksLabel
=
new
();
badLinksLabel
=
new
();
//}}
//{{DECLARE_MENUS
//}}
/**
*
The
background
spider
thread
*/
protected
Thread
backgroundThread;
/**
*
The
spider
object
being
used
*/
protected
Spider
spider;
/**
*
The
URL
that
the
spider
began
with
*/
protected
URL
base;
/**
*
How
many
bad
links
have
been
found
*/
protected
int
badLinksCount
=
0;
/**
*
How
many
good
links
have
been
found
*/
protected
int
goodLinksCount
=
0;
/**
*
Internal
class
used
to
dispatch
events
*
*
@author wuhailin
*
@version
1.0
*/
class
SymAction
implements
Listener
{
public
void
actionPerformed(Event
event)
{
Object
object
=
rce();
if
(
object
==
begin
)
begin_actionPerformed(event);
}
}
/**
*
Called
when
the
begin
or
cancel
buttons
are
clicked
*
*
@param
event
The
event
associated
with
the
button.
*/
void
begin_actionPerformed(Event
event)
{
if
(
backgroundThread==null
)
{
el(
backgroundThread
=
new
Thread(this);
();
goodLinksCount=0;
badLinksCount=0;
}
else
{
();
}
}
/**
*
Perform
the
background
thread
operation.
This
method
*
actually
starts
the
background
thread.
*/
public
void
run()
{
try
{
t(
升值英文-delicatessen
升值英文-delicatessen
升值英文-delicatessen
升值英文-delicatessen
升值英文-delicatessen
升值英文-delicatessen
升值英文-delicatessen
升值英文-delicatessen
-
上一篇:黑屏指令
下一篇:链轮轴设计.(DOC)