Discuz在X3中增加了防採集功能,具體見Discuz x3.0防採集設置圖文教程
開啟防採集後,訪問DZ站點的偽靜態鏈接如http://www.discuz.net/thread-3275423-1-1.html後面會跟上一個?_dsign=xxxxxx,正常鏈接如http://www.discuz.net/forum.php?mod=viewthread&tid=3305274會加上&_dsign=xxxxxx。這讓人很不爽 (o#゜ 曲゜)o
使用httplib2訪問原帖子頁面(下面以http://www.dz.net/forum.php?mod=viewthread&tid=768為例),返回的是一段混淆過的js,如:
1 |
<script type="text/javascript">RKbW=function(){'RKbW';var _R=function(){return '=76'}; return _R();};function AIV(AIV_){function _A(AIV_){function ph(){return getName();}function AIV_(){}return ph();return AIV_}; return _A(AIV_);}DmZP='iew';_IX161 = 'assign';function zoQ(zoQ_){function ti(){return getName();};return ti();return 'zoQ'}function r2oe(){'return r2oe';return 'ad&'}_eloda = 'replace';F59s=function(){'return F59s';return 'p?m';};HP=function(){'return HP';return 'n';};function getName(){var caller=getName.caller;if(caller.name){return caller.name} var str=caller.toString().replace(/[\s]*/g,"");var name=str.match(/^function([^\(]+?)\(/);if(name && name[1]){return name[1];} else {return '';}}uM=function(){'return uM';return '9';};eG9=function(eG9_){'return eG9';return eG9_;};function kp(kp_){function _k(kp_){function o(){return getName();}function kp_(){}return o();return kp_}; return _k(kp_);}vD='1';BN=function(){'BN';var _B=function(){return 'r'}; return _B();};HALw='rum';_RZnE9 = 'href';o5y=function(o5y_){'return o5y';return o5y_;};function PH(){'return PH';return '.'}_BDkwZ = location;function w2(){'return w2';return '_'}KTI4=function(){'return KTI4';return '910';};_NUuAJ = window;wX=function(){'wX';var _w=function(){return 'd'}; return _w();};iyL=function(iyL_){'return iyL';return iyL_;};location.replace((function(){'return Q8mM';return '/fo'})()+HALw+PH()+AIV('Gs8')+F59s()+kp('nm')+(function(){'return njFH';return (function(){return 'd=v';})();})()+DmZP+eG9('th')+BN()+(function(){'return XD';return 'e'})()+r2oe()+zoQ('yKM')+wX()+RKbW()+'8&'+w2()+o5y('ds')+iyL('ig')+HP()+(function(){'return l26W';return '=6f'})()+uM()+(function(){'return by';return (function(){return '7';})();})()+KTI4()+vD);_NUuAJ['href']=(function(){'return Q8mM';return '/fo'})()+HALw+PH()+AIV('Gs8')+F59s()+kp('nm')+(function(){'return njFH';return (function(){return 'd=v';})();})()+DmZP;</script> |
顯然這樣人類是無法理解的……不過使用notepad++的JSFormat插件格式化後還是能看懂的嗯-v-
實際上這是一個字符串替換然後重定向的腳本,生成原理如下(不完全按照上面的例子):
- 原始字符串為location.href=forum.php?mod=viewthread&tid=768&_dsign=6f979101
- 隨機分割這個這個串,如分成l, oc, a, tio, n., ……
- 對每一個子串替換成一個隨機命名的函數,如l替換成_Oc9S(),則在腳本里加一句function _Oc9S(){return ‘l’;}以此類推
- 每個function都可能加入奇怪的例如’return l;’這樣毫無意義的混淆
- 最後在末尾加上window.href=yyy,yyy為取forum.php?mod=viewthread&tid=768&_dsign=6f979101的前x個字符後得到一個子串
我大概寫得不清楚……就……這麼個意思……
毫無疑問要使用PyV8了,本來想自己寫個解釋器,但是算法太渣只能嗚呼哀哉QAQ
這裡有個問題,PyV8隻是一個js解釋器的包裝,不是瀏覽器的js運行時,因此location啊window啊都是undefined的,所以要手動把這些都去掉。(有一點要說明,就是由於js很騷,location.href有時會被寫成location[‘href’],或者用location.assign或者location.replace,而assign和replace都可能被一個隨機命名的變量替換掉了)
直接看代碼吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import PyV8 import re js='''<script type="text/javascript">.........</script>''' #去掉<script>標籤 js=js[31:-9] for st in ['window','location',"'assign'","'href'","'replace'"]: equal=re.findall('[_A-Za-z0-9 =]+%s;'%st,js)#找到變量賦值等式 if equal==[]:#有可能沒有 continue else: equal=equal[0] var=equal.split('=')[0].strip()#找出變量名 #把等式幹掉 js=js.replace(equal,'') #把變量替換成它真正的意思 js=js.replace(var,st) #把['xx'] 替換成 .xx js=js.replace("['%s']"%st.strip("'"),'.%s'%st.strip("'")) #將 window.href= 後的內容踢掉,因為當PyV8隻輸出最後一個等式的值 if re.findall('window\.href=.+',js)!=[]: js=js.replace(re.findall('window\.href=.+',js)[0],'') #刪掉location.xxx= js=js.replace('location.href=','').replace('location.replace','').replace('location.assign','') #交給你了-v- ctxt2 = PyV8.JSContext() ctxt2.enter() print ctxt2.eval(js) |
這樣就得到了包含dsign的新url,可以繼續爬了
最後對DZ的防採集再說幾句
- 防採集是對IP不對用戶的
- 而且要看站長的設置,有可能只對帖子或日誌等開啟;你們可以到Discuz x3.0防採集設置圖文教程感受一下
- _dsign的值是固定的,計算完一次js後可以考慮保存起來,以後可以直接訪問加上_dsign的url
- 防採集是針對不支持js的機械人的,如果用python直接控制瀏覽器的話,可以無視之
- 如果mechanize和PyV8能合體那該多好~ o(* ̄▽ ̄*)o
Done,繼續去抓ラブリーマイエンジェルあやせたん♪的寫真了嗯哼哼哼
幸好俺的蟲子支持JS。
一定不是python