來吧,既然已經開了頭,我們還是要完結一下這個流程,抽個空,接着上篇的來講一下……
這裏有個小插曲,我爲了方便,看了個某位革命同胞提取的加密的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" \
"×tamp={}" \
"&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和接下來怎麼操作就不用我再過多的說了吧,該幹嘛幹嘛……
自動模擬登錄知乎的方法就到這裏了,我拍了拍衣袖,不帶走一絲浮塵……
感覺今天有點累,講起來都比較簡潔,直接代碼說話,裏面都有註釋,如果這篇文章對知乎造成了什麼傷害,請主動聯繫我,我保持着認真負責的態度會立即刪除掉~~!(知乎:你算哪根蔥,沒空理你……)
這裏面的操作都是自己嘔心瀝血一步一步實現的,點不點贊無所謂,希望只是學習交流這個過程,到最後還是那句話,想要源碼的白嫖兄弟們可以給我留言,可以加公衆號回覆:知乎
關注公衆號,我就是我,一個不一樣的自我