爬虫实战(一)-新版知乎

墨蓝 2022-09-03 15:14 403阅读 0赞

知乎的难点:1. 登录,且url跳转 2. 参数加密 3. 验证码

抓包 – 分析登录过程

使用浏览器抓包

获取登录url

输入账号、密码等,登录网站
在这里插入图片描述
post 方式访问url,页面跳转,箭头所指是真实的 登录url

获取登录参数

在这里插入图片描述
可以看到 form data 加密了

处理方法
需要解决两个问题:提交了哪些参数;如何加密

  1. 首先需要进入 source 面板,找寻相关 js 文件与加密函数;
  2. 搜索与加密相关的英文,搜索方法见我的博客《浏览器抓包》,只要相关的函数名没有加密,就能搜到,这里搜索 encrypt;【encrypt:加密】
  3. 在浏览器中格式化 js 代码,定位到加密函数,获取行号;【往往可以搜到很多个encrypt,浏览器中只匹配到第一个,所以要拷到编辑器中,搜索定位】
  4. 在对应行号设置断点;【注意行号可能不完全相同,在上下几行中找找对应函数】
  5. 重新登录,进行调试,抓取登录参数;
    在这里插入图片描述
    加密函数

    var b = function(e) {

    1. return __g._encrypt(encodeURIComponent(e))
    2. };

“client_id=c3cef7c66a1843f8b3a9e6a1e3160e20&grant_type=password&timestamp=1559629752508&source=com.zhihu.web&signature=15317e3484b64449697b285a69a09af8ff23a1af&username=yanshuangwu258%40sina.com&password=6712007&captcha=&lang=en&ref_source=homepage&utm_source=”
加密函数 b 传入参数e,先进行 encodeURIComponent,根据经验应该是 编码成 key-value 形式,然后进行加密
先把参数意义搞清楚

  1. client_id=c3cef7c66a1843f8b3a9e6a1e3160e2 客户端id
  2. grant_type=password 授权类型
  3. timestamp=1559629752508 时间戳
  4. source=com.zhihu.web 源地址
  5. signature=15317e3484b64449697b285a69a09af8ff23a1af 签名
  6. username=yanshuangwu258%40sina.com 用户名
  7. password=6712007 密码
  8. captcha= 验证码
  9. lang=en 验证码类型
  10. ref_source=homepage
  11. utm_source=

多试几次,观察参数值是否固定;
经对比,不固定的是 时间戳、签名、验证码;
时间戳就是时间,算是已知的,剩下就要得到签名和验证码了

获取签名

从上得知,签名也是经过加密的;
破解方法类似第2步;在 source 中搜索 signature;
定位行数,设置断点,调试;
在这里插入图片描述
signature 在这个函数中生成

  1. function(e, t, n) {
  2. "use strict";
  3. var r = n(745)
  4. , o = n.n(r)
  5. , i = n(183)
  6. , a = n.n(i);
  7. Object.assign;
  8. a()("zhihu-redux-middlewares:oauth");
  9. var c = "c3cef7c66a1843f8b3a9e6a1e3160e20";
  10. var u = Object.assign || function(e) {
  11. for (var t = 1; t < arguments.length; t++) {
  12. var n = arguments[t];
  13. for (var r in n)
  14. Object.prototype.hasOwnProperty.call(n, r) && (e[r] = n[r])
  15. }
  16. return e
  17. }
  18. ;
  19. t.a = function(e, t) {
  20. var n = Date.now()
  21. , r = new o.a("SHA-1","TEXT");
  22. return r.setHMACKey("d1b964811afb40118a12068ff74a12f4", "TEXT"),
  23. r.update(e),
  24. r.update(c),
  25. r.update("com.zhihu.web"),
  26. r.update(String(n)),
  27. u({
  28. clientId: c,
  29. grantType: e,
  30. timestamp: n,
  31. source: "com.zhihu.web",
  32. signature: r.getHMAC("HEX")      #######
  33. }, t)
  34. }

该函数传入 e、t和一些全局变量,e是字符串‘password’,t 见截图,n是时间戳,c 见代码,
这个函数显示了 signature 的加密过程;【此处需要学习常规加密方法】
此处通过 秘钥d1b964811afb40118a12068ff74a12f4 和 SHA-1密码散列函数,进行加密,r.update 又添加了 e、c、‘com.zhihu.web’、string(n),
由截图和代码可知,e代表‘password’, c为”c3cef7c66a1843f8b3a9e6a1e3160e20”,n为时间戳,由此可算出 signature

获取登录验证码

知乎验证码的特点

  1. 登录知乎不是每次都需要验证码
  2. 知乎有两种验证码,一种是 “点击倒立的文字”,一种是 “英文字母”
    验证码分析 - 操作过程
  3. 访问知乎登录页面,F12,然后刷新
    在这里插入图片描述
    可以看到,验证码url返回 false,即无需验证码
    此时 的 request url 如下图
    在这里插入图片描述
  4. 多次刷新登录页面,观察 验证码 url 的 response,直至为 true
    在这里插入图片描述
    返回 true ,代表需要验证码
    此时的 request url 如下图
    在这里插入图片描述
    可以看到 和不需验证码的url 相同,method 都是 get
    我们发现紧接着又有一个 验证码url,是什么呢?
    在这里插入图片描述
    这应该就是验证码图片, base64 编码的图片。
    base64 编码的图片。可先存入本地,而后手动输入
    看下headers
    在这里插入图片描述
    我们发现 method 变成了 put,request url 还是一样
    也就是说,如果访问验证码url返回true, 会自动再次请求这个url,请求方式为 put, 返回 base64编码的图片
  5. 输入账号、密码,弹出验证码,输入验证码,点击登录
    在这里插入图片描述
    首先是 post 了验证码数据,同样的url
    post 参数如下图
    在这里插入图片描述
    key 是 input_text, value 为 图片大小和倒立文字的位置,这是倒立文字验证码
    英文字母如下图
    在这里插入图片描述
    key 也是 input_text,value 为英文字母
    倒立文字 和 英文字母 的url 不同, 文字 cn,字母 en
    也就是说,得到 base64 编码的图片后,要给该 url post 验证码,然后才能登录
    至此,我们得到验证码,并 post,获取登录的所有参数。
    也可以尝试通过 搜索 登录url 的 js 关键字,获取登录参数。
    在这里插入图片描述

代码实现登陆

  1. import json
  2. import requests
  3. import time
  4. from hashlib import sha1
  5. from time import sleep
  6. import hmac
  7. import base64
  8. from PIL import Image
  9. class Zhihu(object):
  10. def __init__(self):
  11. self.session=requests.session()
  12. self.headers={
  13. # 'authority':'www.zhihu.com',
  14. 'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0',
  15. }
  16. self.session.headers.update(self.headers)
  17. self.picture=None
  18. self.signature=None
  19. self.picture_url=None
  20. def getcapture(self):
  21. # 获取验证码方法,有时候不用获取验证码就可以直接登录
  22. # lang=en是英文字母 验证码
  23. message=self.session.get(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en').json() # get 检测是否需要验证码
  24. print(message)
  25. if message['show_captcha'] == False:
  26. self.picture=''
  27. else:
  28. self.picture_url = self.session.put(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en').json() # put 获取验证码
  29. # 采用base64格式将验证码通过图片格式显示出来
  30. with open('captcha.jpg','wb') as f:
  31. f.write(base64.b64decode(self.picture_url['img_base64']))
  32. image=Image.open('captcha.jpg')
  33. image.show()
  34. self.picture=input('请输入验证码')
  35. sleep(2)
  36. message1=self.session.post(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en',data={ 'input_text':self.picture}).json() # post 验证码
  37. print(message1)
  38. def get_signature(self):
  39. # 知乎登陆的主要问题在于找到signature了这是重点。
  40. a=hmac.new('d1b964811afb40118a12068ff74a12f4'.encode('utf-8'),digestmod=sha1)
  41. a.update('password'.encode('utf-8'))
  42. a.update(b'c3cef7c66a1843f8b3a9e6a1e3160e20')
  43. a.update(b'com.zhihu.web')
  44. a.update(str(int(time.time()*1000)).encode())
  45. self.signature=a.hexdigest()
  46. def Login_phone(self):
  47. # 登录
  48. data={
  49. 'client_id':'c3cef7c66a1843f8b3a9e6a1e3160e20',#'c3cef7c66a1843f8b3a9e6a1e3160e20',
  50. 'grant_type':'password',
  51. 'timestamp':str(int(time.time()*1000)),
  52. 'source':'com.zhihu.web',
  53. 'signature':self.signature,
  54. 'username':'xxxxxx@sina.com',
  55. 'password':'xxxxxxx',
  56. 'captcha':self.picture,
  57. 'lang':'en',
  58. # 'ref_source':'homepage',
  59. # 'utm_source':''
  60. }
  61. headers = {
  62. # 'scheme':'https',
  63. # 'accept':'*/*',
  64. # 'accept-encoding':'gzip, deflate, br',
  65. # 'accept-language':'zh-CN,zh;q=0.8',
  66. # 'cache-control':'no-cache',
  67. # 'content-length':'412',
  68. # 'origin':'https://www.zhihu.com',
  69. 'content-type':'application/x-www-form-urlencoded',
  70. # 'referer':'https://www.zhihu.com/signin?next=%2F',
  71. 'x-zse-83':'3_2.0',
  72. }
  73. message=self.session.post(url='https://www.zhihu.com/api/v3/oauth/sign_in', headers=headers, data=data)
  74. message.encoding='utf-8'
  75. print(message.text)
  76. print(json.loads(message.text)['error']['message'])
  77. def target_url(self,url):
  78. text=self.session.get(url)
  79. return text.text
  80. if __name__ == "__main__":
  81. zhihu=Zhihu()
  82. zhihu.getcapture() # 验证码
  83. zhihu.get_signature() # signature
  84. zhihu.Login_phone() # 登录
  85. # print(zhihu.target_url('https://www.zhihu.com/'))

参考资料:

https://blog.csdn.net/jiyukun1/article/details/82256222

https://blog.csdn.net/y15518325965/article/details/79406247

https://blog.csdn.net/sergiojune/article/details/87873787

https://blog.csdn.net/lvanboy/article/details/88044576

https://www.chainnews.com/articles/068650003844.htm  代码 错误 解析

https://github.com/zkqiang/Zhihu-Login

发表评论

表情:
评论列表 (有 0 条评论,403人围观)

还没有评论,来说两句吧...

相关阅读