程序員的核心價(jià)值是創(chuàng)造有用的軟件。
----------小明
背景我有時(shí)會(huì)去特定的網(wǎng)站去下載一些資料,比如去englishpod.com去下載英語(yǔ)聽(tīng)力資料,或者去某論壇下載美女貼圖:-),但是通用的爬蟲(chóng)無(wú)法滿足需求,一來(lái)很多網(wǎng)站需要登錄才能下載,另外我也不想下載不需要的東西,只想下載特定的內(nèi)容,所以我只能寫(xiě)一些小程序來(lái)去下載。這樣的小程序?qū)懥藥讉€(gè),重復(fù)的部分很多,所以能不能寫(xiě)一個(gè)通用的平臺(tái),讓寫(xiě)類似的程序更簡(jiǎn)單?于是有了現(xiàn)在這個(gè)開(kāi)源項(xiàng)目Snaker:
http://code.google.com/p/ssnaker/
插件設(shè)計(jì)我的目標(biāo)之一,是讓寫(xiě)特定的爬蟲(chóng)更簡(jiǎn)單,一個(gè)想法是做成插件式的。有幾個(gè)需求:
1. 很容易添加插件
2. 很容易修改插件,不需要重啟程序
3. 特定網(wǎng)站的邏輯都應(yīng)該在插件中,framework只包含通用部分。
所以插件最好是用一種腳本語(yǔ)言來(lái)書(shū)寫(xiě)。平臺(tái)層我使用Java來(lái)開(kāi)發(fā),插件腳本我決定用javascript來(lái)編寫(xiě)。為什么用javascript?主要是受到nodejs和greasemonkey的啟發(fā),尤其是greasemonkey那種javascript插件的方式,我覺(jué)得非常不錯(cuò)。
Java和JavaScript的互動(dòng)我選擇了mozilla的rhino庫(kù)來(lái)實(shí)現(xiàn)腳本的執(zhí)行。
Java調(diào)用Javascript腳本比較簡(jiǎn)單:
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();
}
因?yàn)閖avascript本身并沒(méi)有網(wǎng)絡(luò)下載的功能,所以我要定義一些方法,讓javascript可以調(diào)用java的方法來(lái)實(shí)現(xiàn)下載,這稱為Host object。具體的方法請(qǐng)參見(jiàn)rhino的官方文檔,我這里貼出一小段code。
下面這個(gè)類定義了一個(gè)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中調(diào)用了:
$.sleep(1000);
更多的Snaker API設(shè)計(jì)請(qǐng)參考: