php dht爬虫,利用DHT网络,爬取bt种子。
DHT網(wǎng)絡(luò)爬蟲
傳統(tǒng)的Bittorrent服務(wù)
傳統(tǒng)的BT服務(wù)是由兩部份組成的,tracker服務(wù)和p2p服務(wù),通過前者用戶可以知道誰擁有資源,后者是通過前者向擁有資源的用戶發(fā)起下載。
Trackerless
目前在大多數(shù)國家,提供tracker服務(wù)都是非法的。最終有一天tracker服務(wù)會(huì)像edonkey的服務(wù)一樣消失。trackerless的需求于是變得迫切起來。
DHT網(wǎng)絡(luò)
DHT網(wǎng)絡(luò)就是解決trackerless目前運(yùn)用最廣的方案,核心算法叫Kademlia,也就是所謂的異或算法。在Bittorrent中它叫DHT,在edonkey中它叫Kad,兩者算法是一至的,但細(xì)節(jié)不同,前者更注重文件傳輸,后者更在意文件分享。
什么是NodeID和InfoHash
在DHT網(wǎng)絡(luò)中,所有的用戶和資源都有一個(gè)20bytes的ID,用戶叫NodeID,資源叫InfoHash。NodeID通常是根據(jù)用戶的IP端口計(jì)算得出的(但在DHT爬蟲中可以隨機(jī)獲取一個(gè)20bytes的串,無關(guān)緊要),InfoHash是根據(jù)torrent種子文件的info字段,用hash sha1計(jì)算得出的。在DHT協(xié)議中,
NodeID可以通過以下代碼簡單的得到
const nodeID = crypto.createHash(‘sha1‘).update(Math.random()*100000).digest()
通過種子文件計(jì)算得到InfoHash的代碼
const infoHash = crypto.createHash(‘sha1‘).update(bencode.decode(‘file.torrent‘).info).digest()
得到可傳播的magnet鏈接就簡單了
const magnet = `magnet:?xt=urn:btih:${infoHash.toString(‘hex‘).toUpperCase()}`
可見DHT網(wǎng)絡(luò)中用戶,資源都是無區(qū)別的,所以就有了xor算法之說。NodeID之間可以用異或計(jì)算出距離,NodeID和InfoHash之間同樣可以計(jì)算距離,InfoHash之間也可以計(jì)算距離。計(jì)算方法很簡單,把infoHash或NodeID換為數(shù)值,然后按位異或,就得到了距離。這很關(guān)鍵,在下面的Routing table中會(huì)運(yùn)用到。異或算法得到的距離的結(jié)果雖然不是物理上的距離關(guān)系,但是在數(shù)學(xué)邏輯上是自洽的。
DHT協(xié)議
共4條
ping
find_node
get_peers (在edonkey kad中這叫find_value)
announce_peer
ping
是用檢查Node狀態(tài),用以更新Routing table
find_node
通常是用來初始化Routing table,因?yàn)橐婚_始,你在Routing table是空的,需要通過向公共節(jié)點(diǎn)發(fā)送find_node來填充之。
get_peers
是當(dāng)用戶要下載種子資源時(shí)向其它Node發(fā)起的。如果Node有該資源,則返回資源的下載端口以供對(duì)方下載,如果沒有,則根據(jù)異或算法在自己的Routing table中尋找離資源最近的Node返回給對(duì)方,對(duì)方如此遞歸發(fā)送get_peers,直到找到資源為止。
announce_peer
當(dāng)用用戶下載完種子資源,通過種子開始下載時(shí)(這里下載行為通常會(huì)回倒為tracker式下載,但也有有種子文件是有Nodes字段的,可以通過純p2p下載)通知所有曾經(jīng)get_peers咨詢過的node。?announce_peer是爬蟲的關(guān)鍵,當(dāng)下載開始,用戶就會(huì)通知,于是就得到了一個(gè)有效的InfoHash。
Routing table
每個(gè)Node都要維護(hù)一個(gè)Routing table以存放Node信息。 Routing table的容器為桶,稱為K桶,桶的容量為8(kad中為20)。桶的數(shù)量是可以增加的,當(dāng)桶的個(gè)數(shù)超過8時(shí),桶就會(huì)平均的分裂。桶中的保存的就是Node信息,包含NodeID、IP和端口。 當(dāng)Node接受到任意一條協(xié)議時(shí),都會(huì)試圖向Routing table中插入對(duì)方的NodeID,插入Rule如下:
通過異或算法計(jì)算距離,應(yīng)該往哪個(gè)桶插入。
如果這個(gè)桶是不滿的,則插入成功。
如果這個(gè)桶是滿的,并且這個(gè)桶中不包含自己,則插入失敗。反之則分裂這個(gè)桶,并且遞歸的再嘗試插入。理解Routing table是DHT爬蟲的關(guān)鍵,可以參考協(xié)議文檔
這里是一個(gè)我開發(fā)的
爬蟲的關(guān)鍵
通過上述基礎(chǔ)知識(shí),可以得到以下結(jié)論:
盡量認(rèn)識(shí)更多的Node,這點(diǎn)可以通過find_node來實(shí)現(xiàn)。
盡量讓自己插入到對(duì)方的Routing table中,只有這樣,當(dāng)對(duì)方下載資源時(shí)才會(huì)優(yōu)先通知你。
插入對(duì)方的Routing table成功的關(guān)鍵在于自己的NodeID離對(duì)方的NodeID足夠的近。
爬蟲只無需現(xiàn)實(shí)所有的協(xié)議,只需要實(shí)現(xiàn)find_node(query),get_peers(response),announce_peer(response),ping(response)
Engiy?的開源簡化Node.js版DHTSpider可以參考,有疑問可以github上給我留言。
總結(jié)
以上是生活随笔為你收集整理的php dht爬虫,利用DHT网络,爬取bt种子。的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构总结
- 下一篇: k2p路由器搭建php,搭建ngrok服