python3下使用requests實現模擬用戶登錄 —— 基礎篇(馬蜂窩)
1. 了解cookie和session
首先一定要先了解到cookie和session是什么,這是后面理解網站交互,模擬用戶登錄的基礎。
1.1. 無狀態協議:Http
如上圖所示,HTTP協議 是無狀態的協議,用戶瀏覽服務器上的內容,只需要發送頁面請求,服務器返回內容。對於服務器來說,並不關心,也並不知道是哪個用戶的請求。對於一般瀏覽性的網頁來說,沒有任何問題。
但是,現在很多的網站,是需要用戶登錄的。以淘寶為例:比如說某個用戶想購買一個產品,當點擊 “ 購買按鈕 ” 時,由於HTTP協議 是無狀態的,那對於淘寶來說,就不知道是哪個用戶操作的。
為了實現這種用戶標記,服務器就采用了cookie這種機制來識別具體是哪一個用戶的訪問。
1.2. 了解cookie
如圖,為了實現用戶標記,在Http無狀態請求的基礎之上,我們需要在請求中攜帶一些用戶信息(比如用戶名之類,這些信息是服務器發送到本地瀏覽器的,但是服務器並不存儲這些信息),這就是cookie機制。如下圖所示,在登錄馬蜂窩網站之后,就可以看到瀏覽器已經保存了一些cookie信息(chrome瀏覽器為例):
需要注意的是:cookie信息是保存在本地瀏覽器里面的,服務器上並不存儲相關的信息。 在發送請求時,cookie的這些內容是放在 Http協議中的header 字段中進行傳輸的。
幾乎現在所有的網站都會發送一些 cookie信息過來,當用戶請求中攜帶了cookie信息,服務器就可以知道是哪個用戶的訪問了,從而不需要再使用賬戶和密碼登錄。
但是,剛才也提到了,cookie信息是直接放在Http協議的header中進行傳輸的,看得出來,這是個隱患!一旦別人獲取到你的cookie信息(截獲請求,或者使用你的電腦),那么他很容易從cookie中分析出你的用戶名和密碼。為了解決這個隱患,所以有了session機制。
1.3. 了解session
剛才提到了cookie不安全,所以有了session機制。簡單來說(每個框架都不一樣,這只是舉一個通用的實現策略),整過過程是這樣:
服務器根據用戶名和密碼,生成一個session ID,存儲到服務器的數據庫中。
用戶登錄訪問時,服務器會將對應的session ID發送給用戶(本地瀏覽器)。
瀏覽器會將這個session ID存儲到cookie中,作為一個鍵值項。
以后,瀏覽器每次請求,就會將含有session ID的cookie信息,一起發送給服務器。
服務器收到請求之后,通過cookie中的session ID,到數據庫中去查詢,解析出對應的用戶名,就知道是哪個用戶的請求了。
1.3.1. 看一下Django是如何實現session機制的,來加深對session的了解
第一步:對用戶登錄信息進行加密,生成一個sessionID,存儲到數據庫中。
Session_key:服務器給用戶返回的ID
Session_data:一段加密的文字。用戶名,密碼,一些其他的用戶信息。把這些信息生成一段字符串,是加密的
expire_date:django后台會設置過期時間。 主要是擔心session被黑客截取,那就一直可以用,盜用數據。
1
2
3
第二步,當用戶登錄時,服務器會給本地瀏覽器返回一些cookie信息,包括session ID。
第三步:以后瀏覽器每次訪問時,瀏覽器都會把 session ID帶過來,這樣服務器不需要知道你的用戶名,就知道是哪個用戶的訪問了。
服務器是如何把sessionID轉換成用戶名的?
如上圖所示,在Django中,需要對session進行配置。這個INSTALLED_APPS 是會對每次request和response進行攔截,攔截到瀏覽器發送過來的request時,找到其中的session信息,然后到數據庫中進行查詢,找到session_data,再做解密,就知道所有的用戶信息了,取出user信息。新建完Django項目之后,這個sessions信息就配置好了。如果注釋掉這一個session配置,自動登錄機制就會失效,無法使用。
1.4. 總結一下
cookie 在客戶端(本地瀏覽器),session 在服務器端。cookie是一種瀏覽器本地存儲機制。存儲在本地瀏覽器中,和服務器沒有關系。每次請求,用戶會帶上本地cookie的信息。這些cookie信息也是服務器之前發送給瀏覽器的,或者是用戶之前填寫的一些信息。
Cookie有不安全機制。 你不能把所有的用戶信息都存在本地,一旦被別人竊取,就知道你的用戶名和密碼,就會很危險。所以引入了session機制。
服務器在發送id時引入了一種session的機制,很簡單,就是根據用戶名和密碼,生成了一段隨機的字符串,這段字符串是有過期時間的。
一定要注意:session是服務器生成的,存儲在服務器的數據庫或者文件中,然后把sessionID發送給用戶,用戶存儲在本地cookie中。每次請求時,把這個session ID帶給服務器,服務器根據session ID到數據庫中去查詢,找到是哪個用戶,就可以對用戶進行標記了。
session 的運行依賴 session ID,而 session ID 是存在 cookie 中的,也就是說,如果瀏覽器禁用了 cookie ,那么同時 session 也會失效(但是可以通過其它方式實現,比如在url中傳遞 session ID)
用戶驗證這種場合一般會用 session。 因此,維持一個會話的核心就是客戶端的唯一標識,即session ID
2. 環境
系統:win7
python 3.6.1
requests 2.14.2 (通過pip list查看)
3. 模擬登錄馬蜂窩網站
馬蜂窩:http://www.mafengwo.cn/
3.1. 分析用戶登錄流程
這里會用到兩個小技巧
第一,先使用一個錯誤的用戶名和密碼來登錄,這樣就可以清晰的看到這個登錄請求有post哪些數據,post到哪個url。因為如果使用正確的用戶名和密碼登錄,一旦登錄成功,就會直接跳轉到其他頁面,頁面和請求都會被刷新。很難找出原始的請求信息。
第二,在截取請求的地方,勾選Preserve log,保留跳轉前的請求數據。
截取到的請求如下:
#提取到的請求信息:
Headers:
Request URL:https://passport.mafengwo.cn/login/
Request Method:POST
origin:https://passport.mafengwo.cn
referer:https://passport.mafengwo.cn/
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Form Data:
passport:13725168940
password:aaa00000000
1
2
3
4
5
6
7
8
9
10
11
3.2. 模擬登錄
# -*- coding: utf-8 -*-
import requests
userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
header = {
# "origin": "https://passport.mafengwo.cn",
"Referer": "https://passport.mafengwo.cn/",
'User-Agent': userAgent,
}
def mafengwoLogin(account, password):
# 馬蜂窩模仿 登錄
print ("開始模擬登錄馬蜂窩")
postUrl = "https://passport.mafengwo.cn/login/"
postData = {
"passport": account,
"password": password,
}
responseRes = requests.post(postUrl, data = postData, headers = header)
# 無論是否登錄成功,狀態碼一般都是 statusCode = 200
print(f"statusCode = {responseRes.status_code}")
print(f"text = {responseRes.text}")
if __name__ == "__main__":
# 從返回結果來看,有登錄成功
mafengwoLogin("13756567832", "000000001")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
一般來說,調試期,判斷是否登錄成功的最簡單的方法:就是直接打印登錄之后的text內容,使用錯誤的用戶名登錄,和使用正確的用戶名登錄,對比打印輸出的內容。
后面會提出一個更好的判斷方式…
3.3. 使用cookie訪問站點
在上一步,我們已經成功登錄到馬蜂窩網站了。那么接下來要如何訪問站點中其他頁面呢。前面提到過,網站是通過cookie和session來標記是哪個用戶訪問的。所以,在我們登錄成功之后,有很重要的一步,就是我們需要把cookie保存下來,下一次請求這個站點的頁面時,把這個cookie帶過去。
3.3.1. 保存cookie信息
修改代碼,加入cookie保存機制:
# -*- coding: utf-8 -*-
import requests
# python2 和 python3的兼容代碼
try:
# python2 中
import cookielib
print(f"user cookielib in python2.")
except:
# python3 中
import http.cookiejar as cookielib
print(f"user cookielib in python3.")
# session代表某一次連接
mafengwoSession = requests.session()
# 因為原始的session.cookies 沒有save()方法,所以需要用到cookielib中的方法LWPCookieJar,這個類實例化的cookie對象,就可以直接調用save方法。
mafengwoSession.cookies = cookielib.LWPCookieJar(filename = "mafengwoCookies.txt")
userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
header = {
# "origin": "https://passport.mafengwo.cn",
"Referer": "https://passport.mafengwo.cn/",
'User-Agent': userAgent,
}
def mafengwoLogin(account, password):
# 馬蜂窩模仿 登錄
print("開始模擬登錄馬蜂窩")
postUrl = "https://passport.mafengwo.cn/login/"
postData = {
"passport": account,
"password": password,
}
# 使用session直接post請求
responseRes = mafengwoSession.post(postUrl, data = postData, headers = header)
# 無論是否登錄成功,狀態碼一般都是 statusCode = 200
print(f"statusCode = {responseRes.status_code}")
print(f"text = {responseRes.text}")
# 登錄成功之后,將cookie保存在本地文件中,好處是,以后再去獲取馬蜂窩首頁的時候,就不需要再走mafengwoLogin的流程了,因為已經從文件中拿到cookie了
mafengwoSession.cookies.save()
if __name__ == "__main__":
# 從返回結果來看,有登錄成功
# mafengwoLogin("13756567832", "000000001")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
cookie保存結果如下:
# 文件:mafengwoCookies.txt
#LWP-Cookies-2.0
Set-Cookie3: __today_login=1; path="/"; domain=".mafengwo.cn"; path_spec; domain_dot; expires="2018-03-16 15:56:15Z"; httponly=None; version=0
Set-Cookie3: mafengwo="0a60e1a04f6a6f5555f0e285602b5b17_94281374_5aab641fb23d42.37804626_5aab641fb23dc3.28763728"; path="/"; domain=".mafengwo.cn"; path_spec; domain_dot; expires="2018-06-13 06:25:03Z"; httponly=None; version=0
Set-Cookie3: mfw_uuid="5aab641f-b789-96ef-736d-48640285f4c0"; path="/"; domain=".mafengwo.cn"; path_spec; domain_dot; expires="2019-03-16 06:25:03Z"; version=0
Set-Cookie3: oad_n="a%3A3%3A%7Bs%3A3%3A%22oid%22%3Bi%3A1029%3Bs%3A2%3A%22dm%22%3Bs%3A20%3A%22passport.mafengwo.cn%22%3Bs%3A2%3A%22ft%22%3Bs%00009%3A%222018-03-16+14%3A28%3A47%22%3B%7D"; path="/"; domain=".mafengwo.cn"; path_spec; domain_dot; expires="2018-03-23 06:25:03Z"; version=0
Set-Cookie3: uol_throttle=94281374; path="/"; domain=".mafengwo.cn"; path_spec; domain_dot; expires="2018-03-16 06:35:03Z"; version=0
1
2
3
4
5
6
7
8
9
3.3.2. 使用cookie登錄
為了測試訪問頁面時,是否處於登錄狀態。有一個比較巧妙的方法:就是直接訪問一個需要登錄后,才可見的地址。比如說涉及到用戶信息的頁面。下面以 “我的路線” 頁面為例:http://www.mafengwo.cn/plan/route.php
這是登錄狀態后見到的頁面:
如果是 非登錄狀態,會自動跳轉(重定向302)到 用戶登錄頁面:
所以,我們可以用這個頁面判斷cookie登錄是否成功,代碼如下:
# -*- coding: utf-8 -*-
import requests
# python2 和 python3的兼容代碼
try:
# python2 中
import cookielib
print(f"user cookielib in python2.")
except:
# python3 中
import http.cookiejar as cookielib
print(f"user cookielib in python3.")
# session代表某一次連接
mafengwoSession = requests.session()
# 因為原始的session.cookies 沒有save()方法,所以需要用到cookielib中的方法LWPCookieJar,這個類實例化的cookie對象,就可以直接調用save方法。
mafengwoSession.cookies = cookielib.LWPCookieJar(filename = "mafengwoCookies.txt")
userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
header = {
# "origin": "https://passport.mafengwo.cn",
"Referer": "https://passport.mafengwo.cn/",
'User-Agent': userAgent,
}
def isLoginStatus():
# 通過訪問個人中心頁面的返回狀態碼來判斷是否為登錄狀態
routeUrl = "http://www.mafengwo.cn/plan/route.php"
# 下面有兩個關鍵點
# 第一個是header,如果不設置,會返回500的錯誤
# 第二個是allow_redirects,如果不設置,session訪問時,服務器返回302,
# 然后session會自動重定向到登錄頁面,獲取到登錄頁面之后,變成200的狀態碼
# allow_redirects = False 就是不允許重定向
responseRes = mafengwoSession.get(routeUrl, headers = header, allow_redirects = False)
print(f"isLoginStatus = {responseRes.status_code}")
if responseRes.status_code != 200:
return False
else:
return True
if __name__ == "__main__":
mafengwoSession.cookies.load()
isLogin = isLoginStatus()
print(f"is login mafengwo = {isLogin}")
'''
# 按照之前保存過的mafengwoCookies.txt登錄,屬於登錄狀態:
user cookielib in python3.
isLoginStatus = 200
is login mafengwo = True
'''
'''
# 如果把mafengwoCookies.txt中的信息修改掉之后,就無法登錄了,屬於非登錄狀態了
user cookielib in python3.
isLoginStatus = 302
is login mafengwo = False
'''
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
3.4. 最終形成的登錄模式
因為cookie是有有效期的,所以沒法做到一次登錄,終生有效。所以,一般的登錄模式,就是:
第一步:先嘗試cookie登錄
第二步:如果cookie無法登錄成功,就使用用戶名密碼登錄,將新的cookie保存下來。
# -*- coding: utf-8 -*-
import requests
# python2 和 python3的兼容代碼
try:
# python2 中
import cookielib
print(f"user cookielib in python2.")
except:
# python3 中
import http.cookiejar as cookielib
print(f"user cookielib in python3.")
# session代表某一次連接
mafengwoSession = requests.session()
# 因為原始的session.cookies 沒有save()方法,所以需要用到cookielib中的方法LWPCookieJar,這個類實例化的cookie對象,就可以直接調用save方法。
mafengwoSession.cookies = cookielib.LWPCookieJar(filename = "mafengwoCookies.txt")
userAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
header = {
# "origin": "https://passport.mafengwo.cn",
"Referer": "https://passport.mafengwo.cn/",
'User-Agent': userAgent,
}
# 馬蜂窩模仿 登錄
def mafengwoLogin(account, password):
print("開始模擬登錄馬蜂窩")
postUrl = "https://passport.mafengwo.cn/login/"
postData = {
"passport": account,
"password": password,
}
# 使用session直接post請求
responseRes = mafengwoSession.post(postUrl, data = postData, headers = header)
# 無論是否登錄成功,狀態碼一般都是 statusCode = 200
print(f"statusCode = {responseRes.status_code}")
print(f"text = {responseRes.text}")
# 登錄成功之后,將cookie保存在本地文件中,好處是,以后再去獲取馬蜂窩首頁的時候,就不需要再走mafengwoLogin的流程了,因為已經從文件中拿到cookie了
mafengwoSession.cookies.save()
# 通過訪問個人中心頁面的返回狀態碼來判斷是否為登錄狀態
def isLoginStatus():
routeUrl = "http://www.mafengwo.cn/plan/route.php"
# 下面有兩個關鍵點
# 第一個是header,如果不設置,會返回500的錯誤
# 第二個是allow_redirects,如果不設置,session訪問時,服務器返回302,
# 然后session會自動重定向到登錄頁面,獲取到登錄頁面之后,變成200的狀態碼
# allow_redirects = False 就是不允許重定向
responseRes = mafengwoSession.get(routeUrl, headers = header, allow_redirects = False)
print(f"isLoginStatus = {responseRes.status_code}")
if responseRes.status_code != 200:
return False
else:
return True
if __name__ == "__main__":
# 第一步:嘗試使用已有的cookie登錄
mafengwoSession.cookies.load()
isLogin = isLoginStatus()
print(f"is login mafengwo = {isLogin}")
if isLogin == False:
# 第二步:如果cookie已經失效了,那就嘗試用帳號登錄
print(f"cookie失效,用戶重新登錄...")
mafengwoLogin("13756567832", "000000001")
resp = mafengwoSession.get("http://www.mafengwo.cn/plan/fav_type.php", headers = header, allow_redirects = False)
print(f"resp.status = {resp.status_code}")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 第一次運行程序的輸出:
# 由於第一次還沒有生成cookie,所以需要用賬戶登錄一次
user cookielib in python3.
isLoginStatus = 302
is login mafengwo = False
cookie失效,用戶重新登錄...
開始模擬登錄馬蜂窩
statusCode = 200
……………………
resp.status = 200
1
2
3
4
5
6
7
8
9
10
11
# 第二次運行程序的輸出:
# 第二次,就直接使用cookie登錄了,不再需要使用帳號登錄
user cookielib in python3.
isLoginStatus = 200
is login mafengwo = True
resp.status = 200
1
2
3
4
5
6
7
點贊 50
————————————————
版權聲明:本文為CSDN博主「Kosmoo」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zwq912318834/article/details/79571110