2019年最新 Python 模拟登录知乎 支持验证码
知乎的登录页面已经改版多次,加强了身份验证,网络上大部分模拟登录均已失效,所以我重写了一份完整的,并实现了提交验证码 (包括中文验证码),本文我对分析过程和代码进行步骤分解,完整的代码请见末尾 Github 仓库,不过还是建议看一遍正文,因为代码早晚会失效,解析思路才是永恒。
分析 POST 请求
首先打开控制台正常登录一次,可以很快找到登录的 API 接口,这个就是模拟登录 POST 的链接。
我们的最终目标是构建 POST 请求所需的 Headers 和 Form-Data 这两个对象即可。
构建 Headers
继续看Requests Headers信息,和登录页面的 GET 请求对比发现,这个 POST 的头部多了三个身份验证字段,经测试x-xsrftoken是必需的。
x-xsrftoken则是防 Xsrf 跨站的 Token 认证,访问首页时从Response Headers的Set-Cookie字段中可以找到。
构建 Form-Data
Form部分目前已经是加密的,无法再直观看到,可以通过在 JS 里打断点的方式(具体这里不再赘述,如不会打断点请自行搜索)。
然后我们逐个构建上图这些参数:
timestamp 时间戳,这个很好解决,区别是这里是13位整数,Python 生成的整数部分只有10位,需要额外乘以1000
timestamp = str(int(time.time()*1000))
signature 通过 Ctrl+Shift+F 搜索找到是在一个 JS 里生成的,是通过 Hmac 算法对几个固定值和时间戳进行加密,那么只需要在 Python 里也模拟一次这个加密即可。
def _get_signature(self, timestamp):
ha = hmac.new(b'd1b964811afb40118a12068ff74a12f4', digestmod=hashlib.sha1)
grant_type = self.login_data['grant_type']
client_id = self.login_data['client_id']
source = self.login_data['source']
ha.update(bytes((grant_type + client_id + source + timestamp), 'utf-8'))
return ha.hexdigest()
captcha 验证码,是通过 GET 请求单独的 API 接口返回是否需要验证码(无论是否需要,都要请求一次),如果是 True 则需要再次 PUT 请求获取图片的 base64 编码。
resp = self.session.get(api, headers=headers)
show_captcha = re.search(r'true', resp.text)
if show_captcha:
put_resp = self.session.put(api, headers=headers)
json_data = json.loads(put_resp.text)
img_base64 = json_data['img_base64'].replace(r'\n', '')
with open('./captcha.jpg', 'wb') as f:
f.write(base64.b64decode(img_base64))
img = Image.open('./captcha.jpg')
实际上有两个 API,一个是识别倒立汉字,一个是常见的英文验证码,任选其一即可,代码中我将两个都实现了,汉字是通过 plt 点击坐标,然后转为 JSON 格式。(另外,这里其实可以通过重新请求登录页面避开验证码,如果你需要自动登录的话可以改造试试)
最后还有一点要注意,如果有验证码,需要将验证码的参数先 POST 到验证码 API,再随其他参数一起 POST 到登录 API。
if lang == 'cn':
import matplotlib.pyplot as plt
plt.imshow(img)
print('点击所有倒立的汉字,按回车提交')
points = plt.ginput(7)
capt = json.dumps({'img_size': [200, 44],
'input_points': [[i[0]/2, i[1]/2] for i in points]})
else:
img.show()
capt = input('请输入图片里的验证码:')
# 这里必须先把参数 POST 验证码接口
self.session.post(api, data={'input_text': capt}, headers=headers)
return capt
然后把 username 和 password 两个值更新进去,其他字段都保持固定值即可。
self.login_data.update({
'username': self.username,
'password': self.password,
'lang': captcha_lang
})
timestamp = int(time.time()*1000)
self.login_data.update({
'captcha': self._get_captcha(self.login_data['lang']),
'timestamp': timestamp,
'signature': self._get_signature(timestamp)
})
加密 Form-Data
但是现在知乎必须先将 Form-Data 加密才能进行 POST 传递,所以我们还要解决加密问题,可由于我们看到的 JS 是混淆后的代码,想窥视其中的加密实现方式是一件很费精力的事情。
所以这里我采用了 sergiojune 这位知友通过 pyexecjs 调用 JS 进行加密的方式,只需要把混淆代码完整复制过来,稍作修改即可。
具体可看他的原文:https://zhuanlan.zhihu.com/p/57375111
with open('./encrypt.js') as f:
js = execjs.compile(f.read())
return js.call('Q', urlencode(form_data))
这里也感谢他分享了一些坑,不然确实不好解决。
保存 Cookies
最后实现一个检查登录状态的方法,如果访问登录页面出现跳转,说明已经登录成功,这时将 Cookies 保存起来(这里 session.cookies 初始化为 LWPCookieJar 对象,所以有 save 方法),这样下次登录可以直接读取 Cookies 文件。
def check_login(self):
resp = self.session.get(self.login_url, allow_redirects=False)
if resp.status_code == 302:
self.session.cookies.save()
return True
return False
完整代码
请关注微信公众号:面向人生编程
回复【知乎】获取本文代码
回复【资料】获取本人精选的学习资料

2019年最新 Python 模拟登录知乎 支持验证码的更多相关文章
- python模拟登录知乎
# -*- coding:utf-8 -*- import urllib import urllib2 import cookielib import sys from bs4 import Beau ...
- 2020.10.20 利用POST请求模拟登录知乎
前两天学习了Python的requests模块的相关内容,对于用GET和PSOT请求访问网页以抓取需要的内容有了初步的了解,想要再从一些复杂的网站积累些经验.最开始我采用最简单的get(url)方法想 ...
- 【爬虫】python requests模拟登录知乎
需求:模拟登录知乎,因为知乎首页需要登录才可以查看,所以想爬知乎上的内容首先需要登录,那么问题来了,怎么用python进行模拟登录以及会遇到哪些问题? 前期准备: 环境:ubuntu,python2. ...
- Python爬虫初学(三)—— 模拟登录知乎
模拟登录知乎 这几天在研究模拟登录, 以知乎 - 与世界分享你的知识.经验和见解为例.实现过程遇到不少疑问,借鉴了知乎xchaoinfo的代码,万分感激! 知乎登录分为邮箱登录和手机登录两种方式,通过 ...
- Python爬虫入门(基础实战)—— 模拟登录知乎
模拟登录知乎 这几天在研究模拟登录, 以知乎 - 与世界分享你的知识.经验和见解为例.实现过程遇到不少疑问,借鉴了知乎xchaoinfo的代码,万分感激! 知乎登录分为邮箱登录和手机登录两种方式,通过 ...
- Python模拟登录实战(三)
目标:模拟登录知乎 代码如下: #!/usr/bin/env python # -*- coding:utf-8 -*- __author__ = 'ziv·chan' import re impor ...
- 【Python数据分析】Python模拟登录(一) requests.Session应用
最近由于某些原因,需要用到Python模拟登录网站,但是以前对这块并不了解,而且目标网站的登录方法较为复杂, 所以一下卡在这里了,于是我决定从简单的模拟开始,逐渐深入地研究下这块. 注:本文仅为交流学 ...
- 【py登陆】python模拟登录
用Python模拟登录网站 前面简单提到了 Python 模拟登录的程序,但是没写清楚,这里再补上一个带注释的 Python 模拟登录的示例程序.简单说一下流程:先用cookielib获取cookie ...
- requests_模拟登录知乎
如何登录知乎? 首先要分析,进行知乎验证的时候,知乎服务器需要我们提交什么数据,提交的地址.先进行几次登录尝试,通过浏览器中network中查看数据流得知,模拟登录知乎需要提供5个数据,分别是_xsr ...
随机推荐
- 简单了解junit的使用
普通使用: 在没有用测试框架之前,我们要用一个main方法来跑代码,而有了像junit这样的测试框架后,就可以不用次次写个main方法了. 直接上代码,注释里有说明: package com.stuP ...
- jQuery prop() 与 removeProp()源码解读
prop() prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // don't ...
- JQueryUI基础知识学习
JQueryUI官网 http://jqueryui.com/ 菜鸟教程 http://www.runoob.com/jqueryui/jqueryui-tutorial.html
- 使用Intellij IDEA搭建一个简单的Maven项目
IntelliJ IDEA是Java最优秀的开发工具,它功能全面,提示比较智能,开发界面炫酷,新技术支持的比较迅速. 我使用了Eclipse快10年了,IntelliJ IDEA这么好用必须要试一试. ...
- [windows]设置使用空白密码进行远程登录
前提:系统用户设置了空白密码 方法1步骤: 开始菜单--〉运行--〉输入:gpedit.msc--> 计算机配置--〉Windows设置--〉安全设置--〉本地策略--〉安全选项:帐户:使用空白 ...
- 【Web应用-网络连接】关于 Azure Web 应用 4 分钟空闲连接的限制
Azure Web 应用后台在处理耗时较长的请求时,并且在此期间,客户端和 Azure Web 应用没有数据交互,即 TCP 连接一直处于空闲状态,此种情况超过 4 分钟后,Azure Web 应用会 ...
- ajax传给springMVC数据编码集问题
前台 ajax: $.ajax("${pageContext.request.contextPath}/hello",// 发送请求的URL字符串. { dataType : &q ...
- 洛谷 P3183 [HAOI2016]食物链
题目描述 如图所示为某生态系统的食物网示意图,据图回答第1小题现在给你n个物种和m条能量流动关系,求其中的食物链条数.物种的名称为从1到n编号M条能量流动关系形如a1 b1a2 b2a3 b3.... ...
- Fedora19添加和设置YUM源
Fedora19添加和设置YUM源添加yum源前先安装fastestmirror/downloadonly插件和axelget插件: 1.安装fastestmirror/downloadonly插件 ...
- HDOJ4550 卡片游戏 随便销毁内存的代价就是wa//string类的一些用法
思路 标记最小的最后的位置 放在第一位 标记位置之前按left值小的左方大的右方 标记位置之后按顺序放在最后 不多说先贴上销毁内存的wa代码 销毁内存的wa代码 #include<cstdio ...