Python爬蟲之模擬知乎登入

劉志軍發表於2017-03-30

經常寫爬蟲的都知道,有些頁面在登入之前是被禁止抓取的,比如知乎的話題頁面就要求使用者登入才能訪問,而 “登入” 離不開 HTTP 中的 Cookie 技術。

登入原理

Cookie 的原理非常簡單,因為 HTTP 是一種無狀態的協議,因此為了在無狀態的 HTTP 協議之上維護會話(session)狀態,讓伺服器知道當前是和哪個客戶在打交道,Cookie 技術出現了 ,Cookie 相當於是服務端分配給客戶端的一個標識。

Python爬蟲之模擬知乎登入
cookie

  1. 瀏覽器第一次發起 HTTP 請求時,沒有攜帶任何 Cookie 資訊
  2. 伺服器把 HTTP 響應,同時還有一個 Cookie 資訊,一起返回給瀏覽器
  3. 瀏覽器第二次請求就把伺服器返回的 Cookie 資訊一起傳送給伺服器
  4. 伺服器收到HTTP請求,發現請求頭中有Cookie欄位, 便知道之前就和這個使用者打過交道了。

實戰應用

用過知乎的都知道,只要提供使用者名稱和密碼以及驗證碼之後即可登入。當然,這只是我們眼中看到的現象。而背後隱藏的技術細節就需要藉助瀏覽器來挖掘了。現在我們就用 Chrome 來檢視當我們填完表單後,究竟發生了什麼?

Python爬蟲之模擬知乎登入

(如果已經登入的,先退出)首先進入知乎的登入頁面 www.zhihu.com/#signin ,開啟 Chrome 的開發者工具條(按 F12)先嚐試輸入一個錯誤的驗證碼觀察瀏覽器是如何傳送請求的。

Python爬蟲之模擬知乎登入

從瀏覽器的請求可以發現幾個關鍵的資訊

  1. 登入的 URL 地址是 www.zhihu.com/login/email
  2. 登入需要提供的表單資料有4個:使用者名稱(email)、密碼(password)、驗證碼(captcha)、_xsrf。
  3. 獲取驗證碼的URL地址是 www.zhihu.com/captcha.gif…

_xsrf 是什麼?如果你對CSRF(跨站請求偽造)攻擊非常熟悉的話,那麼你一定知道它的作用,xsrf是一串偽隨機數,它是用於防止跨站請求偽造的。它一般存在網頁的 form 表單標籤中,為了證實這一點,可以在頁面上搜尋 “xsrf”,果然,_xsrf在一個隱藏的 input 標籤中

Python爬蟲之模擬知乎登入

摸清了瀏覽器登入時所需要的資料是如何獲取之後,那麼現在就可以開始寫程式碼用 Python 模擬瀏覽器來登入了。登入時所依賴的兩個第三方庫是 requests 和 BeautifulSoup,先安裝

pip install beautifulsoup4==4.5.3
pip install requests==2.13.0複製程式碼

http.cookiejar 模組可用於自動處理HTTP Cookie,LWPCookieJar 物件就是對 cookies 的封裝,它支援把 cookies 儲存到檔案以及從檔案中載入。

而 session 物件 提供了 Cookie 的持久化,連線池功能,可以通過 session 物件傳送請求

首先從cookies.txt 檔案中載入 cookie資訊,因為首次執行還沒有cookie,所有會出現 LoadError 異常。

from http import cookiejar
session = requests.session()
session.cookies = cookiejar.LWPCookieJar(filename='cookies.txt')
try:
    session.cookies.load(ignore_discard=True)
except LoadError:
    print("load cookies failed")複製程式碼

獲取 xsrf

前面已經找到了 xsrf 所在的標籤,,利用 BeatifulSoup 的 find 方法可以非常便捷的獲取該值

def get_xsrf():
    response = session.get("https://www.zhihu.com", headers=headers)
    soup = BeautifulSoup(response.content, "html.parser")
    xsrf = soup.find('input', attrs={"name": "_xsrf"}).get("value")
    return xsrf複製程式碼

獲取驗證碼

驗證碼是通過 /captcha.gif 介面返回的,這裡我們把驗證碼圖片下載儲存到當前目錄,由人工識別,當然你可以用第三方支援庫來自動識別,比如 pytesser。

def get_captcha():
    """
    把驗證碼圖片儲存到當前目錄,手動識別驗證碼
    :return:
    """
    t = str(int(time.time() * 1000))
    captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + "&type=login"
    r = session.get(captcha_url, headers=headers)
    with open('captcha.jpg', 'wb') as f:
        f.write(r.content)
    captcha = input("驗證碼:")
    return captcha複製程式碼

登入

一切引數準備就緒之後,就可以請求登入介面了。

def login(email, password):
    login_url = 'https://www.zhihu.com/login/email'
    data = {
        'email': email,
        'password': password,
        '_xsrf': get_xsrf(),
        "captcha": get_captcha(),
        'remember_me': 'true'}
    response = session.post(login_url, data=data, headers=headers)
    login_code = response.json()
    print(login_code['msg'])
    for i in session.cookies:
        print(i)
    session.cookies.save()複製程式碼

請求成功後,session 會自動把 服務端的返回的cookie 資訊填充到 session.cookies 物件中,下次請求時,客戶端就可以自動攜帶這些cookie去訪問那些需要登入的頁面了。

原始碼:github.com/lzjun567/cr…

參考資料:

相關文章