python3下使用requests實現模擬用戶登錄 —— 基礎篇(馬蜂窩)

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被黑客截取,那就一直可以用,盜用數據。
  • 第二步,當用戶登錄時,服務器會給本地瀏覽器返回一些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. 模擬登錄馬蜂窩網站

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

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")
  • 一般來說,調試期,判斷是否登錄成功的最簡單的方法:就是直接打印登錄之後的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")
  • 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

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
    '''

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}")
# 第一次運行程序的輸出:
# 由於第一次還沒有生成cookie,所以需要用賬戶登錄一次

user cookielib in python3.
isLoginStatus = 302
is login mafengwo = False
cookie失效,用戶重新登錄...
開始模擬登錄馬蜂窩
statusCode = 200
……………………
resp.status = 200
# 第二次運行程序的輸出:
# 第二次,就直接使用cookie登錄了,不再需要使用帳號登錄

user cookielib in python3.
isLoginStatus = 200
is login mafengwo = True
resp.status = 200
發佈了73 篇原創文章 · 獲贊 244 · 訪問量 69萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章