DHT網絡爬蟲
傳統的Bittorrent服務
傳統的BT服務是由兩部份組成的,tracker服務和p2p服務,通過前者用戶可以知道誰擁有資源,后者是通過前者向擁有資源的用戶發起下載。
Trackerless
目前在大多數國家,提供tracker服務都是非法的。最終有一天tracker服務會像edonkey的服務一樣消失。trackerless的需求於是變得迫切起來。
DHT網絡
DHT網絡就是解決trackerless目前運用最廣的方案,核心算法叫Kademlia,也就是所謂的異或算法。在Bittorrent中它叫DHT,在edonkey中它叫Kad,兩者算法是一至的,但細節不同,前者更注重文件傳輸,后者更在意文件分享。
什么是NodeID和InfoHash
在DHT網絡中,所有的用戶和資源都有一個20bytes的ID,用戶叫NodeID,資源叫InfoHash。NodeID通常是根據用戶的IP端口計算得出的(但在DHT爬蟲中可以隨機獲取一個20bytes的串,無關緊要),InfoHash是根據torrent種子文件的info字段,用hash sha1計算得出的。在DHT協議中,
NodeID可以通過以下代碼簡單的得到
const nodeID = crypto.createHash('sha1').update(Math.random()*100000).digest()
const infoHash = crypto.createHash('sha1').update(bencode.decode('file.torrent').info).digest()
const magnet = `magnet:?xt=urn:btih:${infoHash.toString('hex').toUpperCase()}`
可見DHT網絡中用戶,資源都是無區別的,所以就有了xor算法之說。NodeID之間可以用異或計算出距離,NodeID和InfoHash之間同樣可以計算距離,InfoHash之間也可以計算距離。計算方法很簡單,把infoHash或NodeID換為數值,然后按位異或,就得到了距離。這很關鍵,在下面的Routing table中會運用到。異或算法得到的距離的結果雖然不是物理上的距離關系,但是在數學邏輯上是自洽的。
DHT協議
共4條
- ping
- find_node
- get_peers (在edonkey kad中這叫find_value)
- announce_peer
ping
是用檢查Node狀態,用以更新Routing table
find_node
通常是用來初始化Routing table,因為一開始,你在Routing table是空的,需要通過向公共節點發送find_node來填充之。
get_peers
是當用戶要下載種子資源時向其它Node發起的。如果Node有該資源,則返回資源的下載端口以供對方下載,如果沒有,則根據異或算法在自己的Routing table中尋找離資源最近的Node返回給對方,對方如此遞歸發送get_peers,直到找到資源為止。
announce_peer
當用用戶下載完種子資源,通過種子開始下載時(這里下載行為通常會回倒為tracker式下載,但也有有種子文件是有Nodes字段的,可以通過純p2p下載)通知所有曾經get_peers咨詢過的node。 announce_peer是爬蟲的關鍵,當下載開始,用戶就會通知,於是就得到了一個有效的InfoHash。
Routing table
每個Node都要維護一個Routing table以存放Node信息。 Routing table的容器為桶,稱為K桶,桶的容量為8(kad中為20)。桶的數量是可以增加的,當桶的個數超過8時,桶就會平均的分裂。桶中的保存的就是Node信息,包含NodeID、IP和端口。 當Node接受到任意一條協議時,都會試圖向Routing table中插入對方的NodeID,插入Rule如下:
- 通過異或算法計算距離,應該往哪個桶插入。
- 如果這個桶是不滿的,則插入成功。
- 如果這個桶是滿的,並且這個桶中不包含自己,則插入失敗。反之則分裂這個桶,並且遞歸的再嘗試插入。
這里是一個我開發的 BT搜索,磁力搜索,每天可以抓取infohash100w以上,metainfo20w以上。
爬蟲的關鍵
通過上述基礎知識,可以得到以下結論: