scrapy模擬登錄代碼演示及cookie原理說(shuō)明

登錄的需求

有些數(shù)據(jù),必須在登錄之后才能查看障陶,所以我們?cè)谂廊∵^(guò)程中就會(huì)產(chǎn)生模擬登錄的需求,它有兩個(gè)點(diǎn):
1桐款、未登錄的情況下無(wú)法查看數(shù)據(jù)咸这,或者直接彈出登錄框提示你先登錄
2、登錄后登錄狀態(tài)的保持(通衬д#可以理解為cookie的處理)

登錄的邏輯

  • 訪問(wèn)登錄頁(yè)面(部分網(wǎng)站會(huì)在登錄頁(yè)面設(shè)定token或標(biāo)識(shí)來(lái)反爬蟲(chóng)媳维,根據(jù)Network查看post數(shù)據(jù)來(lái)確認(rèn))
  • 構(gòu)造登錄所需數(shù)據(jù)酿雪,并攜帶偽造的數(shù)據(jù)發(fā)送登錄請(qǐng)求(如token或標(biāo)識(shí)、User-Agent/HOST/Referer等數(shù)據(jù)侄刽,向登錄地址POST數(shù)據(jù)指黎。)
  • 根據(jù)某個(gè)狀態(tài)碼或者登錄后跳轉(zhuǎn)url判斷是否登錄成功
  • 登錄成功后獲取start_urls,并且調(diào)用parse進(jìn)行數(shù)據(jù)爬取

模擬登錄注意的地方

登錄爬取有幾個(gè)特點(diǎn)州丹,比如瀏覽器不能換醋安,可能UserAgent也不能換、要用到cookie墓毒、頁(yè)面可能會(huì)有重定向吓揪,通常表現(xiàn)為登錄后跳轉(zhuǎn)、頁(yè)面需要發(fā)送token或其他標(biāo)識(shí)所计,所以正則是個(gè)關(guān)鍵柠辞。

  • 最好不要用自動(dòng)切換UserAgent的功能(未測(cè)試)
  • 必須在配置開(kāi)啟cookie,COOKIES_ENABLED = True
  • 關(guān)閉重定向禁止開(kāi)關(guān) #REDIRECT_ENABLED = False # 禁止重定向
  • robots協(xié)議也關(guān)掉 ROBOTSTXT_OBEY = False

代碼實(shí)現(xiàn)

這里以東盟貸為例子主胧,


示例網(wǎng)站

這是最簡(jiǎn)單的一種例子(登錄時(shí)沒(méi)有驗(yàn)證碼叭首、不用攜帶token、不用攜帶其他標(biāo)識(shí))踪栋,僅僅需要把用戶名和密碼發(fā)送過(guò)去即可焙格。

當(dāng)你需要爬取投資列表的數(shù)據(jù)時(shí),要到【我要投資】頁(yè)面去爬夷都,你想要打開(kāi)那個(gè)頁(yè)面他就會(huì)判斷你是否登錄眷唉,如果沒(méi)登錄就會(huì)給你直接跳轉(zhuǎn)到登錄界面

被強(qiáng)制跳轉(zhuǎn)到登錄頁(yè)面
審查元素,看input name

那我們面對(duì)這種情況损肛,就必須先登錄后請(qǐng)求頁(yè)面再爬取數(shù)據(jù)(我這里僅演示到登錄完成)厢破,示例代碼:

# -*- coding: utf-8 -*-
import scrapy


class DongmengSpider(scrapy.Spider):
    name = 'dongmeng'
    allowed_domains = ['www.dongmengdai.com']
    start_urls = ['https://www.dongmengdai.com/view/Investment_list_che.php?page=1']

    # 根據(jù)瀏覽器Network返回值來(lái)構(gòu)造header荣瑟,這是比較簡(jiǎn)單的header治拿,復(fù)雜的還會(huì)有很多信息
    header = {
        "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:57.0) Gecko/20100101 Firefox/57.0",
        "HOST": "www.dongmengdai.com",
        "Referer": "https://www.dongmengdai.com/index.php?user&q=action/login",
    }

    def parse(self, response):
        """ 正式進(jìn)入爬取區(qū)域 """
        pass

    def start_requests(self):
        """
        重載start_requests方法 待登錄成功后,再進(jìn)入parse進(jìn)行數(shù)據(jù)爬取
            訪問(wèn)登錄頁(yè)面 并調(diào)用do_login方法進(jìn)行登錄
        """
        return [scrapy.Request('https://www.dongmengdai.com/index.php?user&q=action/login', headers=self.header, callback=self.do_login)]

    def do_login(self, response):
        """
        根據(jù)Network的信息 向登錄地址發(fā)送請(qǐng)求
            攜帶用戶名和密碼 如果需要token或者其他標(biāo)識(shí)則需要用正則進(jìn)行匹配笆焰,然后放到login_data中
            調(diào)用is_login方法判斷是否登錄成功
        """
        login_url = "https://www.dongmengdai.com/index.php?user&q=action/login"
        login_data = {
            "keywords": "18077365555",
            "password": "123456789"
        }
        return [scrapy.FormRequest(url=login_url,formdata=login_data,headers=self.header,callback=self.is_login)]

    def is_login(self, response):
        """
        這個(gè)網(wǎng)站登陸后會(huì)自動(dòng)跳轉(zhuǎn)到用戶中心 可根據(jù)返回的url判斷是否登錄成功
            其他網(wǎng)站可以依靠狀態(tài)碼進(jìn)行判斷
            如果登錄成功則從 start_urls中抽取url進(jìn)行爬取
            這里不用設(shè)置callback回調(diào)parse 因?yàn)樗J(rèn)調(diào)用parse
                如果是在crawl模板的爬蟲(chóng)劫谅,可能需要設(shè)置callback調(diào)用
         """
        if "index.php?user" in response.url:
            for url in self.start_urls:
                yield scrapy.Request(url, dont_filter=True, headers=self.header)
        else:
            print("登錄失敗")

具體邏輯整理

具體的邏輯我已經(jīng)寫在代碼中了,這里再整理一下:
1嚷掠、先確定起始url和設(shè)置domains
2捏检、根據(jù)觀察瀏覽器Network返回值來(lái)構(gòu)造header(因?yàn)樗沧R(shí)別請(qǐng)求頭信息)
3、重載start_requests方法并帶上請(qǐng)求頭信息來(lái)發(fā)起請(qǐng)求
4不皆、do_login方法中執(zhí)行具體的登錄操作贯城,(keywords和password是登錄框的input name,通過(guò)右鍵審查元素可以看到html結(jié)構(gòu)霹娄,通過(guò)input name來(lái)定位輸入框)以及發(fā)起請(qǐng)求
5能犯、is_login方法來(lái)判斷是否登錄成功鲫骗,并且指定了下一步操作的方法(可以開(kāi)始爬數(shù)據(jù)了)

Cookie的問(wèn)題

可以看到,上面的代碼里面只是發(fā)送了用戶名和密碼踩晶,但是常規(guī)的登錄請(qǐng)求是需要保存和發(fā)送cookie的执泰,我們?cè)诖a中并沒(méi)有保存cookie和二次請(qǐng)求攜帶cookie的操作,那Scrapy是如何完成這個(gè)行為的呢渡蜻?
在源碼目錄site-packages/scrapy/downloadermiddlewares/cookies.py文件中术吝,可以看到具體的源碼:

CookiesMiddleware的第前面兩個(gè)個(gè)方法是重載from_crawler:

    def __init__(self, debug=False):
        self.jars = defaultdict(CookieJar)
        self.debug = debug

    @classmethod
    def from_crawler(cls, crawler):
        if not crawler.settings.getbool('COOKIES_ENABLED'):
            raise NotConfigured
        return cls(crawler.settings.getbool('COOKIES_DEBUG'))

init在加載的時(shí)候初始化CookieJar,from_crawler則是檢查settings里面的cookie配置情況茸苇。

接著到process_request方法:

    def process_request(self, request, spider):
        if request.meta.get('dont_merge_cookies', False):
            return

        cookiejarkey = request.meta.get("cookiejar")
        jar = self.jars[cookiejarkey]
        cookies = self._get_request_cookies(jar, request)
        for cookie in cookies:
            jar.set_cookie_if_ok(cookie, request)

        # set Cookie header
        request.headers.pop('Cookie', None)
        jar.add_cookie_header(request)
        self._debug_cookie(request, spider)

它完成的任務(wù)大致就是設(shè)置cookie排苍,請(qǐng)求的時(shí)候就帶上。

而process_response方法又完成了什么任務(wù)呢:

    def process_response(self, request, response, spider):
        if request.meta.get('dont_merge_cookies', False):
            return response

        # extract cookies from Set-Cookie and drop invalid/expired cookies
        cookiejarkey = request.meta.get("cookiejar")
        jar = self.jars[cookiejarkey]
        jar.extract_cookies(response, request)
        self._debug_set_cookie(response, spider)

它是完成cookie的篩選学密,提取cookie和刪除廢棄的cookie

下面還有幾個(gè)方法_debug_cookie纪岁、_debug_set_cookie、_format_cookie则果、_get_request_cookies他們幾個(gè)完成了cookie的獲取幔翰、生成和格式化等任務(wù)。

cookie小結(jié)

可以得出結(jié)論西壮,Scrapy框架會(huì)自動(dòng)幫我們處理cookie的問(wèn)題遗增,在常規(guī)的使用當(dāng)中我們不需要關(guān)心它的切換和更新問(wèn)題。只有在一些邏輯處理的時(shí)候款青,有可能涉及到登錄邏輯的改動(dòng)做修,才需要了解底層原理并對(duì)某個(gè)方法進(jìn)行重載,以實(shí)現(xiàn)邏輯的變化抡草。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饰及,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子康震,更是在濱河造成了極大的恐慌燎含,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腿短,死亡現(xiàn)場(chǎng)離奇詭異屏箍,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)橘忱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門赴魁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人钝诚,你說(shuō)我怎么就攤上這事颖御。” “怎么了凝颇?”我有些...
    開(kāi)封第一講書人閱讀 165,417評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵潘拱,是天一觀的道長(zhǎng)秉继。 經(jīng)常有香客問(wèn)我,道長(zhǎng)泽铛,這世上最難降的妖魔是什么尚辑? 我笑而不...
    開(kāi)封第一講書人閱讀 58,868評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮盔腔,結(jié)果婚禮上杠茬,老公的妹妹穿的比我還像新娘。我一直安慰自己弛随,他們只是感情好瓢喉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著舀透,像睡著了一般栓票。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上愕够,一...
    開(kāi)封第一講書人閱讀 51,692評(píng)論 1 305
  • 那天走贪,我揣著相機(jī)與錄音,去河邊找鬼惑芭。 笑死坠狡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的遂跟。 我是一名探鬼主播逃沿,決...
    沈念sama閱讀 40,416評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼幻锁!你這毒婦竟也來(lái)了凯亮?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,326評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤哄尔,失蹤者是張志新(化名)和其女友劉穎假消,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體究飞,經(jīng)...
    沈念sama閱讀 45,782評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡置谦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了亿傅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡瘟栖,死狀恐怖葵擎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情半哟,我是刑警寧澤酬滤,帶...
    沈念sama閱讀 35,790評(píng)論 5 346
  • 正文 年R本政府宣布签餐,位于F島的核電站,受9級(jí)特大地震影響盯串,放射性物質(zhì)發(fā)生泄漏氯檐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評(píng)論 3 331
  • 文/蒙蒙 一体捏、第九天 我趴在偏房一處隱蔽的房頂上張望冠摄。 院中可真熱鬧,春花似錦几缭、人聲如沸河泳。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,996評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)拆挥。三九已至,卻和暖如春某抓,著一層夾襖步出監(jiān)牢的瞬間纸兔,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,113評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工否副, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留食拜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評(píng)論 3 373
  • 正文 我出身青樓副编,卻偏偏與公主長(zhǎng)得像负甸,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子痹届,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評(píng)論 2 355

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