常常寫爬蟲的都知道,有些頁面在登陸以前是被禁止抓取的,好比知乎的話題頁面就要求用戶登陸才能訪問,而 「登陸」 離不開 HTTP 中的 Cookie 技術。html
Cookie 的原理很是簡單,由於 HTTP 是一種無狀態的協議,所以爲了在無狀態的 HTTP 協議之上維護會話(session)狀態,讓服務器知道當前是和哪一個客戶在打交道,Cookie 技術出現了 ,Cookie 至關因而服務端分配給客戶端的一個標識。python
用過知乎的都知道,只要提供用戶名和密碼以及驗證碼以後便可登陸。固然,這只是咱們眼中看到的現象。而背後隱藏的技術細節就須要藉助瀏覽器來挖掘了。如今咱們就用 Chrome 來查看當咱們填完表單後,究竟發生了什麼?git
(若是已經登陸的,先退出)首先進入知乎的登陸頁面 www.zhihu.com/#signin ,打開 Chrome 的開發者工具條(按 F12)先嚐試輸入一個錯誤的驗證碼觀察瀏覽器是如何發送請求的。github
從瀏覽器的請求能夠發現幾個關鍵的信息json
_xsrf 是什麼?若是你對CSRF(跨站請求僞造)攻擊很是熟悉的話,那麼你必定知道它的做用,xsrf是一串僞隨機數,它是用於防止跨站請求僞造的。它通常存在網頁的 form 表單標籤中,爲了證明這一點,能夠在頁面上搜索 「xsrf」,果真,_xsrf在一個隱藏的 input 標籤中瀏覽器
摸清了瀏覽器登陸時所須要的數據是如何獲取以後,那麼如今就能夠開始寫代碼用 Python 模擬瀏覽器來登陸了。登陸時所依賴的兩個第三方庫是 requests 和 BeautifulSoup,先安裝服務器
pip install beautifulsoup4==4.5.3
pip install requests==2.13.0複製代碼
http.cookiejar 模塊可用於自動處理HTTP Cookie,LWPCookieJar 對象就是對 cookies 的封裝,它支持把 cookies 保存到文件以及從文件中加載。cookie
而 session 對象 提供了 Cookie 的持久化,鏈接池功能,能夠經過 session 對象發送請求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 所在的標籤,,利用 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去訪問那些須要登陸的頁面了。
參考資料: