第一方法用第三方庫(requests):參考http://www.mamicode.com/info-detail-1839685.html
源代碼分析
博客園的登錄頁面非常簡單,查看網頁源代碼,可以發現兩個輸入框的id分別為input1、input2,復選框的id為remember_me,登錄按鈕的id為signin。
還有一段JavaScript代碼,下面來簡單分析一下。
先來看$(function(){});函數:
1 $(function () { 2 $(‘#signin‘).bind(‘click‘, function () { 3 signin_go(); 4 }).val(‘登 錄‘); 5 });
$(function(){});是$(document).ready(function(){})的簡寫。當頁面加載完成之后,$(function(){})里的代碼就會被執行。
$(‘#signin‘)表示選取id為signin的元素,即登錄按鈕。
bind()方法為被選元素添加一個或多個事件處理程序,並規定事件發生時運行的函數。
val()方法返回或設置被選元素的值。
當點擊登錄按鈕時,將執行signnin_go()函數。
JSEncrypt是一個用於RSA加密的庫。在signnin_go()函數中,通過JSEncrypt對用戶名和密碼進行了加密,setPublicKey()函數里面就是加密的公鑰。
$(‘#remember_me‘).prop(‘checked‘)返回復選框的狀態,勾選時返回true,否則返回false。
兩段加密后的密文和復選框的狀態被保存在一個名為ajax_data的對象里。代碼如下:
1 var encrypt = new JSEncrypt(); 2 encrypt.setPublicKey(‘MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB‘); 3 var encrypted_input1 = encrypt.encrypt($(‘#input1‘).val()); 4 var encrypted_input2 = encrypt.encrypt($(‘#input2‘).val()); 5 var ajax_data = { 6 input1: encrypted_input1, 7 input2: encrypted_input2, 8 remember: $(‘#remember_me‘).prop(‘checked‘) 9 };
然后就是最主要的$.ajax({})函數了,ajax()方法通過HTTP請求加載遠程數據,在不刷新頁面的情況下與服務器交換數據,返回其創建的 XMLHttpRequest 對象。詳情請參考jQuery ajax - ajax() 方法
1 $.ajax({ 2 url: ajax_url, 3 type: ‘post‘, 4 data: JSON.stringify(ajax_data), 5 contentType: ‘application/json; charset=utf-8‘, 6 dataType: ‘json‘, 7 headers: {‘VerificationToken‘: ‘。。。省略,此處是一大串字符。。。‘}, 8 success: function (data) { 9 if (data.success) { 10 $(‘#tip_btn‘).html(‘登錄成功,正在重定向...‘); 11 location.href = return_url; 12 } else {} 13 }, 14 error: function (xhr) {} 15 });
上面的代碼中做了一些省略。需要特別注意的是headers屬性,刷新之后,VerificationToken的值將會改變,所以在模擬登錄時,必須先獲取這一段字符串。登錄成功后,頁面將進行跳轉。
抓包分析
這是登錄時的POST請求,其中有3個參數要特別注意:
VerificationToken就是上文中提到的一段變化的字符串。
Ajax異步請求比傳統的同步請求多了一個頭參數,即X-Requested-With。
Content-Type用於定義網絡文件的類型和網頁的編碼,決定瀏覽器將以什么形式、什么編碼讀取這個文件,這就是經常看到一些Asp網頁點擊的結果卻是下載到的一個文件或一張圖片的原因。在這里返回的是json格式的數據。當輸入錯誤的用戶名和密碼時,將得到下面的json數據:
正確的用戶名和密碼將得到{"success":true}
1 import requests 2 import json 3 login_url="https://passport.cnblogs.com/user/signin" 4 return_url="https://home.cnblogs.com/u/xxx/"#我的主頁 5 session=requests.session() 6 #獲取VerificationToken 7 login_page=session.get(login_url) 8 p=login_page.text.find('VerificationToken')+len('VerificationToken')+4 9 token=login_page.text[p:login_page.text.find("'",p)] 10 print(token) 11 headers={ 12 'Content-Type': 'application/json;charset=UTF-8', 13 'X-Requested-With': 'XMLHttpRequest', 14 'VerificationToken':token 15 } 16 session.headers.update(headers) 17 #可以通過抓包獲取加密后的用戶名和密碼,我將在附錄部分介紹如何在Python中加密 18 data={ 19 'input1': "加密的用戶名", 20 'input2': "加密的密碼", 21 'remember':True 22 } 23 24 #模擬登錄 25 response=session.post(login_url,data=json.dumps(data)) 26 print(response.text) 27 #{"success":true} 28 #登錄成功 29 30 #跳轉到主頁 31 home_page=session.get(return_url) 32 #獲取主頁標題 33 p=home_page.text.find('<title>')+len('<title>') 34 title=home_page.text[p:home_page.text.find('</title>',p)] 35 print(title) 36 #xxx的主頁 - 博客園 37 #如果登錄失敗,跳轉到主頁時返回的結果沒有title標簽,home_page.text將為‘需要登陸‘
第二種方法:用自帶的庫(urllib.request)
1 #-*- coding:utf-8 -*- 2 __author__ = 'Administrator' 3 4 #coding:utf-8 5 import re 6 from bs4 import BeautifulSoup 7 import urllib.request 8 import urllib.parse 9 import http.cookiejar 10 import requests 11 12 13 def get_opener(): 14 cj=http.cookiejar.CookieJar() 15 pro=urllib.request.HTTPCookieProcessor(cj) 16 opener=urllib.request.build_opener(pro) 17 return opener 18 19 if __name__=="__main__": 20 opener=get_opener() 21 login_url="https://passport.cnblogs.com/user/signin" 22 return_url="https://home.cnblogs.com/u/xxx/"#我的主頁 23 24 #獲取VerificationToken 25 login_page=opener.open(login_url).read().decode('utf-8') 26 soup=BeautifulSoup(login_page,"html.parser") 27 script=soup.find_all('script') 28 scripttext=script[2].string.strip() 29 p=re.findall('\'VerificationToken\': \'.*?\'',scripttext)[0] 30 start=len('VerificationToken')+5 31 token=p[start:-1] 32 33 headers={ 34 'Content-Type': 'application/json;charset=UTF-8', 35 'X-Requested-With': 'XMLHttpRequest', 36 'VerificationToken':token 37 } 38 39 #可以通過抓包獲取加密后的用戶名和密碼 40 data={ 41 'input1': "加密的用戶名", 42 'input2': "加密的密碼", 43 'remember':True 44 } 45 heads=[] 46 for key,value in headers.items(): 47 heads.append((key,value)) 48 login_data=urllib.parse.urlencode(data).encode('utf-8') 49 opener.addheaders=heads 50 Req=urllib.request.Request(login_url,data=login_data) 51 response= opener.open(Req) 52 print(response.read().decode('utf-8')) 53 #{"success":true} 54 #登錄成功 55 56 #跳轉到主頁 57 home_page=opener.open(return_url) 58 #獲取主頁標題 59 soup=BeautifulSoup(home_page.read().decode('utf-8'),"html.parser") 60 p=soup.find('title') 61 print(p.text) 62 #xxx的主頁 - 博客園 63 #如果登錄失敗,跳轉到主頁時返回的結果沒有title標簽,則‘需要登陸‘