最近學習了Fiddler抓包工具的簡單使用,通過抓包,我們可以抓取到HTTP請求,並對其進行分析。現在我準備嘗試著結合Python來模擬GitHub登入。
Fiddler抓包分析
首先,我們想要模擬一個網站的登入,我們必須要簡單瞭解其大致過程。
在這裡,我通過Fiddler來抓取GitHub登入的請求,從網頁上登入的URL為:https://github.com/login ,抓包結果如下:
左邊的是會話列表,右邊的是請求和響應的資料。一般情況下,登入都是用POST請求,因為我在左邊的會話列表中設定了顯示RequestMethod一列,因此能夠很方便的找到POST請求。當然,Fiddler預設不顯示RequestMethod,如果沒有設定,還可以通過命令“=post”來快速過濾POST請求。
在GitHub登入時,我們通過抓包發現,GitHub登入的URL雖然時https://github.com/login,但發生了302重定向,其真正提交POST表單資料的URL是 https://github.com/session ,當登入成功時,則會跳轉到 https://github.com/ 首頁。
開啟WebForm,我們可以看到POST表單資料提交的值,可以發現,只有authenticity_token、login、password三個欄位是會變化的,其餘的每次登入都是固定的值。而login、password分別是我們登入的使用者和密碼,因此我們只需要分析出 authenticity_token 從何而來,便可以實現模擬登入了。
至於如何確定 authenticity_token 從哪個頁面返回的,我們直接在響應資料中搜尋就行了,或者把資料複製出來再進行搜尋。最後我們會發現,authenticity_token 是在 https://github.com/login 這個請求中返回的,只不過用 hidden 隱藏起來了。
好了,到目前大致流程我們已經梳理清楚了,接下來我們便通過Python來實現模擬GitHub登入。
程式碼實現
本人環境:PyCharm 2018.2.4、Python3.7.0
1. 設定請求頭和Session
# 設定Session
self.s = requests.session()
# 設定請求頭
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:44.0) Gecko/20100101 Firefox/44.0"
}
# 在使用Fiddler時進行請求,通過該程式碼忽略SSLError錯誤
self.s.verify = False
在這裡,我們設定了Session會話物件,Session相當於1個微型瀏覽器,能夠自動幫我們保持請求中的某些引數(如cookies),有了它,我們一般不需要額外去處理cookies、header等。
假如我們是在Fiddler開啟的狀態下,通過程式碼進行請求,那麼將會遇到SSLError的錯誤,而當加上 self.s.verify = False 這行程式碼後,我們便可以忽略該錯誤。
requests.exceptions.SSLError: HTTPSConnectionPool(host='github.com', port=443): Max retries exceeded with url: /login (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1045)')))
注意:
我們通過上面的程式碼忽略了SSLError的錯誤後,再次執行,這時仍然會出現2行警告,這2個警告並不影響我們的登入,可以不管它。
D:\Python\installation\lib\site-packages\urllib3\connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
D:\Python\installation\lib\site-packages\urllib3\connectionpool.py:847: InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
InsecureRequestWarning)
如果我們想去掉這2行警告,也可以通過如下程式碼來解決(針對Python3):
import urllib3
urllib3.disable_warnings()
2. 獲取authenticity_token
login_url = "https://github.com/login"
r = self.s.get(login_url, headers = self.headers)
authenticity_token = re.findall('<input type="hidden" name="authenticity_token" value="(.+?)" />', r.text)
print("authenticity_token:{}".format(authenticity_token))
return authenticity_token[1]
當我們訪問 https://github.com/login 時,登入介面會生成隱藏引數authenticity_token,而這恰是我們在登入提交表單時需要用到的引數。我們可通過正規表示式 re.findall 來獲取authenticity_token。另外,我們還會發現,HTML介面中存在2個authenticity_token,因此通過正則返回的是一個長度為2的列表,經過分析,GitHub在登入時用到的是列表中的第二個元素,即authenticity_token[1]。
3. 模擬登入
def github_login(self, authenticity_token, username, password):
session_url = "https://github.com/session"
body = {
"authenticity_token":authenticity_token,
"commit":"Sign in",
"login":username,
"password":password,
"utf8":"✓",
"webauthn-support":"unknown"
}
r = self.s.post(session_url, headers = self.headers, data = body)
title = re.findall('<title>(.+?)</title>',r.text)
print("title:%s" %title[0])
return title[0]
我們在上面得到authenticity_token後,便可以來實現登入了。通過POST請求提交表單後,我們需要判斷是否登入成功。在這裡,我是通過頁面的標題來判斷GitHub是否登入成功,當然,還有許多方法可以用於判斷。
4. 通過 title 判斷是否登入成功
def is_login_success(self, title):
if "GitHub" == title:
return True
else:
return False
GitHub登入成功後,介面的標題會顯示"GitHub",而登入失敗時,一般顯示的標題則是"Sign in to GitHub · GitHub"。
OK,以上就是通過Python模擬GitHub登入的過程,難度不大,相信大多數人閱讀後都應該可以進行實踐。
附原始碼:
import requests
import re
import urllib3
urllib3.disable_warnings()
class Github_Login():
def __init__(self):
# 設定Session
self.s = requests.session()
# 設定請求頭
self.headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:44.0) Gecko/20100101 Firefox/44.0"
}
# 在使用Fiddler時進行請求,通過該程式碼忽略SSLError錯誤
self.s.verify = False
# 獲取 authenticity_token
def get_authenticity_token(self):
login_url = "https://github.com/login"
r = self.s.get(login_url, headers = self.headers)
authenticity_token = re.findall('<input type="hidden" name="authenticity_token" value="(.+?)" />', r.text)
print("authenticity_token:{}".format(authenticity_token))
return authenticity_token[1]
# 模擬登入,並返回 title
def github_login(self, authenticity_token, username, password):
session_url = "https://github.com/session"
body = {
"authenticity_token":authenticity_token,
"commit":"Sign in",
"login":username,
"password":password,
"utf8":"✓",
"webauthn-support":"unknown"
}
r = self.s.post(session_url, headers = self.headers, data = body)
title = re.findall('<title>(.+?)</title>',r.text)
print("title:%s" %title[0])
return title[0]
# 通過 title 判斷是否登入成功
def is_login_success(self, title):
if "GitHub" == title:
return True
else:
return False
if __name__ == '__main__':
github = Github_Login()
authenticity_token = github.get_authenticity_token()
title = github.github_login(authenticity_token, username = "使用者名稱", password = "密碼")
login_result = github.is_login_success(title)
print(login_result)
如有錯誤,歡迎指出!