最新python模拟登录知乎

步骤:

  • 第一步:抓包查看登陆接口
  • 第二步:分析js文件,提取加密请求参数的js脚本
  • 第三步:分析js文件,构造需要加密的字符串
  • 第四步:编写代码模拟请求登陆

第一步:抓包查看post登陆接口

登陆接口

参数(可以看到post的数据是经过加密的)

第二步:分析js文件,提取加密请求参数的js脚本

通过全局搜索sign_in字段,找到对应post请求

我们看到feachOpiton中的zsEncrypt参数为ture,zsEncrypt为ture应该是代表body需要加密,断点后通过控制台执行Object(d.decamelizeKeys)(e),可以获取到body参数

通过搜索zsEncrypt字段,可以找到请求时对body进行加密的函数

断点后发现o.default 为实际的加密函数,a为需要加密的字符串

控制台调用o.default(a)可以获取到加密后字符

进入o.defaul函数,o.defaul实际为加密模块中对外暴露的Q加密函数

接下来需要提取加密模块,然后使用python执行提取出来的js脚本

将Q函数所在的函数复制到本地zhihu.js文件,将最外层函数删掉,只保存里面的代码

同时将export模块相关的代码删掉

在zhihu.js最后调用Q函数加密需要加密的a字符串

创建zhihu.html文件,引入zhihu.js文件

使用浏览器打开文件,控制台console中可以看到加密过的字符串

此时我们已经提取出了加密所需要的js文件,可以通过浏览器执行,但时通过python执行会发现无法执行,原因是浏览器环境和python执行js的node环境不同,使用vscode断点试调后发现node环境先缺少window对象、navigator对象(过程比较繁琐,有兴趣的可以自己去试调研究下),并且window对象下需要有encodeURIComponent函数,navigator对象下需要有userAgent属性。同时也需要用到atob函数,通过全局搜索atob可以找到zap.js文件中的atob函数,atob函数实际上是将base64编码的字符串转换二进制编码的字符串。缺少的这些我们可以自己定义出来,添加到zhihu.js文件开头。


此时提取出来的zhihu.js文件已经可以正常运行了

我们自己定义一个encrypt函数供python调用,这样就完成了加密js的提取

使用python调用执行js脚本

import execjs

def encrypt(string):
    with open('./zhihu.js', 'r', encoding='utf-8') as f:
        js = f.read()
    result = execjs.compile(js).call('encrypt', string)
    return result

print(encrypt('123456'))

第三步:分析js文件,构造需要加密的字符串

需要加密的字符串:

client_id=c3cef7c66a1843f8b3a9e6a1e3160e20&
grant_type=password&
timestamp=1551062570616&
source=com.zhihu.web&
signature=e3ab73425750a4dbcf9ab357f6030fc281ceeb22&
username=819221111@qq.com&
password=123456&
captcha=&
lang=en&
ref_source=homepage&
utm_source=

这些参数中会变的参数的总共有四个,分别是timestamp,signature,username,password,这些需要我们自己传入,capthca参数是有验证码的时候需要传,我还没遇到过需要输入验证码的,这里我们不作考虑。真正需要我们构造的只有signature参数,下面介绍如何构造

全局搜索signature,在main.app.xxx.js 中可以找到singnature的构造方法,是通过hmac加密
clientId,grantType,source,timestamp四个参数获得的

使用python模拟加密的js,代码如下

import time
import hmac
from hashlib import sha1    

def get_signature():
    h = hmac.new(key='d1b964811afb40118a12068ff74a12f4'.encode('utf-8'), digestmod=sha1)
    grant_type = 'password'
    client_id = 'c3cef7c66a1843f8b3a9e6a1e3160e20'
    source = 'com.zhihu.web'
    now = str(int(time.time()*1000))
    h.update((grant_type + client_id + source + now).encode('utf-8'))
    return h.hexdigest()
print(get_signature())

第四步:编写代码模拟请求登陆

我们的准备工作已经完成了,下面开始编写代码模拟请求

  • 第一步:请求请求login_url,udid_url,captcha_url加载所需要的cookie
  • 第二步:构造需要加密的字符串
  • 第三步:加密字符串
  • 第四步:使用加密后的字符串请求post登陆接口

完整代码如下:

import requests
import re
import execjs
import time
import hmac
from hashlib import sha1

class Zhihu(object):

    def __init__(self, username, password):

        self.username = username
        self.password = password
        self.session = requests.session()
        # 此处请求头只需要这三个
        self.headers = {
            'content-type': 'application/x-www-form-urlencoded',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36',
            'x-zse-83': '3_1.1'
        }

    def login(self):

        # 请求login_url,udid_url,captcha_url加载所需要的cookie
        login_url = 'https://www.zhihu.com/signup?next=/'
        resp = self.session.get(login_url, headers=self.headers)        
        print("请求{},响应状态码:{}".format(login_url,resp.status_code)) 
        # print(self.session.cookies.get_dict())
        # self.save_file('login',resp.text)

        udid_url = 'https://www.zhihu.com/udid'
        resp = self.session.post(udid_url, headers=self.headers)
        print("请求{},响应状态码:{}".format(udid_url,resp.status_code)) 
        # print(self.session.cookies.get_dict())

        captcha_url = 'https://www.zhihu.com/api/v3/oauth/captcha?lang=en'
        resp = self.session.get(captcha_url, headers=self.headers)
        print("请求{},响应状态码:{}".format(captcha_url,resp.status_code)) 
        # print(self.session.cookies.get_dict())
        # print(resp.text)
        # self.save_file('captcha',resp.text)
        
        # 校验是否需要验证吗,需要则直接退出,还没遇到过需要验证码的
        if re.search('true',resp.text):
            print('需要验证码')
            exit()
        
        # 获取signature参数
        self.time_str = str(int(time.time()*1000))
        signature = self.get_signature()
        # print(signature)

        # 拼接需要加密的字符串
        string = "client_id=c3cef7c66a1843f8b3a9e6a1e3160e20&grant_type=password&timestamp={}&source=com.zhihu.web&signature={}&username={}&password={}&captcha=&lang=en&ref_source=homepage&utm_source=".format(self.time_str,signature,self.username,self.password)
        # print(string)
        # 加密字符串
        encrypt_string = self.encrypt(string)
        # print(encrypt_string)

        # post请求登陆接口
        post_url = "https://www.zhihu.com/api/v3/oauth/sign_in"
        resp = self.session.post(post_url, data=encrypt_string, headers=self.headers)
        print("请求{},响应状态码:{}".format(post_url,resp.status_code)) 
        # print(self.session.cookies.get_dict())
        # print(resp.text)
        # self.save_file('post',resp.text)

        # 校验是否登陆成功
        if re.search('user_id',resp.text):
            print('登陆成功')
        else:
            print("登陆失败")
            exit()

    def test(self):

        # 请求个人信息接口查看个人信息
        me_url = 'https://www.zhihu.com/api/v4/me'
        data = {
            'include': 'ad_type;available_message_types,default_notifications_count,follow_notifications_count,vote_thank_notifications_count,messages_count;draft_count;following_question_count;account_status,is_bind_phone,is_force_renamed,email,renamed_fullname;ad_type'
        }
        resp = self.session.get(me_url, data=data, headers=self.headers)
        print("请求{},响应状态码:{}".format(me_url,resp.status_code)) 
        print(resp.text)
        # self.save_file('me',resp.text)

    def encrypt(self, string):

        with open('./zhihu.js', 'r', encoding='utf-8') as f:
            js = f.read()
        result = execjs.compile(js).call('encrypt', string)
        return result

    def get_signature(self):

        h = hmac.new(key='d1b964811afb40118a12068ff74a12f4'.encode('utf-8'), digestmod=sha1)
        grant_type = 'password'
        client_id = 'c3cef7c66a1843f8b3a9e6a1e3160e20'
        source = 'com.zhihu.web'
        now = self.time_str
        h.update((grant_type + client_id + source + now).encode('utf-8'))
        return h.hexdigest()

    def save_file(self, name, html):

        with open('{}.html'.format(name),'w',encoding='utf-8') as f:
            f.write(html)
        

if __name__ == "__main__":

    account = Zhihu('账号','密码')
    account.login()
    account.test()

登陆成功

代码

链接:https://pan.baidu.com/s/1aqzzkacgQM0n2ewV6r7csg
提取码:inv2

参考文章

https://zhuanlan.zhihu.com/p/34073256
https://mp.weixin.qq.com/s/XplpQ6QUophvgfyMszk0Hg

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容