備註:python 2.7.9,32位
有些網站需要登錄後才能爬取所需要的信息,此時可以設計爬蟲進行模擬登錄,原理是利用瀏覽器cookie。
一、瀏覽器訪問服務器的過程:
(1)瀏覽器(客戶端)向Web服務器發出一個HTTP請求(Http request);
(2)Web服務器收到請求,發回響應信息(Http Response);
(3)瀏覽器解析內容呈現給用戶。
二、利用Fiddler查看瀏覽器行爲信息:
Http請求消息:
Http響應消息:(1)起始行:包括請求方法、請求的資源、HTTP協議的版本號
這裏GET請求沒有消息主體,因此消息頭後的空白行中沒有其他數據。
(2)消息頭:包含各種屬性
(3)消息頭結束後的空白行
(4)可選的消息體:包含數據
(1)起始行:包括HTTP協議版本,http狀態碼和狀態
(2)消息頭:包含各種屬性(3)消息體:包含數據
從上面可見,cookie在Http請求和Http響應的頭消息中是很重要的屬性。
三、什麼是cookie:
當用戶通過瀏覽器首次訪問一個域名時,訪問的Web服務器會給客戶端發送數據,以保持Web服務器與客戶端之間的狀態,這些數據就是Cookie。
它是站點創建的,爲了辨別用戶身份而儲存在用戶本地終端上的數據,其中的信息一般都是經過加密的,存在緩存或硬盤中,在硬盤中是一些小文本文件。
當訪問該網站時,就會讀取對應網站的Cookie信息。
作用:記錄不同用戶的訪問狀態。
四、操作過程:
在知乎登錄界面輸入用戶名和密碼,然後登錄。
利用Fiddler來查看這期間瀏覽器和知乎服務器之間的信息交互。
(1)瀏覽器給服務器發送了一個POST,攜帶帳號和密碼等信息;
從起始行可見,POST是發送給http://www.zhihu.com/login/email這個網址,內容在最下面消息體裏,
也可以在Fiddler的Webforms標籤下查看POST的內容,如下:
可以發現,信息裏不僅有帳號(email)和密碼(password),其實還有_xsrf(具體作用往後看)和remember_me(登錄界面的“記住我”)兩個值。
那麼,在python爬蟲中將這些信息同樣發送,就可以模擬登錄。
在發送的信息裏出現了一個項:_xsrf,值爲2fc4ab0f0f144c2e478c436fe3160443
這個項其實是在訪問知乎登錄網頁https://www.zhihu.com/#signin時,網頁發送過來的信息,在瀏覽器源碼中可見:
所以需要先從登錄網址https://www.zhihu.com/#signin獲取這個_xsrf的值,
並連同帳號、密碼等信息再POST到真正接收請求的http://www.zhihu.com/login/email網址。
(2)獲取_xsrf的值:
爬取登錄網址https://www.zhihu.com/#signin,從內容中獲取_xsrf的值。
正則表達式。
(3)發送請求:
xsrf = 獲取的_xsrf的值
data = {"email":"xxx","password":"xxx","_xsrf":xsrf}
login = s.post(loginURL, data = data, headers = headers)
loginURL:是真正POST到的網址,不一定等同於登錄頁面的網址;
(4)爬取登錄後的網頁:
response = s.get(getURL, cookies = login.cookies, headers = headers)
getURL:要爬取的登陸後的網頁;
login.cookies:登陸時獲取的cookie信息,存儲在login中。
(5)輸出內容:
print response.content
五、具體代碼:
# -*- coding:utf-8 -*-
# author:Simon
# updatetime:2016年3月17日 17:35:35
# 功能:爬蟲之模擬登錄,urllib和requests都用了...
import urllib
import urllib2
import requests
import re
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11'}
def get_xsrf():
firstURL = "http://www.zhihu.com/#signin"
request = urllib2.Request(firstURL,headers = headers)
response = urllib2.urlopen(request)
content = response.read()
pattern = re.compile(r'name="_xsrf" value="(.*?)"/>',re.S)
_xsrf = re.findall(pattern,content)
return _xsrf[0]
def login(par1):
s = requests.session()
afterURL = "https://www.zhihu.com/explore" # 想要爬取的登錄後的頁面
loginURL = "http://www.zhihu.com/login/email" # POST發送到的網址
login = s.post(loginURL, data = par1, headers = headers) # 發送登錄信息,返回響應信息(包含cookie)
response = s.get(afterURL, cookies = login.cookies, headers = headers) # 獲得登陸後的響應信息,使用之前的cookie
return response.content
xsrf = get_xsrf()
print "_xsrf的值是:" + xsrf
data = {"email":"xxx","password":"xxx","_xsrf":xsrf}
print login(data)
六、補充:
用知乎網做完試驗,發現這裏好像並不需要發送_xsrf這個值。
不過有的網站在登陸時確實需要發送類似這樣的一個值,可以用上述方法。