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

折騰了將近兩天,中間數次想要放棄,還好硬著頭皮搞下去了,在此分享出來,希望有同等需求的各位能少走一些彎路。
源碼放在了github上, 歡迎前往查看
若是幫你解決了問題,或者給了你啟發,不要吝嗇給加一星

工具準備

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

scrapy genspider zhihu

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

# -*- 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, 切記切記

# Disable cookies (enabled by default)
COOKIES_ENABLED = True

模擬登陸

過程如下:

  • 進入登錄頁,獲取 HeaderCookie 信息,
    完善的 Header 信息能盡量偽裝爬蟲, 有效 Cookie 信息能迷惑知乎服務端,使其認為當前登錄非首次登錄,若無有效 Cookie 會遭遇驗證碼。 在抓取數據之前,請在瀏覽器中登錄過知乎,這樣才使得 Cookie 是有效的。

HeaderCookie 整理如下:

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 的含義, 用于防范 跨站請求偽造

  • 整理以上,代碼如下:

    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 中。

代碼整理如下:

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中盡量的模擬在瀏覽器中的交互過程,使服務端無感抓包過程。 請求中附加有效的 CookiesHeaders 頭信息,可有效的迷惑服務端, 同時在交互的過程中,獲取后續請求必要信息和認證信息,使得整個流程能不斷先前。

若是你遇到什么問題,盡量提出來,歡迎一起來討論解決。
源碼放在了github上, 歡迎前往查看
若是幫你解決了問題,或者給了你啟發,不要吝嗇給加一星

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容