cookie 免密登錄了解一下

  • 2019 年 12 月 4 日
  • 筆記

我們都知道 HTTP 是無狀態的,用戶每次打開 web 頁面時,服務器都打開新的會話,而且服務器也不會自動維護客戶的上下文信息,那麼服務器是怎麼識別用戶的呢?

這就是本文今天要講解的內容。當服務端需要記錄用戶的狀態時,就需要用某種機制來識具體的用戶,這個機制就是 session 和 cookie。

session 是保存在服務器端的,用於標識用戶,並且跟蹤用戶的一種上下文保持機制。當服務器創建了一個 Session 時,給客戶端發送的響應報文包含了 Set-Cookie 字段,其中有一個名為 sid 的鍵值對,這個鍵值對就是 Session ID。客戶端收到後就把 Cookie 保存在瀏覽器中,並且之後發送的請求報文都包含 Session ID

Cookie 由服務器生成,發送給瀏覽器,瀏覽器把 Cookie 以 kv 形式保存到某個目錄下的文本文件內。是客戶端保存用戶信息的一種機制,用來記錄用戶的一些信息,它是實現 Session 的一種方式。

瀏覽器會根據響應報文里的一個叫做 Set-Cookie 的首部字段信息,將其保存在本地。

當下一次請求時會把該 Cookie 發送給服務器,之後服務端發現客戶端發送過來的 Cookie 後,會檢查是那個客戶端發送過來的請求,然後根據服務器上的記錄,最後得到了之前的狀態信息。

我們經常看到登錄的時候,有個下次自動登錄的選項,就是根據這個原理來實現的。既然瀏覽器能實現免密登錄的功能,那麼我們用代碼如何來實現呢?

這裡有兩個登錄案例,看完之後你就知道如何實現了。

案例一:豆瓣登錄

在這裡我們使用 Python 中的 LWPCookieJar ,它是管理 cookie 的工具,可以將 cookie 保存到文件,在文件中讀取本地 cookie 數據到程序中,一般用到以下兩種方法:

源碼

1. 將登錄成功的 cookie 寫入到本地文件

# 實例化一個 LWPCookieJar 對象,並設置保存 cookie 的文件  session = requests.session()  session.cookies = LWPCookieJar(filename='DouBanCookies.txt')  

在使用代碼登錄成功之後,使用 session.save() 將自動將 cookie 寫入到設置的 cookie 文件中

def login():      name = input("輸入賬戶:")      password = input("輸入密碼:")      url = "https://accounts.douban.com/j/mobile/login/basic"      data = {          "ck": "",          "name": name,          "password": password,          "remember": "True",          "ticket": "",      }      response = session.post(url, data=data)      print(response.text)      session.cookies.save()  # 保存 cookie  

寫入之後,會在當前目錄生成 DouBanCookies.txt 的文件,如下圖所示:

2. 直接使用該文件中的 cookie 實現免密登錄

直接使用 load 方法,從文件中獲取 cookie 到代碼中。其中 load 方法有兩個可選值,ignore_discard 主要是忽略關閉瀏覽器丟失, ignore_expires 是忽略 cookie 失效。可根據自己的實際場景自由選擇。

session.cookies.load(ignore_discard=True)  

使用 cookie 登錄之後,可以自主驗證一下是否登錄成功。一般選擇訪問個人主頁,查看響應內容,判讀是否登錄成功。完整代碼如下:

# coding: utf-8  import requests  from scrapy import Selector  from http.cookiejar import LWPCookieJar    session = requests.session()  headers = {          "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"      }  session.headers = headers  session.cookies = LWPCookieJar(filename='DouBanCookies.txt')  # 實例化一個LWPCookieJar對象    def login():      name = input("輸入賬戶:")      password = input("輸入密碼:")      url = "https://accounts.douban.com/j/mobile/login/basic"      data = {          "ck": "",          "name": name,          "password": password,          "remember": "True",          "ticket": "",      }      response = session.post(url, data=data)      print(response.text)      session.cookies.save()      verify_login()    def verify_login():      mine_url = "https://www.douban.com/mine/"      mine_response = session.get(mine_url)      selector = Selector(text=mine_response.text)      user_name = selector.css(".info h1 ::text").extract_first("")      print(f"豆瓣用戶名:{user_name.strip()}")    def cookie_login():      try:          # 從文件中加載cookies(LWP格式)          session.cookies.load(ignore_discard=True)          print(session.cookies)      except Exception:          print("Cookies未能加載,使用密碼登錄")          login()        else:          verify_login()    if __name__ == "__main__":      cookie_login()  

案例二:新榜登錄

除了使用 Python 中自帶的 cookie 管理工具之外,我們還可以自己創建 cookie 文件,寫入到本地文件或者 Redis 中。

例如,新榜的登錄,通過我的測試發現,主要是校驗 token 和用戶名這兩個參數。而 token 在登錄成功後,可以在響應內容中找到。那麼我們就可以自己創建 cookie 文件,一般是 .txt 或者.json 文件。

 cookies = {          "name": self.account,          "token": token,          "useLoginAccount": "true"          }with open("XinBangCookies.txt", 'w')as f:  # 將cookies保存到本地      f.write(str(cookies))  

然後讀取 cookie 加載到代碼中

with open("XinBangCookies.txt", "r")as f:      cookies = f.read()  cookies = eval(cookies)  cookie = "; ".join((key + "=" + value) for key, value in cookies.items())  self.session.headers.update({"Cookie": cookie})  

使用本地 cookie 登錄後,可以選擇訪問登錄之後才能訪問的地址進行驗證,具體代碼就不貼了,邏輯和上面的案例差不多,只是處理方法不一樣。

總結

本文主要是介紹 session 和 cookie 的一些基本概念,以及兩者之間的區別。同時給大夥介紹了兩種用代碼處理 cookie 的案例,這裡要注意一下 cookie 存在時效性,如果失效了需要重新用密碼登錄。感興趣的朋友可以根據以上兩個案例去練練手噢。