知乎是爬虫的一个经典案例,由于他常常改版,愈来愈难爬,可能我这个教程写完他就又改版了。git
知乎的难点github
1. 登陆,且url跳转web
2. 参数加密json
3. 验证码redux
本文将介绍模拟登陆知乎的详细过程。api
使用 fiddler 抓包浏览器
1. 获取登陆urlsession
输入帐号、密码等,登陆网站app
post 方式访问url,页面跳转,箭头所指是真实的 登陆url 编辑器
2. 获取登陆参数
能够看到 form data 加密了
处理方法
须要解决两个问题:提交了哪些参数;如何加密
1. 首先须要进入 source 面板,找寻相关 js 文件与加密函数;
2. 搜索与加密相关的英文,搜索方法见个人博客《浏览器抓包》,只要相关的函数名没有加密,就能搜到,这里搜索 encrypt;【encrypt:加密】
3. 在浏览器中格式化 js 代码,定位到加密函数,获取行号;【每每能够搜到不少个encrypt,浏览器中只匹配到第一个,因此要拷到编辑器中,搜索定位】
4. 在对应行号设置断点;【注意行号可能不彻底相同,在上下几行中找找对应函数】
5. 从新登陆,进行调试,抓取登陆参数;
加密函数
var b = function(e) { return __g._encrypt(encodeURIComponent(e)) };
e
"client_id=c3cef7c66a1843f8b3a9e6a1e3160e20&grant_type=password×tamp=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 形式,而后进行加密
先把参数意义搞清楚
client_id=c3cef7c66a1843f8b3a9e6a1e3160e2 客户端id 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=
多试几回,观察参数值是否固定;
经对比,不固定的是 时间戳、签名、验证码;
时间戳就是时间,算是已知的,剩下就要获得签名和验证码了
3. 获取签名
从上得知,签名也是通过加密的;
破解方法相似第2步;在 source 中搜索 signature;
定位行数,设置断点,调试;
signature 在这个函数中生成
function(e, t, n) { "use strict"; var r = n(745) , o = n.n(r) , i = n(183) , a = n.n(i); Object.assign; a()("zhihu-redux-middlewares:oauth"); var c = "c3cef7c66a1843f8b3a9e6a1e3160e20"; var u = Object.assign || function(e) { for (var t = 1; t < arguments.length; t++) { var n = arguments[t]; for (var r in n) Object.prototype.hasOwnProperty.call(n, r) && (e[r] = n[r]) } return e } ; t.a = function(e, t) { var n = Date.now() , r = new o.a("SHA-1","TEXT"); return r.setHMACKey("d1b964811afb40118a12068ff74a12f4", "TEXT"), r.update(e), r.update(c), r.update("com.zhihu.web"), r.update(String(n)), u({ clientId: c, grantType: e, timestamp: n, source: "com.zhihu.web", signature: r.getHMAC("HEX") ####### }, t) }
该函数传入 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
4. 获取登陆验证码
知乎验证码的特色
1. 登陆知乎不是每次都须要验证码
2. 知乎有两种验证码,一种是 “点击倒立的文字”,一种是 “英文字母”
验证码分析 - 操做过程
1. 访问知乎登陆页面,F12,而后刷新
能够看到,验证码url返回 false,即无需验证码
此时 的 request url 以下图
2. 屡次刷新登陆页面,观察 验证码 url 的 response,直至为 true
返回 true ,表明须要验证码
此时的 request url 以下图
能够看到 和不需验证码的url 相同,method 都是 get
咱们发现紧接着又有一个 验证码url,是什么呢?
这应该就是验证码图片, base64 编码的图片。
base64 编码的图片。可先存入本地,然后手动输入
看下headers
咱们发现 method 变成了 put,request url 仍是同样
也就是说,若是访问验证码url返回true, 会自动再次请求这个url,请求方式为 put, 返回 base64编码的图片
3. 输入帐号、密码,弹出验证码,输入验证码,点击登陆
首先是 post 了验证码数据,一样的url
post 参数以下图
key 是 input_text, value 为 图片大小和倒立文字的位置,这是倒立文字验证码
英文字母以下图
key 也是 input_text,value 为英文字母
倒立文字 和 英文字母 的url 不一样, 文字 cn,字母 en
也就是说,获得 base64 编码的图片后,要给该 url post 验证码,而后才能登陆
至此,咱们获得验证码,并 post,获取登陆的全部参数。
也能够尝试经过 搜索 登陆url 的 js 关键字,获取登陆参数。
import json import requests import time from hashlib import sha1 from time import sleep import hmac import base64 from PIL import Image class Zhihu(object): def __init__(self): self.session=requests.session() self.headers={ # 'authority':'www.zhihu.com', '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', } self.session.headers.update(self.headers) self.picture=None self.signature=None self.picture_url=None def getcapture(self): # 获取验证码方法,有时候不用获取验证码就能够直接登陆 # lang=en是英文字母 验证码 message=self.session.get(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en').json() # get 检测是否须要验证码 print(message) if message['show_captcha'] == False: self.picture='' else: self.picture_url = self.session.put(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en').json() # put 获取验证码 # 采用base64格式将验证码经过图片格式显示出来 with open('captcha.jpg','wb') as f: f.write(base64.b64decode(self.picture_url['img_base64'])) image=Image.open('captcha.jpg') image.show() self.picture=input('请输入验证码') sleep(2) message1=self.session.post(url='https://www.zhihu.com/api/v3/oauth/captcha?lang=en',data={'input_text':self.picture}).json() # post 验证码 print(message1) def get_signature(self): # 知乎登录的主要问题在于找到signature了这是重点。 a=hmac.new('d1b964811afb40118a12068ff74a12f4'.encode('utf-8'),digestmod=sha1) a.update('password'.encode('utf-8')) a.update(b'c3cef7c66a1843f8b3a9e6a1e3160e20') a.update(b'com.zhihu.web') a.update(str(int(time.time()*1000)).encode()) self.signature=a.hexdigest() def Login_phone(self): # 登陆 data={ 'client_id':'c3cef7c66a1843f8b3a9e6a1e3160e20',#'c3cef7c66a1843f8b3a9e6a1e3160e20', 'grant_type':'password', 'timestamp':str(int(time.time()*1000)), 'source':'com.zhihu.web', 'signature':self.signature, 'username':'xxxxxx@sina.com', 'password':'xxxxxxx', 'captcha':self.picture, 'lang':'en', # 'ref_source':'homepage', # 'utm_source':'' } headers = { # 'scheme':'https', # 'accept':'*/*', # 'accept-encoding':'gzip, deflate, br', # 'accept-language':'zh-CN,zh;q=0.8', # 'cache-control':'no-cache', # 'content-length':'412', # 'origin':'https://www.zhihu.com', 'content-type':'application/x-www-form-urlencoded', # 'referer':'https://www.zhihu.com/signin?next=%2F', 'x-zse-83':'3_2.0', } message=self.session.post(url='https://www.zhihu.com/api/v3/oauth/sign_in', headers=headers, data=data) message.encoding='utf-8' print(message.text) print(json.loads(message.text)['error']['message']) def target_url(self,url): text=self.session.get(url) return text.text if __name__ == "__main__": zhihu=Zhihu() zhihu.getcapture() # 验证码 zhihu.get_signature() # signature zhihu.Login_phone() # 登陆 # 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