微博爬蟲“免登入”技巧詳解及Java 實現- 程式人生
文章推薦指數: 80 %
作為前篇的重點內容,本文詳細介紹如何獲取相關的Cookie並重新封裝Httpclient達到免登入的目的,以支援微博上的各項資料抓取任務。
下面就從微博 ...
程式人生>>微博爬蟲“免登入”技巧詳解及Java實現
微博爬蟲“免登入”技巧詳解及Java實現
阿新••發佈:2018-12-23
一、微博一定要登入才能抓取?
目前,對於微博的爬蟲,大部分是基於模擬微博賬號登入的方式實現的,這種方式如果真的運營起來,實際上是一件非常頭疼痛苦的事,你可能每天都過得提心吊膽,生怕新浪爸爸把你的那些賬號給封了,而且現在隨著實名制的落地,獲得賬號的渠道估計也會變得越來越少。
但是日子還得繼續,在如此艱難的條件下,為了生存爬蟲們必須尋求進化。
好在上帝關門的同時會隨手開窗,微博在其他諸如頭條,一點等這類新媒體平臺的衝擊之下,逐步放開了資訊流的檢視許可權。
現在的微博即便在不登入的狀態下,依然可以看到很多微博資訊流,而我們的落腳點就在這裡。
作為前篇的重點內容,本文詳細介紹如何獲取相關的Cookie並重新封裝Httpclient達到免登入的目的,以支援微博上的各項資料抓取任務。
下面就從微博首頁http://weibo.com開始。
二、準備工作
準備工作很簡單,一個現代瀏覽器(你知道我為什麼會寫”現代”兩個字),以及httpclient(我用的版本是4.5.3)
跟登入爬蟲一樣,免登入爬蟲也是需要裝載Cookie。
這裡的Cookie是用來標明遊客身份,利用這個Cookie就可以在微博平臺中訪問那些允許訪問的內容了。
這裡我們可以使用瀏覽器的network工具來看一下,請求http://weibo.com之後伺服器都返回哪些東西,當然事先清空一下瀏覽器的快取。
不出意外,應該可以看到下圖中的內容
第1次請求weibo.com的時候,其狀態為302重定向,也就是說這時並沒有真正地開始載入頁面,而最後一個請求weibo.com的狀態為200,表示了請求成功,對比兩次請求的header:
明顯地,中間的這些過程給客戶端載入了各種Cookie,從而使得可以順利訪問頁面,接下來我們逐個進行分析。
三、抽絲剝繭
第2個請求是https://passport.weibo.com/visitor……,各位可以把這個url複製出來,用httpclient單獨訪問一下這個url,可以看到返回的是一個html頁面,裡面有一大段Javascript指令碼,另外頭部還引用一個JS檔案mini_original.js,也就是第3個請求。
指令碼的功能比較多,就不一一敘述了,簡單來說就是微博訪問的入口控制,而值得我們注意的是其中的一個function:
JavaScript.
//為使用者賦予訪客身份。
varincarnate=function(tid,where,conficence){
vargenconf="";
varfrom="weibo";
varincarnate_intr=window.location.protocol+"//"+window.location.host+"/visitor/visitor?a=incarnate&t="+encodeURIComponent(tid)+"&w="+encodeURIComponent(where)+"&c="+encodeURIComponent(conficence)+"&gc="+encodeURIComponent(gen_conf)+"&cb=cross_domain&from="+from+"&_rand="+Math.random();
url.l(incarnate_intr);
};
1234567
//為使用者賦予訪客身份。
varincarnate=function(tid,where,conficence){vargenconf="";varfrom="weibo";varincarnate_intr=window.location.protocol+"//"+window.location.host+"/visitor/visitor?a=incarnate&t="+encodeURIComponent(tid)+"&w="+encodeURIComponent(where)+"&c="+encodeURIComponent(conficence)+"&gc="+encodeURIComponent(gen_conf)+"&cb=cross_domain&from="+from+"&_rand="+Math.random();url.l(incarnate_intr);};
這裡是為請求者賦予一個訪客身份,而控制跳轉的連結也是由一些引數拼接起來的,也就是上圖中第6個請求。
所以下面的工作就是獲得這3個引數:tid,w(where),c(conficence,從下文來看應為confidence,大概是新浪工程師的手誤)。
繼續閱讀原始碼,可以看到該function是tid.get方法的回撥函式,而這個tid則是定義在那個mini_original.js中的一個物件,其部分原始碼為:
JavaScript
vartid={
key:'tid',
value:'',
recover:0,
confidence:'',
postInterface:postUrl,
fpCollectInterface:sendUrl,
callbackStack:[],
init:function(){
tid.get();
},
runstack:function(){
varf;
while(f=tid.callbackStack.pop()){
f(tid.value,tid.recover,tid.confidence);//注意這裡,對應上述的3個引數
}
},
get:function(callback){
callback=callback||function(){
};
tid.callbackStack.push(callback);
if(tid.value){
returntid.runstack();
}
Store.DB.get(tid.key,function(v){
if(!v){
tid.getTidFromServer();
}else{
……
}
});
},
……
}
……
getTidFromServer:function(){
tid.getTidFromServer=function(){
};
if(window.usefp){
getFp(function(data){
util.postData(window.location.protocol+'//'+window.location.host+'/'+tid.postInterface,"cb=gen_callback&fp="+encodeURIComponent(data),function(res){
if(res){
eval(res);
}
});
});
}else{
util.postData(window.location.protocol+'//'+window.location.host+'/'+tid.postInterface,"cb=gen_callback",function(res){
if(res){
eval(res);
}
});
}
},
……
//獲得引數
window.gen_callback=function(fp){
varvalue=false,confidence;
if(fp){
if(fp.retcode==20000000){
confidence=typeof(fp.data.confidence)!='undefined'?'000'+fp.data.confidence:'100';
tid.recover=fp.data.new_tid?3:2;
tid.confidence=confidence=confidence.substring(confidence.length-3);
value=fp.data.tid;
Store.DB.set(tid.key,value+''+confidence);
}
}
tid.value=value;
tid.runstack();
};
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
vartid={key:'tid',value:'',recover:0,confidence:'',postInterface:postUrl,fpCollectInterface:sendUrl,callbackStack:[],init:function(){tid.get();},runstack:function(){varf;while(f=tid.callbackStack.pop()){f(tid.value,tid.recover,tid.confidence);//注意這裡,對應上述的3個引數}},get:function(callback){callback=callback||function(){};tid.callbackStack.push(callback);if(tid.value){returntid.runstack();}Store.DB.get(tid.key,function(v){if(!v){tid.getTidFromServer();}else{……}});},……}……getTidFromServer:function(){tid.getTidFromServer=function(){};if(window.usefp){getFp(function(data){util.postData(window.location.protocol+'//'+window.location.host+'/'+tid.postInterface,"cb=gen_callback&fp="+encodeURIComponent(data),function(res){if(res){eval(res);}});});}else{util.postData(window.location.protocol+'//'+window.location.host+'/'+tid.postInterface,"cb=gen_callback",function(res){if(res){eval(res);}});}},……//獲得引數window.gen_callback=function(fp){varvalue=false,confidence;if(fp){if(fp.retcode==20000000){confidence=typeof(fp.data.confidence)!='undefined'?'000'+fp.data.confidence:'100';tid.recover=fp.data.new_tid?3:2;tid.confidence=confidence=confidence.substring(confidence.length-3);value=fp.data.tid;Store.DB.set(tid.key,value+''+confidence);}}tid.value=value;tid.runstack();};
顯然,tid.runstack()是真正執行回撥函式的地方,這裡就能看到傳入的3個引數。
在get方法中,當cookie為空時,tid會呼叫getTidFromServer,這時就產生了第5個請求https://passport.weibo.com/visitor/genvisitor,它需要兩個引數cb和fp,其引數值可以作為常量:
該請求的結果返回一串json
JavaScript
{
"msg":"succ",
"data":{
"new_tid":false,
"confidence":95,
"tid":"kIRvLolhrCR5iSCc80tWqDYmwBvlRVlnY2+yvCQ1VVA="
},
"retcode":20000000
}
123456789
{"msg":"succ","data":{"new_tid":false,"confidence":95,"tid":"kIRvLolhrCR5iSCc80tWqDYmwBvlRVlnY2+yvCQ1VVA="},"retcode":20000000}
其中就包含了tid和confidence,這個confidence,我猜大概是推測客戶端是否真實的一個置信度,不一定出現,根據window.gen_callback方法,不出現時預設為100,另外當new_tid為真時引數where等於3,否則等於2。
此時3個引數已經全部獲得,現在就可以用httpclient發起上面第6個請求,返回得到另一串json:
JavaScript
{
"msg":"succ",
"data":{
"sub":"_2AkMu428tf8NxqwJRmPAcxWzmZYh_zQjEieKYv572JRMxHRl-yT83qnMGtRCnhyR4ezQQZQrBRO3gVMwM5ZB2hQ..",
"subp":"0033WrSXqPxfM72-Ws9jqgMF55529P9D9WWU2MgYnITksS2awP.AX-DQ"
},
"retcode":20000000
}
12345678
{"msg":"succ","data":{"sub":"_2AkMu428tf8NxqwJRmPAcxWzmZYh_zQjEieKYv572JRMxHRl-yT83qnMGtRCnhyR4ezQQZQrBRO3gVMwM5ZB2hQ..","subp":"0033WrSXqPxfM72-Ws9jqgMF55529P9D9WWU2MgYnITksS2awP.AX-DQ"},"retcode":20000000}
參考最後請求weibo.com的header,這裡的sub和subp就是最終要獲取的cookie值。
大家或許有一個小疑問,第一個Cookie怎麼來的,沒用嗎?是的,這個Cookie是第一次訪問weibo.com產生的,經過測試可以不用裝載。
最後我們用上面兩個Cookie裝載到HttpClient中請求一次weibo.com,就可以獲得完整的html頁面了,下面就是見證奇蹟的時刻:
XHTML
延伸文章資訊
- 1欢迎登录- 新浪微博
体验微博客户端>>. 注册 登录 · 使用QQ号码登录.
- 2Sina Visitor System - 微博
- 3Weibo 免登入、台灣微博登入 - 電影資訊懶人包
在Weibo 免登入這個討論中,有超過5篇Ptt貼文,作者MOONY135也提到作者: nichtich (nichtich) 看板: CFantasy 標題: [閒聊] 有用的修仙文時間: S...
- 4如何免登陆查看微博网页版,求赐教 - V2EX
微博- @kebamt - 从TopHub 等热榜网站点进去想看看新闻,却让强制登录, ... 更特殊的贴或者博主,非登入状态点进去不是要求登入,直接404,但是登入 ...
- 5微博爬蟲“免登入”技巧詳解及Java 實現- 程式人生
作為前篇的重點內容,本文詳細介紹如何獲取相關的Cookie並重新封裝Httpclient達到免登入的目的,以支援微博上的各項資料抓取任務。下面就從微博 ...