種子站點的集中特性使得它們很容易被關(guān)閉(提供音樂、電影等版權(quán)內(nèi)容的種子文件的網(wǎng)站經(jīng)常會因法律原因而被關(guān)閉,如海盜灣等的關(guān)?;蛘弑粔Γ^近的如17年5月17日Extra Torrent關(guān)停)。
而來自土耳其·伊斯坦布爾的19歲程序員Bora想要解決這個問題,致力于真正的去中心化文件分享,他用python制作了一個開源軟件,使得可以輕松地在自己的電腦上開啟一個種子搜索引擎。(進一步,用pyinstaller打包成exe,前端用electron或者其它工具簡單封裝一下,完全不熟悉python 的普通用戶也可以輕松使用)。
實際上再進一步,如果每個人將自己搜索到的種子數(shù)據(jù)在開放無審查的零網(wǎng)上進行分享互換(這也可以用python自動化),就可以實現(xiàn)完全無審查去中心化的文件分享機制。(零網(wǎng)參見開放的零網(wǎng)與個人站點嘗試)
使用效果圖


- 在騰訊云最低配服務(wù)器上跑了兩天的效果,可以看出速度還是很快的,一天上萬種子。
快速安裝
-
linux使用:在python3的虛擬環(huán)境下(小白可以參看云服務(wù)器簡單配置)
pip3 install magneticod就安裝好了種子爬蟲,在虛擬環(huán)境下命令行執(zhí)行magneticod就可以運行了,等待一會兒,可以看到如下的日志輸出,表明爬蟲正在運行,并且收集到種子了。
(也可以使用magneticod -d運行顯示更詳細的信息,-d參數(shù)表示輸出debug信息。)
網(wǎng)頁顯示與查詢功能安裝,同樣在虛擬環(huán)境下pip install magneticow就好了,然后命令行magneticow --port 8080 --user 用戶名 密碼就可以運行在8080端口了。使用localhost:8080訪問,輸入自己更改的用戶名和密碼即可。 -
windows使用:windows下直接使用pip安裝暫時有點問題(可以先嘗試像上面那樣pip安裝),需要到github上下載源碼包 - download zip,如下圖:
然后解壓進入magneticod文件夾,在當前目錄打開命令行,python setup.py install安裝,再進入magneticow文件夾同樣命令安裝。還需要做一件事,就是找到你的python動態(tài)鏈接庫中的sqlite3.dll(我的在Anaconda3\DLLs路徑下),在SQLite Download Page找到適合你版本的sqlite-dll替換掉它,我用的是sqlite-dll-win64-x64-3200000.zip。(參考stackoverflow)這樣就可以成功運行了。
windows的使用效果不如linux(暫時認為是windows的bug,udp也會報錯——[WinError 10054] 遠程主機強迫關(guān)閉了一個現(xiàn)有的連接),限制速度之后就會好。
windows不限速
種子與磁力鏈接
- 說實話,作為一個從不開車、偶爾上車的良好公民 :),我對這些東西的了解十分有限。
- 我一直習(xí)慣使用的是基于ipv6的非公開BT站點,類似北郵人BT、6維空間這樣需要注冊的BT站點。想要資源時,在站點上下載相應(yīng)的種子(torrent)文件,使用utorrent客戶端下載即可,至于其中的原理不求甚解,大概知道的就是下載完成該資源且開啟ut客戶端的用戶越多我的下載速度越快,同時下載的人越多速度越快,因為下載的同時會互相上傳文件的不同部分給對方,下載完成后要盡保種的義務(wù),盡量開啟ut客戶端,方便其他用戶下載該資源,增加我的上傳量。分享文件做種時,要生成一個種子文件,并提交到站點服務(wù)器。
- 為了有更清楚的認知,打開ut客戶端研究一下,順便下載下權(quán)力的游戲最新集。用ut客戶端打開種子進行下載,在下載時觀察下面的狀態(tài)欄,第二欄就是Trackers,看來是非常關(guān)鍵的一個東西。
基本概念 - Tracker:收集下載者信息的服務(wù)器,并將此信息提供給其他下載者,使下載者們相互連接起來,傳輸數(shù)據(jù)。

-
原來,該BT站點提供了一個Tracker服務(wù)器(倒數(shù)一二行),記錄了所有下載者的信息或者文件分享者的信息,當我下載文件時,這個服務(wù)器會告訴我其他人的下載狀態(tài)(誰擁有資源,誰下載完成了,誰正在下載),也告訴其他人我的下載狀態(tài),讓我們互通有無,互相傳遞資源,增加下載速度,而tracker服務(wù)器充當了信息交換中心的角色??梢钥吹剑谝恍械腄HT被禁用了,是為了不走外網(wǎng)流量,DHT非常重要,下文會講到,暫時不管。
在peers一欄我們可以看到其他下載者的詳細信息,大家互相幫助上傳與下載。
-
在pieces一欄可以發(fā)現(xiàn)文件被分割成為很多份,每小份為1M大小,而我當前下載的視頻為4個多G。在files欄里可以看到所有區(qū)塊的下載狀況。
-
在對資源下載過程有了初步認識后,我們來詳細地看下種子文件到底是什么。原來種子文件本質(zhì)上是一種B編碼后的文本文件,它包含了資源的詳細信息,要打開它看里面的內(nèi)容需要先解碼,我們可以使用BEncode Editor這個軟件。隨便打開一個外網(wǎng)站點上下載的種子。
-
在BEncode Editor中顯示如下,這個73KB的種子包含了豐富的信息,在它的tracker服務(wù)器列表中可以看到名為海盜黨的希臘域名,這個種子文件也才創(chuàng)建不久。
-
而最關(guān)鍵的信息全在
info字典中,它是種子文件元信息。點開查看詳細內(nèi)容??梢钥吹较螺d文件的分塊機制和我們之前在ut客戶端看到的一致。在種子文件的元信息中包含了所有內(nèi)容信息,以及所有分塊的哈希驗證碼(數(shù)字指紋),來確保文件的真實性。在下載時我們會向種子文件中記錄的tracker服務(wù)器發(fā)出請求,得到其他有該資源的用戶的地址,一小塊一小塊的下載,每小塊下載完成后都與種子文件中的該小塊的哈希值進行比對,看是否被篡改。
每個種子文件也具有一個唯一標識碼,稱為種子文件的info_hash,是種子中所有info信息B編碼后的SHA-1哈希值:20個字節(jié),即40個16進制碼。根據(jù)這串碼就能找到對應(yīng)的種子文件。
-
除了種子,我們還會遇到磁力鏈接,如下圖,磁力鏈接又是什么呢?
-
下圖是一個磁力鏈接的分解,來自阮一峰老師的BT下載的未來,詳細見wiki百科-磁力鏈接
可以得出磁力鏈接最重要的是紅線勾出來的那40個16進制字符碼,也就是種子文件的info_hash,根據(jù)它就能找到對應(yīng)的種子文件,得到資源的詳細信息,進而下載資源。
-
擁有這串16進制碼,我們可以輕松構(gòu)造出磁力鏈,通常我們會打開迅雷下載,迅雷會自動搜索相應(yīng)的種子。
-
或者我們也可以到提供服務(wù)的站點,如thetorrent.org,由哈希碼得到相應(yīng)種子文件再進行下載。
通過磁力鏈接中的info_hash碼獲取種子文件 在沒有服務(wù)商或站點情況下,通過info_hash碼可以直接獲取到相應(yīng)的種子元信息及其資源嗎?可以,基于DHT協(xié)議(BEP-5: DHT Protocol - 翻譯),該協(xié)議基于Kademila算法,用udp實現(xiàn)。DHT是分布式哈希表的簡寫,用來存儲種子的下載者(peer)的聯(lián)系信息。一般每個下載者(peer)擁有一個節(jié)點(node),而DHT網(wǎng)絡(luò)由節(jié)點組成(node)。每個節(jié)點(node)擁有一個唯一的ID:20字節(jié)標識碼,和種子文件的info_hash一樣長。每個節(jié)點都維持一個自己的路由表,存儲了一小部分其他節(jié)點的聯(lián)系方式,同時也存儲了一些下載者的聯(lián)系信息。節(jié)點之間互相聯(lián)系幫助尋找資源。比如節(jié)點A拿著資源X的唯一標識碼(info_hash)去問在它路由表中的節(jié)點B有沒有資源X的下載者信息,如果節(jié)點B中沒有資源X的記錄信息,節(jié)點B會在自己的路由表中選出最可能擁有資源X的k個節(jié)點,把他們的聯(lián)系方式返回給節(jié)點A,節(jié)點A再根據(jù)節(jié)點B的返回信息去聯(lián)系這些節(jié)點進行詢問,依次迭代。(每一個節(jié)點比其他節(jié)點對它周邊的節(jié)點有更好的感知能力,
周邊與否由Kademila算法定義)(node用來查找和存儲信息,peer負責(zé)下載)(詳細信息見BEP文檔)只要找到一個種子的下載者(peer)就可以使用
BEP-9: Extension for Peers to Send Metadata Files拓展協(xié)議從該下載者(peer)處下載種子元信息(info)(同樣可以使用元信息的哈希值(info_hash)來驗證該信息的真實性),當然也可以從它那下載資源。這樣只需要一個磁力鏈接在沒有中心服務(wù)器的情況下也可以下載資源了。(注:ut客戶端中會自動保存一份已下載資源的種子文件)
補充1:在前面我們看到的種子文件中,
announce鍵記錄了tracker服務(wù)器的地址信息,在BEP-5的Torrent File Extensions小節(jié)中提到無tracker的種子文件中沒有announce鍵,而有nodes鍵記錄了良好的節(jié)點地址??傊?,在一個新節(jié)點(自身路由表為空)加入DHT網(wǎng)絡(luò)時,需要一個引導(dǎo)過程,要知道一個已經(jīng)在該網(wǎng)絡(luò)中的節(jié)點。要么通過tracker服務(wù)器獲取節(jié)點,要么是直接得到節(jié)點,并沒有那么自由。此外,tracker服務(wù)器的速度還是比DHT查找要快,一般下載過程是兩者的結(jié)合。
補充2:文件分享過程
補充3:Kademlia算法概要 - Kademlia基于兩個節(jié)點之間的距離計算,該距離是兩個網(wǎng)絡(luò)節(jié)點ID號的異或,計算的結(jié)果最終作為整型數(shù)值返回。資源的info_hash和節(jié)點ID有同樣的格式和長度,因此,可以使用同樣的方法計算資源(info_hash)和節(jié)點ID之間的距離。節(jié)點ID一般是一個大的隨機數(shù),選擇該數(shù)的時候所追求的一個目標就是它的唯一性(希望在整個網(wǎng)絡(luò)中該節(jié)點ID是唯一的)。異或距離跟實際上的地理位置沒有任何關(guān)系,只與ID相關(guān)。因此很可能來自德國和澳大利亞的節(jié)點由于選擇了相似的隨機ID而成為鄰居。選擇異或是因為通過它計算的距離享有幾何距離公式的一些特征
(此外還有用戶交換 (PEX)協(xié)議,暫不討論)
源碼分析
注:網(wǎng)絡(luò)分享繁多,很多話的正確性都不是那么高,深入探索還得自己去讀官方英文協(xié)議和論文。別人的話都只是你通往更高處的一個墊腳石,不能停留在上面。
之前網(wǎng)絡(luò)上已經(jīng)有不少開源的dht種子搜索的python代碼。比較有名的是手撕包菜種子搜索引擎網(wǎng)站的python代碼(開源在github上),但在項目介紹里的相關(guān)博文鏈接已經(jīng)失效,來看源碼,關(guān)鍵的種子嗅探爬蟲都在目錄workers下。而最重要的info_hash碼(即種子唯一標識碼)爬蟲為simdht_worker.py文件。主要使用了CreateChen/simDownloader項目中的代碼。而與fanpei91/simDHT基本一致。
simDHT最簡單易讀,單線程,建議先閱讀。思路是偽裝成一個DHT節(jié)點。初始化時,給自己隨機生成一個20位的ID,通過大的tracker服務(wù)器(如
router.bittorrent.com)獲取其他節(jié)點的地址信息(find_node操作),進入DHT網(wǎng)絡(luò),利用KRPC協(xié)議傳輸B編碼的字典信息,即DHT查詢信息(4種,見bep05),與DHT網(wǎng)絡(luò)中的其他節(jié)點互相通信。由于在初始化時已經(jīng)從大的Tracker服務(wù)器獲取了一定量的節(jié)點信息,接下來向這些節(jié)點發(fā)送
find_node請求,參數(shù)中:1. 將自己的ID構(gòu)造成被請求節(jié)點的(按異或)相近ID(代碼為get_neighbor函數(shù),如向ID為A的節(jié)點發(fā)送find_node請求,將自己ID構(gòu)造成A[:end]+X[:20-end],也就是構(gòu)造的ID的前end位與A節(jié)點ID相同,而后(20-end)位隨意,end取10-15,這樣偽裝成A的周邊節(jié)點,而按規(guī)則每個節(jié)點對周邊節(jié)點的感知能力要好,它很可能將你記錄在它的路由表上,使得它自己或引導(dǎo)其他節(jié)點主動向你通信),2. 要查找的節(jié)點ID隨機生成即可。大部分隨機生成的節(jié)點ID是不可能直接查找到的,那么被請求節(jié)點會返回另一批節(jié)點信息,在接受到返回的新節(jié)點信息后,向新節(jié)點繼續(xù)發(fā)送請求,依此迭代進行,目的就是不斷地和其他節(jié)點混臉熟,即auto_send_find_node函數(shù)。這里維護了一個有限長的雙端隊列(deque)存儲節(jié)點。節(jié)點不斷從隊首取出,向其發(fā)送find_node請求,收到的應(yīng)答中的新節(jié)點不斷被添加到隊尾。如果隊列為空,則重新初始化一下。一旦和越來越多的節(jié)點混臉熟了,就會有不斷的查詢請求從其他節(jié)點發(fā)送過來,作為爬蟲,只要處理
get_peers和announce_peer請求就夠了。get_peers是一個節(jié)點向另一個節(jié)點發(fā)出的查詢與info_hash相關(guān)的下載者信息,包含的info_hash參數(shù)就是我們需要的種子的info_hash,但是,get_peers中包含的info_hash對應(yīng)的種子可能已經(jīng)失效或者難連接上,不采用。這時我們要回應(yīng)它,關(guān)鍵是給他一個token(自己以一定方式生成,不固定,用來校驗的)與一個空的nodes參數(shù)(我們沒有種子的下載者信息,按協(xié)議應(yīng)當返回最有可能有該信息的K個節(jié)點給查詢節(jié)點,但是也可以返回空值)。這個向我查詢的節(jié)點如果最終(通過其他節(jié)點)找到了資源(其他下載者,即peer),而控制該節(jié)點的下載者開始下載資源了,該節(jié)點很可能向我發(fā)送
announce_peer消息,該消息告訴我們它的下載者信息。消息參數(shù)中的info_hash和下載者地址就是我們需要的,同時要驗證參數(shù)中的token是否就是我之前發(fā)送給該節(jié)點的,保證真實性。返回給它的消息只是自己節(jié)點的ID。對于其他節(jié)點發(fā)送給自己的
ping和find_node查詢不用管即可。(可以思考,對于這兩種查詢是否有某種響應(yīng)方式可以給自己帶來更多收益)以上就是simDHT的內(nèi)容了。
而進一步,光有種子的info_hash碼還不夠,能直接拿到種子的元信息就好了。這就是手撕包菜里的simMetadata.py實現(xiàn)的通過bep9拓展協(xié)議從之前
announce_peer消息中的下載者那里獲取到種子的元信息。此外,wuzhenda/simDHT和0x0d/dhtfck實現(xiàn)了K桶等,有一定注釋和他個人的理解,但作為爬蟲可能并不需要這個功能,還有NanYoMy的DHT-woodworm 以及DHT-simDHT增加了一點新特性,可以瀏覽下。
以上都是python2的,基于python3的異步IO特性的DHT爬蟲并不多,有whtsky/maga,而zrools基于maga,寫了asyncDHT,并有圖文并茂的博文,DHT爬蟲:18.4GB種子分析小記,值得一看。
另外,B編碼的編解碼庫:python2使用的多為bencode,
pip install bencode。python可以使用的有bcoding,pip install bcoding與better-bencode,pip install better-bencode。實現(xiàn)bttorrent客戶端的python庫libtorrent,貌似只支持python2,libtorrent庫的使用可以看: 從磁力鏈獲取種子文件 - Magnet_To_Torrent2.py的43行到67行(其他都是次要代碼)。還可以參考creating daemon using Python libtorrent for fetching meta data of 100k+ torrents。(注:還發(fā)現(xiàn)有個Simple libtorrent,
pip install SimpleTorrentStreaming)回到文章開頭使用的
magneticod,它使用了python3提供的asyncio機制。主要嗅探代碼部分magneticod/dht.py中的思路和之前介紹的simDHT基本相似,有點不同的是,它維護了一個自己的節(jié)點字典self._routing_table,每一輪(間隔一秒)向里面所有節(jié)點發(fā)出find_node查詢?nèi)缓笄蹇兆值?,如果收到自己發(fā)出的find_node請求的響應(yīng)時,字典中的所有節(jié)點數(shù)超出self.__n_max_neighbours數(shù)則不再加入新節(jié)點。(主要函數(shù)為async def tick_periodically(self),這個機制還有可以斟酌的地方)在大的異步結(jié)構(gòu)上繼承了官方的
asyncio.DatagramProtocol,可以先看官方樣例UDP echo client protocol和UDP echo server protocol,很簡明,數(shù)據(jù)的發(fā)送和接收都封裝好了,并且可以通過pause_writing和resume_writing控制流量。在處理
announce_peer消息時,用asyncio.ensure_future新建異步任務(wù)來抓取種子元信息,且對同一個種子元信息的多個抓取進行管理。在數(shù)據(jù)存儲方面使用了python自帶的sqlite,不用安裝就能使用,很方便。數(shù)據(jù)庫存儲位置管理使用了appdirs庫。
作者表示近期會有一次大的重構(gòu),讓我們拭目以待。
論文
- Kademlia: A Peer-to-Peer Information System Based on the XOR Metric
- A Torrent Recommender based on DHT Crawling
- Real-World Sybil Attacks in BitTorrent Mainline DHT
- Measuring large-scale distributed systems: case of BitTorrent Mainline DHT
- Crawling BitTorrent DHTs for Fun and Profit
可用參考
- 如何通過infohash得到torrent種子文件?
- 種子文件 - Torrent file
- Torrent 文件格式詳解
- B編碼以及BT種子文件分析
- What exactly is the info_Hash in a torrent file
- Hash calculation in torrent clients
- BT服務(wù)器/tracker服務(wù)器 - BitTorrent tracker - Trackerless torrents
- 分布式散列表
- Kademlia算法
其他
-
http://torrage.com/
- SimpleXMLRPCServer
-
迅雷從磁力鏈接下載種子時的http請求
請求,參數(shù)為大寫的infohash
響應(yīng)















