用scrapy 模擬知乎的登錄過程

本人剛開始學習,可能有些不對的地方,希望大家指正~~

首先,我們分析下知乎登陸的接口,打開瀏覽器,到知乎的登陸界面,隨便輸入一個賬號密碼,查看點擊登陸它幹了些什麼(別輸入正確的,不然他就跳到首頁去啦~)
這裏寫圖片描述
可以看到它調用了一個phone_num的接口(郵箱登陸同理就不演示了),再看下這個接口的參數
這裏寫圖片描述
出了那個_xsrf外,其他參數根據名字大概都可以猜到了
我們先來看看這個_xsrf從哪裏來的,打開網頁源碼,查找_xsrf,發現有一個叫_xsrf的隱藏input標籤,值和我們傳入的這個參數是一樣的
這裏寫圖片描述
這樣,我們就可以直接去取了
除了這個_xsrf外,我們還看到有一個叫captcha的參數,我們猜測它應該就是驗證碼,我們爲了看看這個驗證碼是如何獲得的,刷新一下看看
這裏寫圖片描述
發現它調了這樣一個接口,我們把這個url複製下來,然後直接打開看看~發現正是我們的驗證碼,我們看這個驗證碼,他是讓我們點擊倒立的字,再看我們上傳的參數,除了那張圖片的大小外,還有一個input_points的參數,應該就是我們點擊的點的座標,服務器通過這個判斷我們是否點擊了倒立的字,如果我們這樣傳參數的話,驗證碼圖片的大小我們看上去是固定的,但是這個座標就比較麻煩了,我們再來分析一下這個請求驗證碼的url的參數,有3個參數,r,type,lang,最後一個參數好像是表示語言是中文,我們把它變爲en驗證一下,
這裏寫圖片描述
發現請求變成了這樣一張圖片,這不就是直接輸入驗證碼的圖片了麼~如果可以用這個輸入驗證碼的話我們就可以解決驗證碼這個參數了

好了,請求的分析差不多就這樣了~下面我們可以開始寫代碼了

先一下我使用的python版本爲3.6
新建一個scrapy的項目,新建一個爬蟲(以scrapy的base模板新建~另外,這篇文章就做登錄的過程,item,pipelines,middleware,settings這些文件就用默認的就行了~)

我們想一下,這個登錄的過程中,我們有兩個接口需要調用,1是獲取驗證碼,2就是登錄,毫無疑問,獲取驗證碼應該優先調用,我們把我們的初始url定爲獲取驗證碼,再看一下我們上面驗證碼接口的參數,有個r的參數,是一串數字,我們優先應該想到是一個和時間有關的參數,我們先用當前時間來試試,我們的入口函數start_requests就變成下面這樣

    def start_requests(self):
        t = str(int(time.time() * 1000))
        captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + '&type=login&lang=en'
        return [scrapy.Request(url=captcha_url, headers={},
        callback=self.parser_captcha)]

debug 看下我們的回調函數的response
發現服務器返回了500的錯誤,並未進入我們的回調函數,再去看下我們的網絡請求的header,我們知道scrapy對於cookie等一系列值都已經封裝好了,但是下面有一個Use-Agent的參數,是需要我們傳的,它表示了我們的系統信息以及我們的瀏覽器信息等一系列信息,我們直接在我們的瀏覽器複製這個,在我們的header裏傳進去,再次debug,進入到回調函數裏了
這裏寫圖片描述
看出body是一個二進制文件,我們把文件寫入本地看看是不是我們要的驗證碼圖片(注意:這裏要用pillow的Image來把圖片展示出來),發現我們的猜測都是正確的,打開就是我們的驗證碼圖片了,然後就是讀取驗證碼裏的信息問題了,這裏就用簡單的打開圖片我們手動輸入的方式,當然,還可以用雲打碼這種三方平臺來讀取驗證碼信息,就可以讓爬蟲全程不需要人來操作了
接下來,我們就需要去調用登錄的接口了,記得前面我們說的參數有個_xsrf的,我們先去取這個參數

_xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()

參數都齊了,我們去調接口去~

    def login(self, response):
        xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()
        if xsrf is None:
            return ''
        post_url = 'https://www.zhihu.com/login/phone_num'
        post_data = {
            "_xsrf": xsrf,
            "phone_num": 'your phone number',
            "password": 'your password',
            "captcha": response.meta['captcha']
        }
        return [scrapy.FormRequest(url=post_url, formdata=post_data, headers=self.header, callback=self.check_login)]

後面還寫了個檢查登錄是否成功的回調

    def check_login(self, response):
        js = json.loads(response.text)
        if 'msg' in js and js['msg'] == '登錄成功':
            for url in self.start_urls:
                yield scrapy.Request(url=url, headers=self.header, dont_filter=True)

運行一下我們的爬蟲
這裏寫圖片描述
嗯 ,成功了,接下來就可以去主頁上爬取自己感興趣的內容了
第一次寫博客,有很多東西可能描述的也不是很清楚,最後把這個爬蟲的完整代碼放上來吧

# -*- coding: utf-8 -*-
import json
import os

import scrapy
import time

from PIL import Image


class ZhihuloginSpider(scrapy.Spider):
    name = 'zhihulogin'
    allowed_domains = ['www.zhihu.com']
    start_urls = ['https://www.zhihu.com/']
    Agent = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'
    header = {
        'User-Agent': Agent,
    }

    def parse(self, response):
        #主頁爬取的具體內容
        pass

    def start_requests(self):
        t = str(int(time.time() * 1000))
        captcha_url = 'https://www.zhihu.com/captcha.gif?r=' + t + '&type=login&lang=en'
        return [scrapy.Request(url=captcha_url, headers=self.header, callback=self.parser_captcha)]

    def parser_captcha(self, response):
        with open('captcha.jpg', 'wb') as f:
            f.write(response.body)
            f.close()
        try:
            im = Image.open('captcha.jpg')
            im.show()
            im.close()
        except:
            print(u'請到 %s 目錄找到captcha.jpg 手動輸入' % os.path.abspath('captcha.jpg'))
        captcha = input("please input the captcha\n>")
        return scrapy.FormRequest(url='https://www.zhihu.com/#signin', headers=self.header, callback=self.login, meta={
            'captcha': captcha
        })

    def login(self, response):
        xsrf = response.xpath("//input[@name='_xsrf']/@value").extract_first()
        if xsrf is None:
            return ''
        post_url = 'https://www.zhihu.com/login/phone_num'
        post_data = {
            "_xsrf": xsrf,
            "phone_num": 'your phone number',
            "password": 'your password',
            "captcha": response.meta['captcha']
        }
        return [scrapy.FormRequest(url=post_url, formdata=post_data, headers=self.header, callback=self.check_login)]

    # 驗證返回是否成功
    def check_login(self, response):
        js = json.loads(response.text)
        if 'msg' in js and js['msg'] == '登錄成功':
            for url in self.start_urls:
                yield scrapy.Request(url=url, headers=self.header, dont_filter=True)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章