urk-小星星英语
“
网络蜘蛛
”
或者说<
/p>
“
网络爬虫
”
,
是一种能访问网站并跟踪链接的程序,
通过它,
可快速地画出一个网站所包含的网页地图信息。
本文主要讲述如何使用
Java
编程来构建一个
“
蜘
蛛
”
,我们会先以一个可复用的
蜘蛛类包装一个基本的
“
蜘蛛
”
,并在示例程序中演示如何创建一个特定的
“
蜘蛛
”
来扫描相关网站并找出死链接。
Java
语言在此非常适合构建一个
“
蜘蛛
”
程序,其内建了对
HTTP
协议的支持,通过它可以传输大部分的网页信息;其还内建了一个<
/p>
HTML
解析器,正是这两个原因使
Ja
va
语言成为本文构建
“
蜘蛛
”
程序的首选。
文章
后面例
1
的示例程序,将会扫描一个网站,并寻找死链接。使用
这个程序时需先输入一个
URL
并单击
“Begin”
按钮,程序开始之后,
“Begin”
按钮会变成
“Cancel”
按钮。
在程序扫描网站期间,会在
“Cancel”
按钮
之下显示进度,且在检查当前网页时,也会显示相关正常链接与死链接的数目,死链接将显示在程序底部的滚动文
本框中。单击
“Cancel”
按钮会停止扫描过程,
之后可以输入一个新的
URL
;
如果期间没有单击
“Cancel”
,
程序将会一直运行直到查找完所有网页,
此后,
“Ca
ncel”
按钮会再次变回
“Begin”
,
表示程序已停止。
下面将
p>
演示示例程序是如何与可复用
“Spider”
类交互
的,示例程序包含在例
1
的
CheckLinks
类中,
这个类实
现了
ISpiderReportable
接口,如例
2
所示,正是通过这个
接口,蜘蛛类才能与示例
程序相交互。在这个接口中,定义了三个方法:第一个方法是
“spiderFound
URL”
,它在每次程序定位一个
URL
时被调用,如果方法返回
true
,表
示程序应继续执行下去并找出其中的链接;第二个方法是
“spiderURLErr
or”
,它在每次程序检测
URL
导致
错误时被调用(如
“404
页面未找到
”
);第三个方法是
“spiderFoundEMail”
,它在每次发现电子邮件地址时被调用。有了这三个方法,
Sp
ider
类就能把相关信息反馈给创建它的程序了。
在
begin
方法被调用后,
< br>“
蜘蛛
”
就开始工作了;为允许
程序重绘其用户界面,
“
蜘蛛
”
是作为一个单独的线程启动的。点击
“Begin”
< br>按钮会开始这个后台线程,当后台线程运行
之后,又会调用
“CheckLinks”
类的
run
方法,而
run
方法是由
Spide
r
对象实例化时启动的,如下所示:
spider = new Spider(this);
();
base = new URL(t());
(base);
();
首先,
一个新的
Spider
对象被实例化<
/p>
,
在此,
需要传递一个
< br>“
ISpiderReportable
”
对象给
Spider
对象的构造函数
,
因为
“CheckLinks”
类实现了
“
ISpiderReportable
”
接口,
只需简单地把它作为当前对象(可由关
键字
this
表示)传递给构造函数即可
;其次,
在程序中维护了一个其访问过的
URL
列表
,
而
“
clear
”
方法的调用则是为了确保程序开
始时
URL
列表为空,程序开始运行之前必须添
加一个
URL
到它的待处理列表中,此时用户输入的
URL
则是添加到列表中的第一个,程序就由扫描这个网页开始,并找到与
这个起始
URL
相链接的其他页面;最
后,调用
“begin”
方法开始运行
“
蜘蛛
”
,这个方法直到
“
蜘蛛
”
工作完毕或用户取
消才会返回。
当
p>
“
蜘蛛
”
运行时,
可以调用由
“ISpiderReportable”
接口实现的三个方法来报告程序当前状态
,程序的大部分工作都是由
p>
“spiderFoundURL”
方法
来
完成的,
当
“
蜘蛛
”
发现一个新的
URL
时,它首先
检查其是否有效,如果这个
URL
导致一个错误,就会把它当作
一个死链接;如果链接有效,就会继续检查它是否在一个不同的服务器上,如果
链接在同
一服务器上,
“spiderFoundURL”
返回
true
,
表示
“
p>
蜘蛛
”
应继续跟踪这个
URL
并找出其他链接,
如果链接在另外的服务器上
,
就不会扫描是否还有其他链接,因为
这会导
致
“
蜘蛛
”
不
断地浏览
Internet
,寻找更多、更多的网站,所以,示
例程序只会查找用户指定网站上的链接。
构造
Spider
类
前面已经讲
了如何使用
Spider
类,请看例
3
中的代码。使用
Spider
类及
p>
“ISpiderReportable”
接口能方便地为某一程序
添加
“
蜘蛛
”
功能,下面继续讲解
Spider
类是怎样
工作的。
Spider
类必须保
持对其访问过的
URL
的跟踪
,
这样做的目的是为了确保
“
蜘蛛
”
不会访问同一
URL
一次
以上
;进一步来说,
“
蜘蛛
”
必须把
URL
分成三组
,
第一组存储在
“workloadW
aiting”
属性中,包含了一个未处理的
URL
列表,
“
蜘蛛
”
要访问的第一个
URL
也存在其中;第二组存储
在
“workloadProcessed”
中,它是
“
蜘蛛
”
已经处理过且
无需再次访问的
URL
;第三组存储在
“workloadError”
中,包含了发生错误的
URL
。
Begi
n
方法包含了
Spider
类的主循环
,其一直重复遍历
“workloadWaiting”
,并处理其中的每一个页面,当然我们也想到了,在这些页面被处理时,很可能有其他的
URL
添加到
“workloadWaiti
ng”
中,所以,
begin
方法一直
继续此过程,
直到调用
Spider
类
的
cancel
方法
,或
“
workloadWaiting”
中已不再剩有
URL
。这个过程如下:
cancel = false;
while (
!getWorkloadWaiting().isEmpty() && !cancel ) {
Object list[] =
getWorkloadW
aiting
().toArray();
for (
int i=0; (i<)&&!cancel; i++=
processURL<
/p>
((URL)list[i]);
}
当上述代码遍历
“workloadWaiting”
时,它
把每个需处理的
URL
都传递给
“
p>
processURL
”
方法,
而这个方法才是真正读取并解析
URL
中
HTML
信息的
。
读取并解析
HTML
Java
同时支持访问
URL
内容及解析
HTML
,而这正是
“
pr
ocessURL
”
方法要做的。在
J
ava
中读取
URL
内容相对还比较简
单,下面就是
“processURL”
方法实现此功能的代<
/p>
码:
URLConnection
connection = nnection();
if (
(tentType()!=null) &&!tentType().toLowerCase().sta
rtsWith(
getWorkloadWaiting().remove(url
);
getWorkloadProcessed().add(url);
log(
tentType() );
return;
}
首先,
为每个传递进来的变量
url
中存储的
URL
构造一个
“
U
RLConnection
”
对象
,<
/p>
因为网站上会有多种类型的文档,
而
“<
/p>
蜘蛛
”
只对那些包
含
HTML
,
尤其是基于文本的文档
感兴趣
。前述代码是为了确保文档内容以
“text/”
打头,如果文档类型为非文本,会从等待区移除此
URL
,
并
把它添加到已处理区,这也是为了保证不会再次
访问此
URL
。在对特定
URL
建立连接之后,接下来就要解析其内容了。下面的代码打开了
URL<
/p>
连接,并读取内容:
InputStream is = utStream();
Reader r = new InputStreamReader(is);
//
字符流
reader
现在,我们有了一个<
/p>
Reader
对象,可以用它来读取此
U
RL
的内容,对本文中的
“
蜘蛛
”
来说,只需简单地把其内容传递给
HTML
解析器就
可以了。本例中使用的
HTM
L
解析器为
Swing HTML
解析
器,其由
Java
内置,但由于
Jav
a
对
HTML
解析的支持力度不够,所
以必须重载一
个类来实现对
HTML
解
析器的访问,这就是为什么我们要调用
“
HTMLEditor
Kit
”
类中的
“
getParser
”
方法。但不幸的是,
Sun
公司把这个方法置
为
p
rotected
,唯一的解决办法就是创建自己的类并重载
“
getParser”
方法,并把它置为
public
,这由
“
HTMLParse
< br>”
类来实现,请看例
4
:
import .*;
public
class
HTMLParse extends
HTMLEditorKit {
public
getParser()
{
return ser();
}
}
这个类用在
< br>Spider
类的
“processURL”
方法中,我们也会看到,
Reader
对象会用于
读取
传递到
“”
中
网页的内容
:
p>
//
这个地方意思是,所谓的回调方法,就是供别人调用的,当
p>
parser
的对
reader
对象进行解析的时候,发现
标记
或者
文本
就会去调用
回调类
的方
法去执行相应的动作
reader
parse = new HTMLParse().getParser();
(
r
,new
Parser
(url),true);
请留意,
这里又构造了一个新的
Parser
类,
这个
Parser
类是
一个
Spider
类中的内嵌类,
而且
还是一个回调类,
它包含了对应于每种
HTML
tag
将要调用的特定方法。在本文中,我们只需关心两类回调函数,它们分
别对应
一个简单
tag
(即不带结束<
/p>
tag
的
tag
,如)和
一个开始
tag
,
这两类回调函数名为
“
handleSimple
Tag
”
和
“
handleStartTag
”
。因为每种的处理过程都是一
样的,所以
“
handleStartTag
< br>”
方法仅是简单地调
用
“
handleSimpleTag
”
,
而
“
handleSimpleTag
”
则会负责从文档中取出超链接
,
这些超链接将会用于定位
“
蜘蛛
< br>”
要访问的其他页面
。
在当前<
/p>
tag
被解析时,
“handleSim
pleTag”
会检查是否存在一个
“href”
或超文本引用:
String href =
(String)ribute();
if( (href==null) &&
(t==) )
href = (String)ribute();
if ( href==null )
return;
p>
如果不存在
“href”
属性,会继续检查
当前
tag
是否为一个
Frame
p>
,
Frame
会使用一个
< br>“src”
属性指向其他页面,一个典型的超链接通常为
以下形式:
上面链接中的
“href
”
属性指向其链接到的页面,
但是
“”
不是一个地址,
它只是指定了这个
We
b
服务器上一个页面上的某
处,这称为相对
URL
,
相对
URL
必须被解析为绝对
URL
,而这由以下代码完成:<
/p>
URL url = new URL(base,str);
这又会构造一个
URL
,
str
为相对
URL
,
p>
base
为这个
URL
上的页面,
这种形式的
URL
类构
造函数可构造一个绝对
URL
。在
UR
L
变为正
确的绝对形式之后,
通过检查
它是否在等待区,来确认此
URL
是否已经被处理过
。
如果此
URL
没有被处
理过,它会添加到等待区,之后,它会
像其他
URL
一样被处理。
相关的代码如下所示:
import .*;
import .*;
import .*;
import .*;
public class
CheckLinks extends implements
Runnable,ISpiderReportable {
/**
* The constructor. Perform setup here.
*/
public CheckLinks()
{
//{{INIT_CONTROLS
setTitle(
getContentPane().setLayout(null);
setSize(405,288);
setVisible(true);
t(
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(
getContentPane().add(current);
nds(12,72,384,12);
t(
getContentPane().add(goodLinksLabel);
nds(12,96,192,12);
t(
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(
spider =
new Spider(this);
();
base = new URL(t());
(base);
();
Runnable doLater = new Runnable()
{
public void run()
{
t(
}
};
Later(doLater);
backgroundThread=null;
} catch ( MalformedURLException e ) {
UpdateErrors err = new
UpdateErrors();
=
Later(err);
}
}
/**
* Called by the spider
when a URL is found. It is here
* that links are validated.
*
* @param
base The page that the link was found on.
* @param url The actual
link address.
*/
public boolean
spiderFoundURL(URL base,URL url)
{
UpdateCurrentStats cs = new
UpdateCurrentStats();
=
ng();
Later(cs);
if ( !checkLink(url) ) {
UpdateErrors err = new
UpdateErrors();
=
url+
Later(err);
badLinksCount++;
urk-小星星英语
urk-小星星英语
urk-小星星英语
urk-小星星英语
urk-小星星英语
urk-小星星英语
urk-小星星英语
urk-小星星英语
-
上一篇:2015年12月英语四级考试听力原文
下一篇:ibm整体解决方案