2020版python實現模擬登錄知乎(包含自動過驗證碼) (下)

來吧,既然已經開了頭,我們還是要完結一下這個流程,抽個空,接着上篇的來講一下……

這裏有個小插曲,我爲了方便,看了個某位革命同胞提取的加密的js方式,覺得這用比較簡單方便,不需要修改JS中的內容,於是就這樣寫了下:

保持從加密JS裏copy出來的代碼不用修改,就用上面2個方法代理了在NODEjS(V8)中缺少的的函數,But……萬萬沒想到就是這個方法讓我掉進一個坑,費了幾個小時的時間,因爲在瀏覽器中調試這段代碼和知乎上加密後的結果一樣的,但是在python中加密後結果死活不一樣,最後調試發現這樣定義就改變了引擎中window的對象,將這個window方法刪除掉,還是直接按上篇說的將 typeof window改成true或者1,加密後結果就和瀏覽器的一樣了,只是後面多了個_xxx的小尾巴,將它截取掉。

我們測試已加密123456爲例   

在python中:

瀏覽器中:

ok……下面我們來說下執行的方法,其實很多類似的文章裏都有了,我就簡單的說下,我們根據瀏覽器的加載情況來看,知乎是先請求是否要驗證碼

如果爲true的話就再次請求這個鏈接獲取圖片:

那我們就寫一個獲取驗證碼的方法:

#獲取驗證碼並驗證
def get_captcha(self):
    # 首先訪問一次看下是否需要驗證碼
    batchurl='https://www.zhihu.com/api/v3/oauth/captcha?lang={}'.format(self.lang)
    response=self.session.get(url=batchurl,headers=self.headers,timeout=5)
    #打印一下 show_captcha:true則是需要驗證碼
    print(response.text)
    rjson=json.loads(response.text,encoding="utf-8")
    if rjson["show_captcha"]:
        #如果爲true,則用put請求圖片base64碼
        response = self.session.put(url=batchurl,headers=self.headers,timeout=5)
        imgbase64=json.loads(response.text,encoding="utf-8")["img_base64"]
        #這裏調用識別驗證的接口
        captcha_result = self.ocr_captcha(imgbase64)
        # captcha = input('輸入驗證碼:')
        #判斷類型傳遞對應的參數值
        if self.lang == 'cn':
            #這裏循環數據除以2是因爲,中文驗證碼圖片是400X88,這是的尺寸是200,44所以除以2
            tsrc= json.dumps({"img_size": [200, 44],"input_points": [[i[0]/2, i[1]/2] for i in captcha_result]})
            data = {"input_text": tsrc}
        else:
            data = {"input_text": captcha_result}
        # 進入驗證,返回success:true則表示驗證成功
        print(data)
        r=self.session.post(batchurl, headers=self.headers,data=data)
        print(r.text)
        if self.lang == 'cn':
            return parse.quote(tsrc)
        else:
            return captcha_result
    else:
        return ''

上面呢,我是調用了中文的驗證碼來登陸的,是因爲我的自動識別英文的驗證碼目前還在用pytorch訓練中……,怎麼訓練?這個話題就長了,這個沒有個把月是說不是清楚的,中文的驗證碼用了下革命同胞的模型,我部署了到了自己網站的一個接口,可以通過網址:https://www.xiuler.com/docs,註冊一個賬號後調用,https://www.xiuler.com/ocr/ocr_post,參數typeid:4,請記住這個隱藏參數:captcha_type:"zhihu",上面的self.ocr_captcha的方法長這樣:

#識別驗證碼
def ocr_captcha(self,imgbase64):
    data = {
        "mode": "base64",
        "base64": imgbase64,
        "appid": self.appid,
        "appsecret": self.appsecret,
        "typeid": 4,
        "captcha_type": "zhihu"
    }
    response = requests.post(url=self.captcha_url, data=data)
    result = json.loads(response.text, encoding="utf-8")
    captcha_result=result["words_result"]
    return captcha_result

獲取驗證碼以後,我們就開始生成登錄的加密formdata的參數,首先我們封裝一下上篇的加密方法:

#獲取加密後的formdata
def get_formdata(self,data):
    with open('zh_encrypt.js', 'r', encoding='utf-8') as f:
        js = execjs.compile(f.read())
        result = js.call('b', data)
        return result

來,繼續……,接着封裝一下獲取signature的hmac加密簽名方法:

#獲取signature
def get_signature(self,time_str):
    h = hmac.new(key='d1b964811afb40118a12068ff74a12f4'.encode('utf-8'), digestmod=sha1)
    grant_type = 'password'
    client_id = 'c3cef7c66a1843f8b3a9e6a1e3160e20'
    source = 'com.zhihu.web'
    h.update((grant_type + client_id + source + time_str).encode('utf-8'))
    return h.hexdigest()

這裏面很多參數都是固定的,就只需要傳一個時間戳,接着我們組裝一下要加密的數據:

dtime=int(time.time()*1000)
#拼裝數據
post_data = "client_id=c3cef7c66a1843f8b3a9e6a1e3160e20" \
            "&grant_type=password" \
            "&timestamp={}" \
            "&source=com.zhihu.web" \
            "&signature={}" \
            "&username={}" \
            "&password={}" \
            "&captcha={}" \
            "&lang={}" \
            "&ref_source=other_https%3A%2F%2Fwww.zhihu.com%2Fsignin%3Fnext%3D%252F" \
            "&utm_source=".format(dtime, self.get_signature(str(dtime)), self.uname, self.pwd,self.get_captcha(),self.lang)
#調用加密方法
formdata=self.get_formdata(post_data)
#經觀察加密後的結果和瀏覽器生成的後面多了_XXX,截取一下
formdata=formdata[:formdata.rfind("_")]
print(formdata)

到此我們就拿到了加密後的formdata數據,接着我們就請求登錄接口:

#爲了醒目,我這裏單獨寫個headers,請務必保證這個請求頭有這3個參數,因爲JS裏有這3個參數,接口會驗證
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36',
    'content-type': 'application/x-www-form-urlencoded',
    'x-zse-83':'3_2.0',
}
#知乎登錄接口
post_url='https://www.zhihu.com/api/v3/oauth/sign_in'
response = self.session.post(url=post_url, data=formdata, headers=headers)
#打印一下獲取到的登錄結果
print(json.loads(response.text,encoding="utf-8"))
if response.status_code == 201:
    #保存一下cookies
    self.session.cookies.save()
    print("登錄成功")
else:
    print("登錄失敗")

執行一下打印下結果看看:

至此,就獲取到了登錄成功後的cookie,這裏讀取cookie和接下來怎麼操作就不用我再過多的說了吧,該幹嘛幹嘛……

自動模擬登錄知乎的方法就到這裏了,我拍了拍衣袖,不帶走一絲浮塵……

感覺今天有點累,講起來都比較簡潔,直接代碼說話,裏面都有註釋,如果這篇文章對知乎造成了什麼傷害,請主動聯繫我,我保持着認真負責的態度會立即刪除掉~~!(知乎:你算哪根蔥,沒空理你……)

這裏面的操作都是自己嘔心瀝血一步一步實現的,點不點贊無所謂,希望只是學習交流這個過程,到最後還是那句話,想要源碼的白嫖兄弟們可以給我留言,可以加公衆號回覆:知乎 

關注公衆號,我就是我,一個不一樣的自我

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章