Posted on 2012-01-20 15:27
小明 阅读(1962)
评论(2) 编辑 收藏 所属分类:
开发日志
程序员的核心价值是创造有用的软件。
----------小明
背景我有时会去特定的网站去下载一些资料,比如去englishpod.com去下载英语听力资料,或者去某论坛下载美女贴图:-),但是通用的爬虫无法满足需求,一来很多网站需要登录才能下载,另外我也不想下载不需要的东西,只想下载特定的内容,所以我只能写一些小程序来去下载。这样的小程序写了几个,重复的部分很多,所以能不能写一个通用的平台,让写类似的程序更简单?于是有了现在这个开源项目Snaker:
http://code.google.com/p/ssnaker/
插件设计我的目标之一,是让写特定的爬虫更简单,一个想法是做成插件式的。有几个需求:
1. 很容易添加插件
2. 很容易修改插件,不需要重启程序
3. 特定网站的逻辑都应该在插件中,framework只包含通用部分。
所以插件最好是用一种脚本语言来书写。平台层我使用Java来开发,插件脚本我决定用javascript来编写。为什么用javascript?主要是受到nodejs和greasemonkey的启发,尤其是greasemonkey那种javascript插件的方式,我觉得非常不错。
Java和JavaScript的互动我选择了mozilla的rhino库来实现脚本的执行。
Java调用Javascript脚本比较简单:
Context cx = Context.enter();
try {
Scriptable scope = cx.initStandardObjects();
Script script = cx.compileString(sourceCode, engine.getName(), 1, null);
script.exec(cx, scope);
} finally {
Context.exit();
}
因为javascript本身并没有网络下载的功能,所以我要定义一些方法,让javascript可以调用java的方法来实现下载,这称为Host object。具体的方法请参见rhino的官方文档,我这里贴出一小段code。
下面这个类定义了一个sleep的方法。
Java:
public class JsHelper extends NativeObject {
public JsHelper() {
}
@Override
public String getClassName() {
return "JsHelper";
}
public void jsFunction_sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
logger.error("interrupted",e);
}
}
}
Scriptable tx = cx.newObject(scope, "JsHelper");
scope.put("$", scope, tx);
这样就可以在javascript中调用了:
$.sleep(1000);
更多的Snaker API设计请参考: