在百度查询单词时,发现百度可以显示这个单词在近些年考了多少次,例如
喜欢瞎鼓捣的我就想着自己用python来实现直接获取考频分布,这样在背一些单词时也能着重记忆。想着先上网找一找,嘿,网上居然没有人这么干过还,只找到有人在解决sign算法,这个后面再说,所以只能自己尝试。
老规矩,打开F12,不难发现是这项在请求
看载荷可以发现是通过网址向后端发送数据,数据分别是“word”、“tag”、“sign”和“callback”,
word和tag一眼就能看出是什么内容,重点实在“sign”和“callback”,熟悉时间戳的话也不难发现callback的内容部分其实是时间戳,和当前时间戳对比的话就会发现猜想是没错的,是时间戳整数加小数点后三位,那么“_”之后的内容又是什么?sign的内容又是什么?
首先继续看callback部分,通过全局搜索jsonp_,发现
在js文件中找到这一部分
通过结构来看,我们找对了,就是这一段生成了callback,这段代码保存下来
再来看sign,这个是最难的部分,通过相似的方法可以找到他在js中是这样的
这个破解就带着很大的运气成分了,首先是我到观察sign的表达式最大为f,且刷新不会改变sign值,其他单词的sign同样如此,并且还都是32位的,第一反应是16位进制,尝试转换为二进制后,发现并无规律,也尝试使用了含有两个相同字母以上的单词进行测试,也没有发现规律。又想到了md5加密,将单词加密后仍然与sign值不相同。“干瞪眼”方法行不通,再返回到我们前面找到的js代码部分,这里我在网上找了很久,但是只找到了反向破解百度翻译sign值的方法,网上其他文中介绍破解sign时也涉及到了js某个函数,但是与这里的完全不同,百度翻译生成sign时会将单词传入函数,再生成sign,但是考频分布这里的sign中d()函数并没有传入任何的数据,在这里卡了很久很久,最终决定尝试通过后半部分来进行入手,还是先观察,this.examTags.wordProto,这个变量从名字来看的意思应该是当前这个tag(即考研还是六级还是四级等)下的单词是什么,再在后面加上“_321188626”,但是与我们前面所获得的32位字符串仍然不同,此时就靠运气,我尝试生成end_321188626的md5加密值,结果和前文的32字符串完全相同!
至此,四个数据及生成方法全部拿到,废话不多说,直接上python代码
import requests
import js2py
import hashlib
import json
import os
def chaxun(word):
#word = str(input())
#word='reliance'
import time
js='Math.ceil(1e5 * Math.random())'
r = js2py.eval_js(js)
time=str(time.time())
callback='jsonp_' + time[0:10] + time[11:-4] + '_' +str(r)
tag = '考研'
sign = word + '_321188626'
sign = hashlib.md5(sign.encode(encoding='utf-8'))
sign = sign.hexdigest()
url = 'https://edu.baidu.com/fanyi/examtags?word=' + word +'&tag=考研&sign='+sign +'&callback=' + callback
res = requests.get(url).text
#res= 'jsonp_1679493198005_43684({"code":0,"data":{"tag":"六级","kernel_level":"","word_level":"","recent_years":"5","recent_years_zh":"五","appear_count":"5","importance":"1","definition":[{"text":"v/n. 费心做; 努力 ","partname":"v/n.","percentage":"60%"},{"text":"v/n. 打扰; 使烦心; 麻烦","partname":"v/n.","percentage":"40%"}]}})'
#print(res.text['recent_years_zh'])
#print(res)
try:
json1 = json.loads(res[26:-1])
except json.decoder.JSONDecodeError:
json1 = json.loads(res[25:-1])
#print(json1)
try:
if str(json1['msg'])== '数据不存在':
print('输入的单词可能有误或考研未涉及')
except KeyError:
print('近'+json1['data']['recent_years_zh']+'年出现'+json1['data']['appear_count'] + '次')
print('重要性:'+str(int(json1['data']['importance'])*'☆'))
i=0
for data in json1['data']['definition']:
print(str(json1['data']['definition'][i]['text']) + ' ' +str(json1['data']['definition'][i]['percentage']))
i=i+1
print('\n')
def main():
print('如果要停止,请输入 endend')
while True:
print('输入要查询的单词:')
word=input()
print()
if word =='endend':
break
else:
chaxun(word)
main()
os.system("pause")
Python运行后提示
如果要停止,请输入 endend
输入要查询的单词:
Python输入end
近六年出现17次
重要性:☆☆☆
n. 结尾; 最后部分 26%
n/v. 结束; 了结 26%
vphr. (make ends meet)收支相抵 21%
vphr. (end up)最终成为 15%
n. 目的 12%
输入要查询的单词:
Python我也已经把代码打包好了,如果不想再安装库或者调试,可以用这个获取考频.zip