CF665E Beautiful Subarrays(Tire)
上班都快一週了,一直想更新,奈何小夥還沒有從假期的快樂中緩過來,今天終於耐下心來更新一小篇。摳一下某品會的JS程式碼,接著使用摳取的JS程式碼加密密碼進行登入。友情提示:為避免不必要的糾紛,本文中所有網址都進行了一定隱藏。看完本文覺得有幫助關注一下知識圖譜與大資料公眾號吧,有大量摳JS程式碼的文章,當然不關注也無所謂,完整程式碼點選文末閱讀原文。如有侵權,聯絡刪除。
目標
標題已經闡明瞭本文的目的:
- 密碼加密解密;
- 利用第一步加密方法加密後進行登入;
- 完整程式碼中嘗試了多賬號號批量登入(由於篇幅有限,移動到了閱讀原文中);
摳出程式碼
找到目標網站,進入登入頁面(對各位來說都很easy):
像以往一樣輸入錯誤的賬號密碼,看看提交的資料,點選登入後,提交賬號密碼url如下:
繼續看FormData,如下圖:
圖中的loginName為你輸入的使用者名稱,password為密碼,可以看出被加密了,如果你熟悉了各類JS加密方式,心裡應該能大概確定這就是MD5加密結果。暫時不用管其它的四個引數,接下來無非就是把加密JS程式碼摳出來,可以通過呼叫棧進去,也可以全域性搜尋password來定位JS檔案,具體使用哪種方法就看各位看官的喜好了,我這裡是從呼叫棧進去的(既然我們是在登入,那就點帶有login字樣的js檔案進去好了):
進來後你可以搜一下password關鍵字,應該馬上就能定位到想要的位置,定位的時候別忘了掛上一個斷點,就像下圖一樣:
一看加密方法名就是熟悉的MD5,接下來的操作應該更加熟悉了,啟用斷點(輸入賬號密碼,點選登入,前提是你掛上了斷點)。
點選後就進入了加密方法裡:
function md5(string, key, raw) { if (!key) { if (!raw) return hex_md5(string); return raw_md5(string) } if (!raw) return hex_hmac_md5(key, string); return raw_hmac_md5(key, string) }
可以看出md5方法一共有三個引數,第一個striing即為密碼,key和raw是undefined。接下笨一點的辦法就是一步一步執行,把跳轉的所有程式碼都扣下來,如果是剛開始學習摳程式碼,這個方法能增加很多除錯”感覺”,慢慢摳得越來越順手。取巧一點的無非就是找到大括號:
一直往上找到,應該馬上就能找到正括號:
這樣裡面的程式碼其實就是本次要摳的程式碼,但是要使用python呼叫,還要進行一點改動。本次要摳的加密程式碼其實很簡單,畢竟只是md5。經過稍微改寫後,我們嘗試使用python裡execjs庫執行:
成功執行出結果,摳取完畢。
登入
FormData
通過上一節,我們已經可以得到加密後的密碼,既然要登入,那就要回到FormData中,看看幾個引數的含義與取值,經過一番測試,總結如下,感興趣的也可以自己去試一下。
引數取值loginName使用者名稱password加密後的密碼remUser是否記住使用者名稱(0或者1)whereFrom可為空captchaId驗證碼(可為空)captchaTicket可為空
Cookies
現在的登入都需要攜帶cookies,看一下本站登入時候的Cookies:
看起來很多,但是經過測試並不需要全部攜帶,cookies應該是服務端產生的,所以還是老老實實帶上吧,沒有捷徑。經過粗略測試,攜帶以下幾個即可登入:
cookies = { ' mars_pid': '你的', ' cps': '你的', ' mars_sid': '你的', 'times_XXXXX': '你的', ' VipRUID': '你的', ' VipRNAME': '', ' VipDegree': '你的', ' user_class': '你的', ' VipCI_te': '你的', 'mars_cid': '你的' }
有興趣的可以繼續試試這裡面還有沒有可以不用攜帶的。
Header
不管是登入還是爬取某個網頁,請求頭是絕對繞不過的,現在一起看看本站的請求頭都有哪些:
好傢伙,各種都有,不過大家不用擔心,經過測試在本文實際爬取過程中只用攜帶user-agent,平時的爬取過程中,有些可能會檢查上一個網頁是在哪裡,即要攜帶referer,還有origin和host也是可能會攜帶的。
正式登入
本次登入的幾個要點在前面應該算已經闡述清楚了,現在要做的無非就是把FormData裡的資料post到login_url。
flowchat st=>start: 開始 e=>end: 結束 op0=>operation: 輸入賬號密碼 op1=>operation: 執行js程式碼加密密碼 op=>operation: 組裝formdata op2=>operation: 把formdata post到登入url op3=>operation: 分析返回 st->op0->op1->op->op2->op3->e
好了,流程知道了開始寫程式碼,友情提示:由於可能引起一些不必要的紛爭,程式碼中的url和cookies值都隱藏了,大家按照自己的新增即可。建立了一個VipLogin類,下面是部分模組的程式碼。
執行js程式碼
@property def exec_js(self): """ 你自己的js路徑 :return: """ with open('..//js//weipinhui.js', encoding='utf-8') as f: weipinhui = f.read() js = execjs.compile(weipinhui) return js
加密密碼
def get_pwd(self,password): key = "" raw = "" pwd = self.js.call('md5', password, key, raw) logger.info("加密結果為:{}".format(pwd)) return pwd
使用者名稱加密
def encrypt_phone(self,phone): return phone[:3]+"*"*5+phone[-3:]
提交資料
def login(self,user,passwd): if not user.isdigit or len(user) != 11: logger.error("目前僅支援手機號方式登入:{}".format(user)) return False session = requests.Session() vip_name = self.encrypt_phone(user) times_key = "times_"+user data = { "loginName": user, "password": passwd, "remUser": "0", "whereFrom":"", "captchaId":"" , "captchaTicket":"", } ck_dict = { ' mars_pid': '你的', ' cps': '你的', ' mars_sid': '你的', times_key: '你的', ' VipRUID': '你的', ' VipRNAME': vip_name, ' VipDegree': '你的', ' user_class': '你的', ' VipCI_te': '你的', 'mars_cid': '你的' } requests.utils.add_dict_to_cookiejar(session.cookies,ck_dict) resp = session.post(self.login_url,headers=self.headers,data=data,verify=False) ret = json.loads(resp.text) logger.info("賬號{}返回結果為:{}".format(self._encrypt_phone(user),ret)) if ret.get("result","") == "success": return True return False
登入結果
登入成功的標誌為'result': 'success‘如下:
{ 'result': 'success', 'errorCode': 0, 'data': { 'redirectUrl': 'https://www.xxx.com', 'captchaFlowData': None, 'extend': None, 'bindMobile': True, 'illegalState': False }, 'redirectUrl': 'https://www.xxx.com' }