記錄我與DHT爬蟲那些激情歲月
2013年10月份某一天,從搬磚的工地回到辦公室,甩掉破了幾個(gè)洞的手套,解下油膩膩的安全帽,打開已有7,8年使用歷史的IBM筆記本電腦,灰暗無光的眼睛瞬間變得精亮精亮的(我從屏幕反光看到),叼著娃哈哈,進(jìn)入博客園看有木有干貨出現(xiàn),鬼使神差地進(jìn)入了小蝦的個(gè)人博客,看到了那篇關(guān)于DHT的文章,發(fā)現(xiàn)dianying.fm是他的杰作,當(dāng)時(shí)把我激動(dòng)得……事情回到5月份,當(dāng)時(shí)我想做一個(gè)跟dianying.fm類似的網(wǎng)站,當(dāng)時(shí)采取的是把他資源給扒下來,但是后來給放棄了,個(gè)人覺得,扒別人的資源來做資源站顯得沒技術(shù)含量。 所以一直就掛在心上,時(shí)不時(shí)地在琢磨他是怎么辦到的。 很笨的是,居然沒寫信問他是如何做到的。 也不知道他的個(gè)人博客。
時(shí)隔5個(gè)月后,終于發(fā)現(xiàn)了這個(gè)秘密,于是就開始研究DHT,但是國(guó)內(nèi)關(guān)于DHT文章少得可憐,根本就沒幾個(gè)人在研究(這更使我覺得要是實(shí)現(xiàn)了會(huì)更有成就感),加之根本就看不懂英文官方文檔。 對(duì)DHT也是一知半解,當(dāng)時(shí)一直以為DHT的"distance metric"指的就是實(shí)際地理距離,也一直以為如果把爬蟲放到日本地區(qū)的話,會(huì)爬取到更多的AV視頻。 于是只好借用別人DHT爬蟲(dhtcrawler),用了一段時(shí)間,始終不滿意它的通過HTTP請(qǐng)求種子下載方式,而且一點(diǎn)成就感都沒有,畢竟爬蟲代碼不是自己寫的。 貌似dhtcrawler的作者也在博客園來著,嘿嘿! 于是下定決心學(xué)英語(yǔ)(本人初中畢業(yè),在學(xué)校幾乎沒學(xué)過英語(yǔ)),一定要寫一個(gè)屬于自己的DHT爬蟲。 于是開始閉關(guān)修煉,不再上QQ閑扯蛋。
接著開始狠看Python中英對(duì)照技術(shù)文檔練英語(yǔ),看了差不多半個(gè)月,了解了一些技術(shù)文檔常用的語(yǔ)法。 還把DHT官方文檔不認(rèn)識(shí)的單詞給背了。 棄掉用了一兩年的PHP這個(gè)只擅長(zhǎng)web端編程語(yǔ)言,改用NodeJS,看上了它那事件編程,后來發(fā)現(xiàn)寫的代碼實(shí)在難以理解,嵌套太深,"內(nèi)涵"太低,改用Perl,學(xué)了一周就上馬了,一開始用著還不錯(cuò),一兩行代碼頂NodeJS和PHP十幾行代碼,但就是因?yàn)樘珡?qiáng)悍了,駕馭不了它那亂七八糟的^$#@_*~%什么的符號(hào),一眼望去,整篇代碼丑陋不堪(咋一看還挺高深的樣),依靠上下文環(huán)境的代碼太多。 于是打算換其他的編程語(yǔ)言,花了幾天就是找不到順手的。 C像個(gè)巫婆,法力大,脾氣怪,Java"官僚化",太繁瑣,C#只支持Windows(雖然Linux有mono)。 Lisp深不可測(cè),erlang看不懂,語(yǔ)法怪。 Ruby更是怪。 一時(shí)陷入世界這么大,無編程語(yǔ)言可用的狀態(tài),一連好幾天搬磚都沒精神,好幾次都差點(diǎn)被落下的建筑物給砸到。
后來猛地想起還有個(gè)叫Python這個(gè)動(dòng)態(tài)語(yǔ)言,于是趕緊地看手冊(cè),草草學(xué)了一周,發(fā)現(xiàn)用著還真順手,好用得我只能說"爽爆了!"。 它那異常處理很自然,不像PHP那樣硬生生的; 也不像Java那樣太繁瑣; 有點(diǎn)像Lisp/Haskell,雖然一點(diǎn)都不會(huì),不過特別喜歡里面的某些風(fēng)格,比如那lambda,list comps; 還有自己的shell,語(yǔ)法簡(jiǎn)單無比; 庫(kù)也特別多,讓我這個(gè)不愛寫小工具的懶人真是個(gè)寶貝; 于是你們懂得。 我就成了Python的教徒了。 以前用PHP的那一兩年,從未有這么個(gè)"宗教感"。
上述毫無挑起語(yǔ)言宗教戰(zhàn)爭(zhēng)的意思,請(qǐng)勿對(duì)號(hào)入座,只是激動(dòng)了點(diǎn)!
接著開始了解Python的多線程,事件編程,各種各樣的web框架,模板,挑出Flask,jinja這倆玩意兒來做web開發(fā),文檔簡(jiǎn)單例子多,推薦那些用Django的人試試Flask,不知是不是名字太過火爆,官網(wǎng)都要靠翻墻。 jianja模板引擎跟PHP的Symfony2的默認(rèn)模板引擎Twig非常相似,干貨一個(gè),話說好知網(wǎng)都是用的Symfony2。 然后學(xué)習(xí)Twisted網(wǎng)絡(luò)框架,這個(gè)玩意兒只有英語(yǔ)文檔,寫得不是很通順,讓我費(fèi)了很大的勁才學(xué)懂一點(diǎn)點(diǎn),還不錯(cuò)! 只是感覺事件編程沒有NodeJS那么自然。 轉(zhuǎn)眼就到了12月份,天氣冷得在野外撒尿都掏不出JJ; 于是全部放假回家,回到家,猛騎了幾天的稀泥山地車活躍身體,就開始閉關(guān)修煉專攻DHT。 因?yàn)榈谝淮慰磪f(xié)議類的文檔,總感覺協(xié)議文檔很虛無,很容易讓人忘記是在看協(xié)議而不是在看手冊(cè),一點(diǎn)樣例代碼都沒。 有點(diǎn)頭大,不過放棄這么意思的協(xié)議實(shí)現(xiàn)不是我的風(fēng)格,所以還是硬著頭皮仔仔細(xì)細(xì)地看文檔,好不容易懂了概念,就開始coding了,因?yàn)閷?duì)DHT還不是很熟,所以代碼寫了推,推了寫,一直都沒多少效果,于是就搞了幾個(gè)開源代碼看,看了幾個(gè)后,豁然開朗。 后來總算搞出一個(gè)可以運(yùn)行的版本。 又花了幾天重新整了下代碼。 總算實(shí)現(xiàn)了DHT爬蟲: https://github.com/laomayi/simDHT 簡(jiǎn)單粗暴不做作! 這個(gè)是要做類似dianying.fm的發(fā)動(dòng)機(jī)。
霉運(yùn)正式開始:
由于是在Linux環(huán)境下編寫,有次不小心刪掉了所有代碼,當(dāng)時(shí)感覺腦袋一黑,臉通紅,頭冒汗,腿打擺子,心想: 完鳥完鳥,我?guī)讉€(gè)月的代碼就這么完鳥,頭一次體會(huì)到一國(guó)外牛說的"rm -rf *。log"就是個(gè)錯(cuò)誤設(shè)計(jì)的內(nèi)涵了(我在"*" 和"。log"之間不小心空了一格)。 緩了一會(huì),蛋定地睡覺去了,之所以這么蛋定,是因?yàn)樯院笙氲綄懥藷o數(shù)次,代碼構(gòu)造都差不多能背下來了,不急,再加上編輯器還緩存著幾個(gè)文件代碼,復(fù)制粘貼來,最主要的是代碼又很精簡(jiǎn)。 第二天騎著我那巨無霸山地車到了親戚家聚會(huì),花了一兩個(gè)小時(shí)給寫了回來。 順便向一用Java,站在我旁邊看我coding的美女炫耀了一番我程序,把她驚奇得一個(gè)勁兒地問我一臺(tái)電腦怎么可能認(rèn)識(shí)幾百萬,幾千萬的電腦? 怎么可能把他們電腦的共享資源給收集下來? 怎么可能你服務(wù)器就只記錄這么點(diǎn)信息? 怎么可能服務(wù)器還不用承受資源下載負(fù)擔(dān)? 還問我的什么語(yǔ)言,代碼看起來一點(diǎn)不像代碼? 我都一一自豪又耐心地回答。 我也看了她那Java寫的代碼,寫得很搞笑,都是些Dog/Cat/Master/Food Class什么的,好吧,她是個(gè)大學(xué)生,那些都是跟著他們老師寫的。 也順便給她說了句,設(shè)計(jì)模式要穩(wěn)打穩(wěn)扎地學(xué),學(xué)得隨手拈來才接下一個(gè),免得像邯鄲學(xué)步,都忘了如何走路,趴著回來,多看看開源代碼,少看點(diǎn)爛書。 話說,在聚會(huì)時(shí),人人都在玩游戲,而你戴著一副防光鏡編程,是一件多么拉風(fēng)的事情。 當(dāng)然也有人明著暗著說編程有個(gè)毛線用,我一笑了之。 借用Zed A。 Shaw說的: 當(dāng)有人說你編程像個(gè)怪物,不隨大眾,與眾不同,甚至因戳穿了他們的邏輯漏洞而他們開始和你爭(zhēng)辯,不用鳥他們,他們只是嫉妒你掌握了他們做夢(mèng)都不能得到的技能而已,要記住這是你的旅程,不是他們的。 后來吸取經(jīng)驗(yàn),整了個(gè)bitbucket來做備份,私有代碼免費(fèi)滴。
實(shí)現(xiàn)了DHT還不夠,得想辦法弄到種子文件,只有這樣才能做一個(gè)資源下載站,看了很多開源DHT爬蟲程序,要么沒實(shí)現(xiàn),要么就是通過HTTP向別的種子站下載,這方式對(duì)我來說,有種危機(jī)感,萬一那種子站關(guān)閉了咋辦? 而且沒成就感有木有? 所以還是要自己實(shí)現(xiàn)協(xié)議整一個(gè)BT客戶端,看了好幾天協(xié)議文檔,還是搞不懂怎么實(shí)現(xiàn),借鑒的也只有l(wèi)ibtorrent,但是太龐大,C/C++語(yǔ)言又不是很熟悉,所以暫時(shí)把它當(dāng)庫(kù)在Python里調(diào)用,好歹也是靠自己去DHT網(wǎng)絡(luò)下載的,比那些使用HTTP下別人的種子強(qiáng)多了。 等休息一段時(shí)間再來研究,連續(xù)4,5個(gè)月沒怎么好好休息了。
后來,一件件讓我發(fā)瘋的事情出現(xiàn),我買的3G無線網(wǎng)卡居然停機(jī)了,沒法測(cè)試種子下載部分代碼。 于是只好帶著筆記本到我們這鄉(xiāng)村唯一的網(wǎng)吧去上網(wǎng),使用小米的網(wǎng)絡(luò)共享,開啟熱點(diǎn)。 霉運(yùn)未就此打住,連上USB不能直接使用網(wǎng)絡(luò)共享,得安裝小米助手,但是小米助手里有驅(qū)動(dòng),很多網(wǎng)吧可是禁止安裝驅(qū)動(dòng),一安立馬重啟,重啟后可啥都沒了,后來鼓搗鼓搗,把那小米安裝文件設(shè)置成windows 2000兼容模式,搞定,只是不穩(wěn)定,易崩潰。 霉運(yùn)又接著開始,根本就沒法進(jìn)行ICMP和UDP(網(wǎng)吧電腦可以),始終不了解原因。 后來把之前用來測(cè)試DHT那部分的阿里云主機(jī)搞來,在那上面測(cè)試,由于不支持Gentoo(諧音"賤兔"),那些Ubuntu,CentOS,Debian真的很難用有木有,使用包管理自定義個(gè)軟件安裝參數(shù)都不支持(就是像源代碼安裝configure自定義參數(shù)那樣,可以開啟什么關(guān)閉什么的),軟件源又老,雖然Debian/Ubuntu可以ppa什么的,使用源代碼安裝又有那么多的依賴要整。 花了好長(zhǎng)時(shí)間都沒搞定,棄用之。
真疑惑國(guó)外那么流行的Gentoo為什么在國(guó)內(nèi)得不到重視? 是不是Gentoo太低調(diào)了? 還是Gentoo咋一看很難用? 在國(guó)內(nèi)也僅知道晉江文學(xué)城,豆瓣,知乎在用Gentoo。 后兩者還用的是Python做web端開發(fā)。 于是乎又到budgetvm開了個(gè)VPS,支持Gentoo,這個(gè)更讓我發(fā)瘋,始終無法啟動(dòng),問他們神馬原因,居然說Gentoo template出了問題,在修復(fù)。 建議我用Ubuntu/CentOS/Debian神馬的,我要是愛用這倆,我還到你那干嗎? 由于僅會(huì)閱讀英語(yǔ),不擅長(zhǎng)寫,沒法用長(zhǎng)一點(diǎn)的英語(yǔ)"批評(píng)"他們。 于是回復(fù)等待他們修。 第一通宵就繼續(xù)研究我電腦為嘛無法UDP/ICMP(這可不是神馬防火墻,殺毒軟件的問題,我是裸奔的,知道的大神指教下,只有在借助于小米手機(jī)電腦網(wǎng)絡(luò)共享才會(huì)這樣,連接真正的無線路由器可不會(huì)這樣)
第三天晚,還是沒收到budgetvm給我的Gentoo template修好就給我Email的信息,我當(dāng)時(shí)就在想,國(guó)外的客服說不定也像國(guó)內(nèi)一樣,敷衍了事。 于是又冒雨翻山越嶺去了網(wǎng)吧,打開budgetvm,能啟動(dòng)Gentoo了,真不敬業(yè),說好要通知的。 可是。。。可是為嘛不能SSH? 連網(wǎng)吧電腦ping都不能ping? 提交ticket詢問之,沒給我解決,一氣之下,又棄之! 我算是死心了,只好到城里再說了。 短時(shí)間可找不到價(jià)格便宜,支持Gentoo,支付寶的VPS。 于是坐在網(wǎng)吧那下幾個(gè)電影放松放松。 感謝我一兄弟,陪我熬了倆通宵,受不了通宵,一直躺在我大腿上睡覺,幸好帶了被子,這里很冷的有木有? 更丟臉的是,因錢包忘在老家,網(wǎng)費(fèi)都是他付的。 話說我教他前端編程,不過他人太帥,人緣好,事多,無法專心,沒學(xué)會(huì)。
在工地的最后兩個(gè)月是我人生最邋遢的日子,白天搬磚,晚上coding。 為省時(shí)間,兩個(gè)月不洗澡,不洗頭,洗腳都是涼水沖沖,臟衣服積累了幾十斤,在工地休息時(shí)也處于神游狀態(tài)。 話說工地上那些人要不是看過我在黑洞洞屏幕前編寫代碼的那"神秘感",都以為我腦子不正常來著,怪不得工地上的一癡呆小工都喜歡和我說話。
寫這個(gè)程序給我?guī)韼讉€(gè)好處:
0,編程技能上升一個(gè)等級(jí),都不敢直視以前那些亂用各種各樣的設(shè)計(jì)模式混在一堆四不像PHP代碼;
1,英語(yǔ)被逼到能看懂技術(shù)文檔,爽歪了我,更加熱愛英語(yǔ)了;
2,成了Python教徒,話說無"宗教感"的程序員不是好程序員,哈哈,這當(dāng)然不是說程序員要被編程語(yǔ)言所禁錮,要根據(jù)不同的項(xiàng)目選用合適的語(yǔ)言;
最后,我想說一句: 你會(huì)編程,他們不會(huì),這真tmd的酷!