scrapy模擬登陸知乎--抓取熱點(diǎn)話題

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

工具準(zhǔn)備

在開始之前,請確保 scrpay 正確安裝住练,手頭有一款簡潔而強(qiáng)大的瀏覽器地啰, 若是你有使用 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

有一點(diǎn)切記讲逛,不要忘了啟用 Cookies, 切記切記

# Disable cookies (enabled by default)
COOKIES_ENABLED = True

模擬登陸

過程如下:

  • 進(jìn)入登錄頁亏吝,獲取 HeaderCookie 信息,
    完善的 Header 信息能盡量偽裝爬蟲盏混, 有效 Cookie 信息能迷惑知乎服務(wù)端蔚鸥,使其認(rèn)為當(dāng)前登錄非首次登錄,若無有效 Cookie 會遭遇驗證碼许赃。 在抓取數(shù)據(jù)之前止喷,請在瀏覽器中登錄過知乎,這樣才使得 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 參數(shù), 這個參數(shù)與登陸驗證信息無關(guān)预愤,但很明顯是由登陸頁面攜帶的信息。 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)
        ]
    

設(shè)置Bearer Token

經(jīng)過上述步驟登陸成功了展懈,有點(diǎn)小激動销睁,有沒有! 但苦難到此還遠(yuǎn)沒有結(jié)束存崖,這個時候嘗試抓取最近熱門話題冻记,直接返回 code:401 ,未授權(quán)的訪問。 授權(quán)信息未設(shè)置来惧,導(dǎo)致了此類錯誤冗栗,莫非遺漏了什么,看來只能在瀏覽器中追蹤請求參數(shù)來偵測問題违寞。 在瀏覽器的請求中,包含了Bearer Token, 而我在scrapy中模擬的請求中未包含此信息偶房, 所以我被服務(wù)器認(rèn)定為未授權(quán)的趁曼。 通過觀察發(fā)現(xiàn) Bearer Token 的關(guān)鍵部分,就是 Cookies 中的 z_c0 包含的信息棕洋。


z_c0 包含的信息挡闰,是在登陸完成時種下的,所以從登陸完成返回的登陸信息里,獲取要設(shè)置的 Cookie 信息摄悯, 然后拼接出 Bearer Token,最后設(shè)置到 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'])

獲取數(shù)據(jù)

上述步驟后,數(shù)據(jù)獲取就水到渠成了奢驯,為了檢測成功與否申钩, 把返回信息寫到文件中,而且只獲取前五十個,代碼如下:

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)

最終獲取的數(shù)據(jù)如下圖所示:

寫在最后

知乎的數(shù)據(jù),只有登錄完成之后瘪阁,才可有效的獲取撒遣,所以模擬登陸是無法忽略不管的。 所謂的模擬登陸管跺,只是在scrapy中盡量的模擬在瀏覽器中的交互過程义黎,使服務(wù)端無感抓包過程。 請求中附加有效的 CookiesHeaders 頭信息豁跑,可有效的迷惑服務(wù)端廉涕, 同時在交互的過程中,獲取后續(xù)請求必要信息和認(rèn)證信息艇拍,使得整個流程能不斷先前狐蜕。

若是你遇到什么問題,盡量提出來淑倾,歡迎一起來討論解決馏鹤。
源碼放在了github上, 歡迎前往查看娇哆。
若是幫你解決了問題湃累,或者給了你啟發(fā),不要吝嗇給加一星碍讨。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末治力,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子勃黍,更是在濱河造成了極大的恐慌宵统,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件覆获,死亡現(xiàn)場離奇詭異马澈,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)弄息,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進(jìn)店門痊班,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摹量,你說我怎么就攤上這事涤伐÷ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵凝果,是天一觀的道長祝迂。 經(jīng)常有香客問我,道長器净,這世上最難降的妖魔是什么型雳? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮掌动,結(jié)果婚禮上四啰,老公的妹妹穿的比我還像新娘。我一直安慰自己粗恢,他們只是感情好柑晒,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著眷射,像睡著了一般匙赞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上妖碉,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天涌庭,我揣著相機(jī)與錄音,去河邊找鬼欧宜。 笑死坐榆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的冗茸。 我是一名探鬼主播席镀,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼夏漱!你這毒婦竟也來了豪诲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤挂绰,失蹤者是張志新(化名)和其女友劉穎屎篱,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體葵蒂,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡交播,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了践付。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秦士。...
    茶點(diǎn)故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖荔仁,靈堂內(nèi)的尸體忽然破棺而出伍宦,到底是詐尸還是另有隱情,我是刑警寧澤乏梁,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布次洼,位于F島的核電站,受9級特大地震影響遇骑,放射性物質(zhì)發(fā)生泄漏卖毁。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一落萎、第九天 我趴在偏房一處隱蔽的房頂上張望亥啦。 院中可真熱鬧,春花似錦练链、人聲如沸翔脱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽届吁。三九已至,卻和暖如春绿鸣,著一層夾襖步出監(jiān)牢的瞬間疚沐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工潮模, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亮蛔,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓擎厢,卻偏偏與公主長得像究流,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子锉矢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容