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"]
        #获取到的有换行标签,解码一下
        imgbase64=parse.unquote(imgbase64)
        #这里调用识别验证的接口
        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和接下来怎么操作就不用我再过多的说了吧,该干嘛干嘛……

自动模拟登录知乎的方法就到这里了。

感觉今天有点累,讲起来都比较简洁,直接代码说话,里面都有注释,如果这篇文章对知乎造成了什么伤害,请主动联系我,我保持着认真负责的态度会立即删除掉~~!

这里面的操作都是自己呕心沥血一步一步实现的,点不点赞无所谓,希望只是学习交流这个过程,到最后还是那句话,想要源码的白嫖兄弟们可以给我留言,可以加公众号回复:知乎 

关注公众号,我就是我,一个不一样的自我

  • 3
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值