天天看點

搜尋引擎Nutch源代碼研究之一 網頁抓取(3)

今天我們看看Nutch網頁抓取,所用的幾種資料結構:

主要涉及到了這幾個類:FetchListEntry,Page,

首先我們看看FetchListEntry類:

public final class FetchListEntry implements Writable, Cloneable

實作了Writable, Cloneable接口,Nutch許多類實作了Writable, Cloneable。

自己負責自己的讀寫操作其實是個很合理的設計方法,分離出來反倒有很瑣碎

的感覺。

看看裡面的成員變量:

[code]

public static final String DIR_NAME = "fetchlist";//要寫入磁盤的目錄

private final static byte CUR_VERSION = 2;//目前的版本号

private boolean fetch;//是否抓取以便以後更新

private Page page;//目前抓取的頁面

private String[] anchors;//抓取到的該頁面包含的連結

[/code]

我們看看如何讀取各個字段的,也就是函數

public final void readFields(DataInput in) throws IOException

讀取version 字段,并判斷如果版本号是否大約目前的版本号,則抛出版本不比對的異常,

然後讀取fetch 和page 字段。

判斷如果版本号大于1,說明anchors已經儲存過了,讀取anchors,否則直接指派一個空的字元串

代碼如下:

[code]

byte version = in.readByte(); // read version

if (version > CUR_VERSION) // check version

throw new VersionMismatchException(CUR_VERSION, version);

fetch = in.readByte() != 0; // read fetch flag

page = Page.read(in); // read page

if (version > 1) { // anchors added in version 2

anchors = new String[in.readInt()]; // read anchors

for (int i = 0; i < anchors.length; i++) {

anchors[i] = UTF8.readString(in);

}

} else {

anchors = new String[0];

}

[/code]

同時還提供了一個靜态的讀取各個字段的函數,并建構出FetchListEntry對象傳回:

[code]

public static FetchListEntry read(DataInput in) throws IOException {

FetchListEntry result = new FetchListEntry();

result.readFields(in);

return result;

}

[/code]

寫得代碼則比較易看,分别寫每個字段:

[code]

public final void write(DataOutput out) throws IOException {

out.writeByte(CUR_VERSION); // store current version

out.writeByte((byte)(fetch ? 1 : 0)); // write fetch flag

page.write(out); // write page

out.writeInt(anchors.length); // write anchors

for (int i = 0; i < anchors.length; i++) {

UTF8.writeString(out, anchors[i]);

}

}

[/code]

其他的clone和equals函數實作的也非常易懂。

下面我們看看Page類的代碼:

public class Page implements WritableComparable, Cloneable

和FetchListEntry一樣同樣實作了Writable, Cloneable接口,我們看看Nutch的注釋,我們就非常容易知道各個字段的意義了:

[code]

[/code]

各個字段:

[code]

private final static byte CUR_VERSION = 4;

private static final byte DEFAULT_INTERVAL =

(byte)NutchConf.get().getInt("db.default.fetch.interval", 30);

private UTF8 url;

private MD5Hash md5;

private long nextFetch = System.currentTimeMillis();

private byte retries;

private byte fetchInterval = DEFAULT_INTERVAL;

private int numOutlinks;

private float score = 1.0f;

private float nextScore = 1.0f;

[/code]

同樣看看他是如何讀取自己的各個字段的,其實代碼加上本來提供的注釋,使很容易看懂的,不再詳述:

[code]

ublic void readFields(DataInput in) throws IOException {

byte version = in.readByte(); // read version

if (version > CUR_VERSION) // check version

throw new VersionMismatchException(CUR_VERSION, version);

url.readFields(in);

md5.readFields(in);

nextFetch = in.readLong();

retries = in.readByte();

fetchInterval = in.readByte();

numOutlinks = (version > 2) ? in.readInt() : 0; // added in Version 3

score = (version>1) ? in.readFloat() : 1.0f; // score added in version 2

nextScore = (version>3) ? in.readFloat() : 1.0f; // 2nd score added in V4

}

[/code]

寫各個字段也很直接:

[code]

public void write(DataOutput out) throws IOException {

out.writeByte(CUR_VERSION); // store current version

url.write(out);

md5.write(out);

out.writeLong(nextFetch);

out.write(retries);

out.write(fetchInterval);

out.writeInt(numOutlinks);

out.writeFloat(score);

out.writeFloat(nextScore);

}

[/code]

我們順便看看提供友善讀寫Fetch到的内容的類FetcherOutput:這個類通過委托前面介紹的兩個類的讀寫,提供了Fetche到的

各種粒度結構的讀寫功能,代碼都比較直接,不再詳述。

下次我們看看parse-html插件,看看Nutch是如何提取html頁面的。

繼續閱讀