1. 程式人生 > >轉載-Python爬蟲之模擬登入總結

轉載-Python爬蟲之模擬登入總結

備註:python 2.7.9,32位

有些網站需要登入後才能爬取所需要的資訊,此時可以設計爬蟲進行模擬登入,原理是利用瀏覽器cookie。

一、瀏覽器訪問伺服器的過程
    (1)瀏覽器(客戶端)向Web伺服器發出一個HTTP請求(Http request);
    (2)Web伺服器收到請求,發回響應資訊(Http Response);
    (3)瀏覽器解析內容呈現給使用者。

二、利用Fiddler檢視瀏覽器行為資訊:

Http請求訊息

(1)起始行:包括請求方法、請求的資源、HTTP協議的版本號

    這裡GET請求沒有訊息主體,因此訊息頭後的空白行中沒有其他資料。

    

(2)訊息頭:包含各種屬性

(3)訊息頭結束後的空白行

(4)可選的訊息體:包含資料

Http響應訊息

(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

五、具體程式碼

[python] view plain copy print?
  1. # -- coding:utf-8 --
  2. # author:Simon
  3. # updatetime:2016年3月17日 17:35:35
  4. # 功能:爬蟲之模擬登入,urllib和requests都用了…
  5. import urllib  
  6. import urllib2  
  7. import requests  
  8. import re  
  9. headers = {’User-Agent’:‘Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.12 Safari/535.11’}  
  10. def get_xsrf():  
  11.     request = urllib2.Request(firstURL,headers = headers)  
  12.     response = urllib2.urlopen(request)  
  13.     content = response.read()  
  14.     pattern = re.compile(r’name=”_xsrf” value=”(.?)”/>’,re.S)  
  15.     _xsrf = re.findall(pattern,content)  
  16.     return _xsrf[0]  
  17. def login(par1):  
  18.     s = requests.session()  
  19.     login = s.post(loginURL, data = par1, headers = headers)                  # 傳送登入資訊,返回響應資訊(包含cookie)
  20.     response = s.get(afterURL, cookies = login.cookies, headers = headers)    # 獲得登陸後的響應資訊,使用之前的cookie
  21.     return response.content  
  22. xsrf = get_xsrf()  
  23. print“_xsrf的值是:” + xsrf  
  24. data = {”email”:“xxx”,“password”:“xxx”,“_xsrf”:xsrf}  
  25. print login(data)  
# -- coding:utf-8 -*-

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這個值。

    不過有的網站在登陸時確實需要傳送類似這樣的一個值,可以用上述方法。