scrapy模擬登錄知乎--抓取熱點話題

工具準備

在開始以前,請確保 scrpay 正確安裝,手頭有一款簡潔而強大的瀏覽器, 如果你有使用 postman 那就更好了。css

scrapy genspider zhihu

使用以上命令生成知乎爬蟲,代碼以下:html

# -*- coding: utf-8 -*- import scrapy class ZhihuSpider(scrapy.Spider): name = 'zhihu' allowed_domains = ['www.zhihu.com'] start_urls = ['http://www.zhihu.com/'] def parse(self, response): pass

有一點切記,不要忘了啓用 Cookies切記切記 :python

# Disable cookies (enabled by default) COOKIES_ENABLED = True

模擬登錄

過程以下:shell

  • 進入登陸頁,獲取 Header 和 Cookie 信息,
    完善的 Header 信息能儘可能假裝爬蟲, 有效 Cookie 信息能迷惑知乎服務端,使其認爲當前登陸非首次登陸,若無有效 Cookie 會遭遇驗證碼。 在抓取數據以前,請在瀏覽器中登陸過知乎,這樣才使得 Cookie 是有效的。
  • 歡迎加入個人QQ羣`923414804`與我一塊兒學習,羣裏有我學習過程當中整理的大量學習資料。加羣便可免費獲取

Header 和 Cookie 整理以下:json

headers = {
    'Host': 'www.zhihu.com', 'Connection': 'keep-alive', 'Origin': 'https://www.zhihu.com', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'Accept': '*/*', 'X-Requested-With': 'XMLHttpRequest', 'DNT': 1, 'Referer': 'https://www.zhihu.com/', 'Accept-Encoding': 'gzip, deflate, br', 'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6', } cookies = { 'd_c0': '"AHCAtu1iqAmPTped76X1ZdN0X_qAwhjdLUU=|1458699045"', '__utma': '51854390.1407411155.1458699046.1458699046.1458699046.1', '__utmv': '51854390.000--|3=entry_date=20160322=1', '_zap': '850897bb-cba4-4d0b-8653-fd65e7578ac2', 'q_c1': 'b7918ff9a5514d2981c30050c8c732e1|1502937247000|1491446589000', 'aliyungf_tc': 'AQAAAHVgviiNyQsAOhSntJ5J/coWYtad', '_xsrf': 'b12fdca8-cb35-407a-bc4c-6b05feff37cb', 'l_cap_id': '"MDk0MzRjYjM4NjAwNDU0MzhlYWNlODQ3MGQzZWM0YWU=|1503382513|9af99534aa22d5db92c7f58b45f3f3c772675fed"', 'r_cap_id': '"M2RlNDZjN2RkNTBmNGFmNDk2ZjY4NjIzY2FmNTE4NDg=|1503382513|13370a99ee367273b71d877de17f05b2986ce0ef"', 'cap_id': '"NmZjODUxZjQ0NzgxNGEzNmJiOTJhOTlkMTVjNWIxMDQ=|1503382513|dba2e9c6af7f950547474f827ef440d7a2950163"', }
  • 在瀏覽器中,模擬登錄,抓取登錄請求信息。 

從圖中能夠看到 _xsrf 參數, 這個參數與登錄驗證信息無關,但很明顯是由登錄頁面攜帶的信息。 Google了下 xsrf 的含義, 用於防範 跨站請求僞造 。 api

 


  • 整理以上,代碼以下:瀏覽器

    loginUrl = 'https://www.zhihu.com/#signin' siginUrl = 'https://www.zhihu.com/login/email' def start_requests(self): return [ scrapy.http.FormRequest( self.loginUrl, headers=self.headers, cookies=self.cookies, meta={'cookiejar': 1}, callback=self.post_login) ] def post_login(self, response): xsrf = response.css( 'div.view-signin > form > input[name=_xsrf]::attr(value)' ).extract_first() self.headers['X-Xsrftoken'] = xsrf return [ scrapy.http.FormRequest( self.siginUrl, method='POST', headers=self.headers, meta={'cookiejar': response.meta['cookiejar']}, formdata={ '_xsrf': xsrf, 'captcha_type': 'cn', 'email': 'xxxxxx@163.com', 'password': 'xxxxxx', }, callback=self.after_login) ]

設置Bearer Token

通過上述步驟登錄成功了,有點小激動,有沒有! 但苦難到此還遠沒有結束,這個時候嘗試抓取最近熱門話題,直接返回 code:401 ,未受權的訪問。 受權信息未設置,致使了此類錯誤,莫非遺漏了什麼,看來只能在瀏覽器中追蹤請求參數來偵測問題。 在瀏覽器的請求中,包含了Bearer Token, 而我在scrapy中模擬的請求中未包含此信息, 因此我被服務器認定爲未受權的。 經過觀察發現 Bearer Token 的關鍵部分,就是 Cookies 中的 z_c0 包含的信息。服務器

 


z_c0 包含的信息,是在登錄完成時種下的,因此從登錄完成返回的登錄信息裏,獲取要設置的 Cookie 信息, 而後拼接出 Bearer Token,最後設置到 Header 中。
cookie

代碼整理以下:app

def after_login(self, response): jdict = json.loads(response.body) print('after_login', jdict) if jdict['r'] == 0: z_c0 = response.headers.getlist('Set-Cookie')[2].split(';')[0].split( '=')[1] self.headers['authorization'] = 'Bearer ' + z_c0 return scrapy.http.FormRequest( url=self.feedUrl, method='GET', meta={'cookiejar': response.meta['cookiejar']}, headers=self.headers, formdata={ 'action_feed': 'True', 'limit': '10', 'action': 'down', 'after_id': str(self.curFeedId), 'desktop': 'true' }, callback=self.parse) else: print(jdict['error'])

獲取數據

上述步驟後,數據獲取就水到渠成了,爲了檢測成功與否, 把返回信息寫到文件中,並且只獲取前五十個,代碼以下:

feedUrl = 'https://www.zhihu.com/api/v3/feed/topstory' nextFeedUrl = '' curFeedId = 0 def parse(self, response): with open('zhihu.json', 'a') as fd: fd.write(response.body) jdict = json.loads(response.body) jdatas = jdict['data'] for entry in jdatas: entry['pid'] = entry['id'] yield entry jpaging = jdict['paging'] self.curFeedId += len(jdatas) if jpaging['is_end'] == False and self.curFeedId < 50: self.nextFeedUrl = jpaging['next'] yield self.next_request(response) def next_request(self, response): return scrapy.http.FormRequest( url=self.nextFeedUrl, method='GET', meta={'cookiejar': response.meta['cookiejar']}, headers=self.headers, callback=self.parse)

最終獲取的數據以下圖所示:

 

寫在最後

知乎的數據,只有登陸完成以後,纔可有效的獲取,因此模擬登錄是沒法忽略無論的。 所謂的模擬登錄,只是在scrapy中儘可能的模擬在瀏覽器中的交互過程,使服務端無感抓包過程。 請求中附加有效的 Cookies 和 Headers 頭信息,可有效的迷惑服務端, 同時在交互的過程當中,獲取後續請求必要信息和認證信息,使得整個流程能不斷先前。

相關文章
相關標籤/搜索