知乎--Python模擬登錄

運行環境

Python:python 3.6.5
IDE:PyCharm 2018.1.2
抓包工具:Charles 4.2.1
操作系統:Windows 7 (32 bit)
瀏覽器:Chrome

抓包

首先先進行登錄抓包,打開Chrome瀏覽器(無痕模式),清空所有的緩存,打開Charles,然后再瀏覽器中輸入www.zhihu.com,打開知乎登錄界面。

知乎登錄界面

點擊登錄,輸入郵箱賬號和密碼,進行登錄。
可能會出現驗證碼,出現的驗證碼分兩種情形,一種是英文的由英文字母和數字組成的四個字符,一種是中文的點擊圖中倒立的文字
英文驗證碼

中文驗證碼

這里我用了錯誤的賬號和密碼進行嘗試登錄,主要是為了查看并分析多次請求流程。綜合多次的分析,發現驗證碼的獲取是不一樣的,其他的流程都相同。

一般情況下,可以嘗試輸入錯誤的密碼和驗證碼,多查看幾次登錄的請求流程。

登錄分析

  • 找到登錄請求
登錄請求

通常情況下,登錄請求都是POST請求。在這個請求中,找到了username和password,可以確定這個就是登錄請求,分析就從這里開始。
從紅框中看到出現了兩個字段:Authentication和Multipart,在其他的網站登錄沒有遇到過,Multipart是一個多部分編碼數據格式,Authentication是一種認證。


Authentication
  • Authentication

先搜索一下,發現是在一個main.app.xxxx.js的腳本中,打開看一下,都是固定值。而實際上,經過多次請求分析,可以發現Authentication就是固定不變的。
Authentication = 'C3cef7c66a1843f8b3a9e6a1e3160e20'
與此同時,也可以確定其他的固定參數。

Authentication

  • 分析登錄請求的參數
登錄請求的參數

通過觀察,只有signature還未知,client_id就是上面Authentication的值,timestamp是時間戳(13位),captcha是輸入的驗證碼,其余為固定值。

  • 解密signature
    搜索signature,搜索結果如下圖,位于main.app.xxxx.js文件中。


    搜索signature

    signature的加密過程

    在這里,我們還看到了其他的參數。
    認真分析一下,SHA-1、setHMACKey、幾個update、getHMAC,可以肯定是加密了,這里采用了HMAC加密算法。
    貼下解密代碼:


    signature的解密
  • captcha

上面我們說過,驗證碼分為英文和中文兩種,請求的URL如下

(英文)https://www.zhihu.com/api/v3/oauth/captcha?lang=en
(中文)https://www.zhihu.com/api/v3/oauth/captcha?lang=ch

驗證碼請求的GET方法

可以看出,驗證碼請求方法有三種方式

  • GET(判斷是否需要輸入驗證碼)
  • PUT(返回驗證碼的base64加密數據)


    驗證碼請求的PUT方法
  • POST(返回驗證碼的驗證結果)


    驗證碼請求的POST方法

對驗證碼這塊,有一個小技巧,我們只使用英文格式的驗證碼,利用GET方法的返回值,判斷是否為True,不為True,重新GET,直到返回值為True。

這樣就避免了,較為復雜的中文驗證碼的識別和操作。

重點說明一下,圖片的驗證請求是在登錄請求之前完成的。
到此,所有的提交參數都搞定了,接下來看一看headers

  • 分析headers

authorization的值是固定的,與clien_id的值一樣。

  • X-Xsrftoken

搜索一下這個值


搜索X-Xsrftoken

X-Xsrftoken的源

來自于

首頁的請求response中設置的cookies值

可以直接從cookies中提取_xsrf值,加入headers即可。

  • X-UDID

也來自

首頁的請求response中設置的cookies值

可以直接從cookies中提取d_c0值,加入headers即可。

分析到這里,基本就完成了,可以發送請求了。

發送請求

  • multipart/form-data
Multipart

這種表單也是第一次提交,查資料找到一個requests_toolbelt,可以提交這種類型的數據。(使用MultipartEncoder類)。

boundary

boundary 就是一個Multipart數據分界線,大小寫英文字母和數字組成,共16位。

import base64
import hmac
import random
import time
from hashlib import sha1

import requests
import urllib3
from requests_toolbelt import MultipartEncoder

urllib3.disable_warnings()


class ZhihuLogin:

    def __init__(self, username, password):
        if username.isdigit():
            self.username = '+86{}'.format(username)
        if '@' in username:
            self.username = username
        self.password = password
        self.s = requests.session()
        self.s.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 '
                          'Safari/537.36'
        }
        self.s.verify = False

    @staticmethod
    def signature(timestamp):
        key = b'd1b964811afb40118a12068ff74a12f4'
        r = hmac.new(key, digestmod=sha1)
        r.update(b'password')
        r.update(b'c3cef7c66a1843f8b3a9e6a1e3160e20')
        r.update(b'com.zhihu.web')
        r.update(timestamp.encode())
        return r.hexdigest()

    @staticmethod
    def random_boundary():
        temp = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
        boundary = '----WebKitFormBoundary{}'.format(''.join(random.choices(temp, k=16)))
        return boundary

    def cookie_from_home(self):
        self.s.get('https://www.zhihu.com')
        cookie = self.s.cookies
        if cookie.get('_xsrf'):
            self.s.headers['X-Xsrftoken'] = cookie.get('_xsrf')
        if cookie.get('d_c0'):
            self.s.headers['X-UDID'] = cookie.get('d_c0').strip('"').split('|')[0]

    def captcha(self):
        url = 'https://www.zhihu.com/api/v3/oauth/captcha'
        params = {
            'lang': 'en',
        }
        self.s.headers['Authorization'] = 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20'
        result = self.s.get(url, params=params).json()
        if not result.get('show_captcha'):
            self.captcha()
        else:
            result = self.s.put(url, data=params).json()
            with open('captcha.bmp', 'wb') as f:
                f.write(base64.b64decode(result.get('img_base64')))

            code = input('請輸入驗證碼:')
            multipart = MultipartEncoder(
                fields={
                    'input_text': code,
                },
                boundary=self.random_boundary()
            )
            self.s.headers['Content-Type'] = multipart.content_type
            result = self.s.post(url, data=multipart.read(), params=params).json()
            if result.get('success'):
                print('驗證碼正確')
            return code

    def login(self):
        code = self.captcha()
        timestamp = str(int(time.time() * 1000))
        multipart = MultipartEncoder(
            fields={
                'client_id': 'c3cef7c66a1843f8b3a9e6a1e3160e20',
                'grant_type': 'password',
                'timestamp': timestamp,
                'source': 'com.zhihu.web',
                'signature': self.signature(timestamp),
                'username': self.username,
                'password': self.password,
                'captcha': code,
                'lang': 'en',
                'ref_source': 'homepage',
                'utm_source': '',
            },
            boundary=self.random_boundary()
        )
        self.s.headers['Content-Type'] = multipart.content_type

        url = 'https://www.zhihu.com/api/v3/oauth/sign_in'
        result = self.s.post(url, data=multipart.read()).json()
        if 'user_id' in result:
            print('登陸成功!')


if __name__ == '__main__':
    zhihu = ZhihuLogin('知乎郵箱(手機)賬號', '知乎密碼')
    zhihu.cookie_from_home()
    zhihu.login()

下面貼上兩張 運行結果圖(郵箱登錄和手機號碼登錄)

郵箱登錄
手機號碼登錄

最后更新于 2018-05-15 18:39:23

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370