TinySpider是一个基于Tiny HtmlParser的网络数据抓取框架。
Maven引用坐标:
1
2
3
4
5
|
<dependency>
<groupId>org.tinygroup</groupId>
<artifactId>tinyspider</artifactId>
<version>
0.0
.
12
</version>
</dependency>
|
网络爬虫,一般用在全文检索或内容获取上面。
Tiny框架对此也做了有限的支持,虽然功能不多,但是想做全文检索或从网页上获取数据也是非常方便的。
框架特性
- 强大的节点过滤能力
- 支持post与get两种数据提交方式
- 避免网页重复处理功能
- 支持多站点内容抓取功能
- 较强的Html容错处理
框架设计
网络爬虫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
public
interface
Spinder {
/**
* 添加站点访问器
*
* @param siteVisitor
*/
void
addSiteVisitor(SiteVisitor siteVisitor);
/**
* 添加监视器
*
* @param watcher
*/
void
addWatcher(Watcher watcher);
/**
* 处理url
*
* @param url
*/
void
processUrl(String url);
/**
* 处理url
* @param url
* @param parameter
*/
void
processUrl(String url, Map<String, Object> parameter);
/**
* 设置URL仓库
*
* @param urlRepository
*/
void
setUrlRepository(UrlRepository urlRepository);
}
|
一个爬虫,至少需要包含一个站点访问器,站点访问器用于对URL进行访问。如果没有匹配的站点访问器,URL将被忽略,不做继续处理。
一个爬虫至少需要包含一个监视器,监视器用于对URL中的内容进行过滤,并对命中的节点进行处理。如果没有监视器,爬虫爬回的内容就没有任何价值。
一个爬虫至少需要一个Url仓库,Url仓库用于对ur进行判断,是否已经抓取并处理过。如果没有url仓库,将无法判断url是否处理过,在非常多的时候,会造成死循环,无法退出。
当然,一个爬虫,也必须能够对url进行处理。
网站访问者
由于一个爬虫可以有多个站点访问器,因此,需要有isMatch方法告诉爬虫是否应该由自己进行处理。
访问方式,可以设置是通过get还是post方式获取数据。
URL仓库
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
public
interface
UrlRepository {
/**
* 返回url是否已经在仓库中存在
*
* @param url
* @return
*/
boolean
isExist(String url);
/**
* 返回url是否已经在仓库中存在,带有参数
*
* @param url
* @param parameter
* @return
*/
boolean
isExist(String url, Map<String, Object> parameter);
/**
* 如果不存在,则放放,如果已经存在,则替换
*
* @param url
* @param content
*/
void
putUrlWithContent(String url, String content);
/**
* 如果不存在,则放放,如果已经存在,则替换
*
* @param url
* @param parameter
* @param content
*/
void
putUrlWithContent(String url, Map<String, Object> parameter,
String content);
/**
* 如果存在,则返回内容;如果不存在,则抛出运行时异常
*
* @param url
* @return
*/
String getContent(String url);
/**
* 如果存在,则返回内容;如果不存在,则抛出运行时异常
*
* @param url
* @param parameter
* @return
*/
String getContent(String url, Map<String, Object> parameter);
}
|
url仓库用于对url及其内容进行管理。由于方法都简单明了,因此不做更多介绍。
监视器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public
interface
Watcher {
/**
* 设置节点过滤器
*
* @param filter
*/
void
setNodeFilter(NodeFilter<HtmlNode> filter);
/**
* 获取节点过滤器
*
* @return
*/
NodeFilter<HtmlNode> getNodeFilter();
/**
* 添加处理器
*
* @param processor
*/
void
addProcessor(Processor processor);
/**
* 获取处理器列表
*
* @return
*/
List<Processor> getProcessorList();
}
|
一个监视器,必须一个节点过滤器,但是可以有多个处理器。
处理器
1
2
3
4
5
6
7
8
|
public
interface
Processor {
/**
* 处理节点
*
* @param node
*/
void
process(HtmlNode node);
}
|
处理器非常简单, 就是对命中的节点进行处理即可。
示例
通过访问[http://www.oschina.net/question?catalog=1]可以看到,里面有许多技术问答的问题。
下面我们就来编写一段程序来把这些标题打出来:
编写爬虫
1
2
3
4
5
6
7
8
9
10
11
|
public
static
void
main(String[] args) {
Spinder spinder =
new
SpinderImpl();
Watcher watcher =
new
WatcherImpl();
watcher.addProcessor(
new
PrintOsChinaProcessor());
QuickNameFilter<HtmlNode> nodeFilter =
new
QuickNameFilter<HtmlNode>();
nodeFilter.setNodeName(
"div"
);
nodeFilter.setIncludeAttribute(
"class"
,
"qbody"
);
watcher.setNodeFilter(nodeFilter);
spinder.addWatcher(watcher);
spinder.processUrl(
"http://www.oschina.net/question?catalog=1"
);
}
|
编写处理器
1
2
3
4
5
6
7
8
9
10
11
|
public
class
PrintOsChinaProcessor
implements
Processor {
public
void
process(HtmlNode node) {
FastNameFilter<HtmlNode> filter =
new
FastNameFilter<HtmlNode>(node);
filter.setNodeName(
"h2"
);
filter.setIncludeNode(
"a"
);
HtmlNode h3 = filter.findNode();
if
(h3 !=
null
) {
System.out.println(h3.getSubNode(
"a"
).getContent());
}
}
}
|
运行结果
输出结果可能与结果不相同,因为数据是一直在变化的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
约瑟夫环问题,一段代码求讲解
求推荐一款分享,回复的前端开源js
MySQL什么情况使用MyISAM,什么时候使用InnoDB?
phpstorm中使用搜狗输入中文出现乱行问题怎样解决?
Android中如何实现快播中娱乐风向标的效果
使用java做手机后台开发!
Chrome
29
的alert对话框好漂亮,有木有啊有木有
Eclipse+ADT+Android环境配置问题
关于android holderview的疑惑
蛋疼 从一个公司到另外一个公司都是一个人开发 有木有
wsunit 官方访问不了
android求大神给我看看什么问题
关于Hibernate search 查询结果与数据库不相符的问题
求推荐Oracle好的书籍或PDF
关于
"记事本"
的
"自动换行"
的实现
swing在线html文本编辑器
android下网络阻塞问题
文件上线系统该如何做(代码上线)
ztree节点设置成check多选框的时候如何只获取叶节点,不要其他节点
怎么设置上传的图片不自动压缩
js 正则表达式问题
eclipse 经常loading descriptor
for
XXX ,然后卡死
关于android开发xml显示问题
RMI远程对象是共享的吧?
参与开源项目如何进行文档编写
php如何以文件图标的形式列出服务器上的所有文件?
php中一个简单的问题?请帮助解决一下,菜鸟
请教 solr query分词查询,结果为空的问题
这段代码有问题吗,怎么我运行报错?
jquery mobile 页面中切换闪屏问题
你帮我改好,我给你讲个笑话可好TUT
asp.net问题:Js如何获取cookie中的值?
android 电话拦截并处理
iis7 下 php 如何显示报错?
安装virtualbox的时候提示要安装通用串行总线控制器,这个要安装吗?
API获取新浪微博消息
工厂该不该有默认行为
如何处理开发过程中遗留无用的代码
ireport 设计时报表模板时,无法使用sybase驱动com.sybase.jdbc3.jdbc.SybDriver?
关于 使用druid后的一些问题.
|
小结
从示例可以看出,要从网页里获取数据,确实是非常容易的一件事情,只寥寥几行(20行左右),就采集出了我们想要的数据,要想抓出更多的数据,只要逐层细化分析即可。