2019年最新 Python 模拟登录知乎 支持验证码和保存 Cookies

知乎的登录页面已经改版多次,加强了身份验证,网络上大部分模拟登录均已失效,所以我重写了一份完整的,并实现了提交验证码 (包括中文验证码),本文我对分析过程和代码进行步骤分解,完整的代码请见末尾 Github 仓库,不过还是建议看一遍正文,因为代码早晚会失效,解析思路才是永恒。

分析 POST 请求

首先打开控制台正常登录一次,可以很快找到登录的 API 接口,这个就是模拟登录 POST 的链接。

我们的最终目标是构建 POST 请求所需的 Headers 和 Form-Data 这两个对象即可。

构建 Headers

继续看Requests Headers信息,和登录页面的 GET 请求对比发现,这个 POST 的头部多了三个身份验证字段,经测试x-xsrftoken是必需的。 x-xsrftoken则是防 Xsrf 跨站的 Token 认证,访问首页时从Response HeadersSet-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 pltplt.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 进行加密的方式,只需要把混淆代码完整复制过来,稍作修改即可。
具体可看他的原文: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 Truereturn False
复制代码

完整代码

请关注微信公众号:面向人生编程
回复关键词 “知乎” 获取代码

编程思维不应只存留在代码之中,更应伴随于整个人生旅途,所以公众号里不只聊技术,还会聊产品/互联网/经济学等广泛话题,所以也欢迎非程序员关注。

2019年最新 Python 模拟登录知乎 支持验证码相关推荐

  1. 小试牛刀:使用Python模拟登录知乎

    2019独角兽企业重金招聘Python工程师标准>>> 作者:刘帝伟(微博:@拾毅者) 原文链接:点击这里 BitTiger尊重原创版权,转载已经过授权. 最近突然对爬虫兴趣倍增,主 ...

  2. 使用Python模拟登录知乎

    环境与开发工具 在抓包的时候,开始使用的是Chrome开发工具中的Network,结果没有抓到,后来使用Fiddler成功抓取数据.下面逐步来细化上述过程. 模拟知乎登录前,先看看本次案例使用的环境及 ...

  3. Python 模拟登录知乎

    前言 必备知识点 headers Referer User-Agent 隐藏域 其他 模拟登录 模拟防爬 服务器端 loginphp loginhtml 浏览器测试 正常提交用户名密码的话如下 用户名 ...

  4. [Python]网络爬虫(三):使用cookiejar管理cookie 以及 模拟登录知乎

    大家好哈,上一节我们研究了一下爬虫的异常处理问题,那么接下来我们一起来看一下Cookie的使用. 为什么要使用Cookie呢? Cookie,指某些网站为了辨别用户身份.进行session跟踪而储存在 ...

  5. Python爬虫初学(三)—— 模拟登录知乎

    模拟登录知乎 这几天在研究模拟登录, 以知乎 - 与世界分享你的知识.经验和见解为例.实现过程遇到不少疑问,借鉴了知乎xchaoinfo的代码,万分感激! 知乎登录分为邮箱登录和手机登录两种方式,通过 ...

  6. Python爬虫:模拟登录知乎完全详解

    [源码在最下面] 知乎登录分为邮箱登录和手机登录两种方式,通过浏览器的开发者工具查看,我们通过不同方式登录时,网址是不一样的.邮箱登录的地址email_url = 'https://www.zhihu ...

  7. python3模拟登录知乎

    1,前言 在爬虫的世界里,模拟登录是一项必备的技能,很多网站登录才能有浏览信息的权限,今天就在python来模拟登录知乎 2,获取登录时post的参数 在网页上输入知乎的url:https://www ...

  8. header python 环境信息_【关于header信息的构造】Python模拟登录出现乱码

    使用Python模拟登录Z-Blog系统的后台时,如果构造的header信息如下,那么得到的结果将会乱码,如下图所示 对应的错误的header信息如下: url = "http://192. ...

  9. HttpClient4.4.1模拟登录知乎

    HttpClient4.4.1模拟登录知乎 一,登录要Post的表单数据是什么 这部分可以使用Wireshark工具来抓包就可以了,发现需要以下数据: "_xsrf" = xxxx ...

最新文章

  1. QT5实践:如何应用窗口菜单
  2. 关于c语言中合法的数值常量
  3. VIBE复现过程,使用nvidia和libOpenGL.so渲染出错及解决方案
  4. linux 二进制安装mysql
  5. rest api是什么_如何选择合适的API测试工具
  6. 结合CRT与欧拉定理高阶幂求余
  7. Ubuntu分辨率修改
  8. QT5.14.2+VS2019安装配置教程Windows
  9. 调查:2013年十大急需的热门IT技能
  10. Landsat8遥感数据大气校正
  11. 在线二进制取余计算机,十进制转二进制和十六进制计算器
  12. PM_24 项目管理成熟度模型(了解)、26 知识产权与标准规范、收尾管理
  13. 小样儿想封我?WebOS 1.2.1再次突破iTunes同步限制
  14. Discuz发帖如何设置默认回帖仅作者可见回帖
  15. 苹果笔的代替笔有哪些?Ipad好用电容笔测评
  16. vue3.0中props父子传值的改动
  17. html页面插入百度谷歌地图的方法
  18. python中的格式化输出
  19. Android驻留广播,Android实现Service永久驻留
  20. 敏捷开发大家谈(三)--敏捷开发技术在电子商务软件中的应用(2)

热门文章

  1. javascript返回页面顶部_RobotFramework: 执行JavaScript语句
  2. oracle增量和全量的区别,ORACLE全备份和0级增量备份的区别
  3. 高性能服务器程序框架,高性能服务器程序框架
  4. JenkinsDay18-查看服务器有哪些JOB
  5. Python21天打卡Day13-生成器表达式
  6. 参加软件测试工程师面试前,这些内容你一定要准备
  7. Pytest学习-如何在用例代码中调用fixtrue时传入参数
  8. mysql 主从的作用_MySQL主从复制作用和原理
  9. uni 加入图标_uniapp中引入 iconfont
  10. 基本排序方法实现:选择排序、插入排序、希尔排序