cookie 免密登錄了解一下
- 2019 年 12 月 4 日
- 筆記
我們都知道 HTTP 是無狀態的,用戶每次打開 web 頁面時,服務器都打開新的會話,而且服務器也不會自動維護客戶的上下文信息,那麼服務器是怎麼識別用戶的呢?

這就是本文今天要講解的內容。當服務端需要記錄用戶的狀態時,就需要用某種機制來識具體的用戶,這個機制就是 session 和 cookie。
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 存在時效性,如果失效了需要重新用密碼登錄。感興趣的朋友可以根據以上兩個案例去練練手噢。