有道翻译的网址:http://fanyi.youdao.com/
因为有道翻译在不断的做反爬,我今天可以这样做,或许明天就不可以了,所以大家了解思路就可以了,对以后出来的东西有一个解决的思路就可以了!很多时候我们在做爬虫的时候,要自己去摸索规则。
1.打开有道翻译的网址
输入j,此时的http请求的方法是post
F12 打开 Network
要提交的数据是 Form Data里面的内容
要提交的url是
2.写一个简单的爬虫
"""
有道翻译
"""
import requests
url = \'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule\'
data_dic = {
\'i\': \'j\',
\'from\': \'AUTO\',
\'to\': \'AUTO\',
\'smartresult\': \'dict\',
\'client\': \'fanyideskweb\',
\'salt\': \'15562424251945\',
\'sign\': \'8a649f0ce7088b3f64b3ef6c4a63732c\',
\'ts\': \'1556242425194\',
\'bv\': \'5933be86204903bb334bf023bf3eb5ed\',
\'doctype\': \'json\',
\'version\': \'2.1\',
\'keyfrom\': \'fanyi.web\',
\'action\': \'FY_BY_REALTlME\',
}
response=requests.post(url=url,data=data_dic)
print(response.text)
3.此时服务器会返回一个错误
{"errorCode":50}
说明肯定有什么地方不一样,
有时候光有data解决不了问题,需要加一下headers
接下来,我们开始观察一下请求的头部
4.分别输入 j jo job 来比较一下请求的头部有什么变化
通过观察可以找到规律,content-length=233+要翻译单词的长度
5.修正代码
import requests
keyword=input(\'请输入要翻译的单词:\')
url = \'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule\'
headers = {
\'Accept\': \'application/json, text/javascript, */*; q=0.01\',
\'Accept-Language\': \'zh-CN,zh;q=0.9\',
\'Connection\': \'keep-alive\',
\'Content-Length\': str(233+len(keyword)),
\'Content-Type\': \'application/x-www-form-urlencoded; charset=UTF-8\',
\'Cookie\': \'[email protected]; JSESSIONID=aaaT594x_2P98-gLurxPw; OUTFOX_SEARCH_USER_ID_NCOO=661300740.1028955; ___rl__test__cookies=1556242425186\',
\'Host\': \'fanyi.youdao.com\',
\'Origin\': \'http://fanyi.youdao.com\',
\'Referer\': \'http://fanyi.youdao.com/\',
\'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\',
\'X-Requested-With\': \'XMLHttpRequest\',
}
data_dic = {
\'i\': keyword,
\'from\': \'AUTO\',
\'to\': \'AUTO\',
\'smartresult\': \'dict\',
\'client\': \'fanyideskweb\',
\'salt\': \'15562424251945\',
\'sign\': \'8a649f0ce7088b3f64b3ef6c4a63732c\',
\'ts\': \'1556242425194\',
\'bv\': \'5933be86204903bb334bf023bf3eb5ed\',
\'doctype\': \'json\',
\'version\': \'2.1\',
\'keyfrom\': \'fanyi.web\',
\'action\': \'FY_BY_REALTlME\',
}
response = requests.post(url=url, data=data_dic,headers=headers)
print(response.text)
手动输入要翻译的单词之后,发现只有之前写好的那个单词可以翻译,其他的还是会报50的错误
{"errorCode":50}
分析一下,此时只有输入的内容有所不同,所以是Form Data 那里有问题
6.分别输入 j jo job 看看Form Data 的变化
很明显的可以看出来,salt sign ts 这三个变量的值发生了变化
salt ts 的格式很像时间戳
时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。通俗的讲, 时间戳是一份能够表示一份数据在一个特定时间点已经存在的完整的可验证的数据。 它的提出主要是为用户提供一份电子证据, 以证明用户的某些数据的产生时间。
import time
time.time()
print(time.time()) # 1556244346.4114347
t=(time.time()*1000)
print(t) # 1556244491948
时间戳是随着前端自动在变的,能实现这个功能的就是js文件
所以我们要找到js文件,拷贝到我们的pycharm中
7.查找前端的js文件
找前端的js文件需要一段很长的时间,在每个js文件中查找有没有那几个变量(salt,ts,sign)
经过查找我发现在文件fanyi.min.js
在线代码格式化
把代码复制到 fanyi.js,
查找salt : ctrl+F salt
把重点的代码复制出来,重点分析一下
function(e, t) {
var n = e("./jquery-1.7");
e("./utils");
e("./md5");
var r = function(e) {
var t = n.md5(navigator.appVersion),
r = "" + (new Date).getTime(),
i = r + parseInt(10 * Math.random(), 10);
return {
ts: r,
bv: t,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "@6f#X3=cCuncYssPsuRUE")
}
};
(1)ts的值为 r : 获取到当前的时间戳,并把它转换为字符串
import time
r=str(time.time()*1000)
(2)bv的值为 t : t是把navigator.appVersion进行md5加密
由于我们不知道navigator.appVersion是啥,在前端的console输出一下
此时你有没有觉得这个结果有点眼熟,没错,就是之前咱们Request Headers 里面的User-Agent
因为每次提交数据都在同一个浏览器中,所以这个变量不会有变化
(3)salt的值为 i : 把字符串 r 和从1 到10里面的随机数拼接产生的字符串
字符串+整型数字=直接拼接成字符串
eg: \'abcd\'+2=\'abcd2\'
import time
import random
r=str(time.time()*1000)
i=r+str(random.random()*10)
# 从1到10产生一个随机数
# random.randint(1,11)
# random.random()*10
(4)sign的值为对后面的字符串进行md5加密
sign: n.md5("fanyideskweb" + e + i + "@6f#X3=cCuncYssPsuRUE")
这当中的e为输入的内容
import hashlib
keyword=input("请输入要翻译的内容:")
pre_md5="fanyideskweb" + keyword + i + "@6f#X3=cCuncYssPsuRUE"
md5=hashlib.md5()
md5.update(bytes(pre_md5,encoding=\'utf-8\'))
md5_str=md5.hexdigest()
8.改进代码
"""
有道翻译
"""
import requests
keyword=input(\'请输入要翻译的单词:\')
url = \'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule\'
"""----------------------------------------------------------"""
import time
r = str(int(time.time() * 1000))
import random
# random.randint(1, 11)
# int(random.random() * 10)
i = r + str(int(random.random() * 10))
pre_md5 = \'fanyideskweb\' + keyword + i + \'@6f#X3=cCuncYssPsuRUE\'
# print(pre_md5)
# 生成md5字符串
import hashlib
md5 = hashlib.md5()
md5.update(bytes(pre_md5, encoding=\'utf-8\'))
md5_str = md5.hexdigest()
# print(md5_str)
"""----------------------------------------------------------"""
headers = {
\'Accept\': \'application/json, text/javascript, */*; q=0.01\',
\'Accept-Language\': \'zh-CN,zh;q=0.9\',
\'Connection\': \'keep-alive\',
\'Content-Length\': str(233+len(keyword)),
\'Content-Type\': \'application/x-www-form-urlencoded; charset=UTF-8\',
\'Cookie\': \'[email protected]; JSESSIONID=aaaT594x_2P98-gLurxPw; OUTFOX_SEARCH_USER_ID_NCOO=661300740.1028955; ___rl__test__cookies=1556242425186\',
\'Host\': \'fanyi.youdao.com\',
\'Origin\': \'http://fanyi.youdao.com\',
\'Referer\': \'http://fanyi.youdao.com/\',
\'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\',
\'X-Requested-With\': \'XMLHttpRequest\',
}
data_dic = {
\'i\': keyword,
\'from\': \'AUTO\',
\'to\': \'AUTO\',
\'smartresult\': \'dict\',
\'client\': \'fanyideskweb\',
\'salt\': i,
\'sign\': md5_str,
\'ts\': r,
\'bv\': \'5933be86204903bb334bf023bf3eb5ed\',
\'doctype\': \'json\',
\'version\': \'2.1\',
\'keyfrom\': \'fanyi.web\',
\'action\': \'FY_BY_REALTlME\',
}
response = requests.post(url=url, data=data_dic,headers=headers)
print(response.text)
执行结果
9.代码优化
"""
有道翻译
代码规则:PEP8规则
遵循PEP8规范,有良好的编码习惯
"""
import requests
import time
import random
# 生成md5字符串
def getMd5(value):
import hashlib
md5 = hashlib.md5()
md5.update(bytes(value, encoding=\'utf-8\'))
md5_str = md5.hexdigest()
return md5_str
if __name__ == \'__main__\':
# 输入单词
keyword = input(\'请输入要翻译的单词:\')
# 接口地址
url = \'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule\'
# 生成ts
r = str(int(time.time() * 1000))
# 生成salt
i = r + str(int(random.random() * 10))
# 生成sign
pre_md5 = \'fanyideskweb\' + keyword + i + \'@6f#X3=cCuncYssPsuRUE\'
md5_str = getMd5(pre_md5)
# 生成请求表头数据
headers = {
\'Accept\': \'application/json, text/javascript, */*; q=0.01\',
\'Accept-Language\': \'zh-CN,zh;q=0.9\',
\'Connection\': \'keep-alive\',
\'Content-Length\': str(233 + len(keyword)),
\'Content-Type\': \'application/x-www-form-urlencoded; charset=UTF-8\',
\'Cookie\': \'[email protected]; JSESSIONID=aaaT594x_2P98-gLurxPw; OUTFOX_SEARCH_USER_ID_NCOO=661300740.1028955; ___rl__test__cookies=1556242425186\',
\'Host\': \'fanyi.youdao.com\',
\'Origin\': \'http://fanyi.youdao.com\',
\'Referer\': \'http://fanyi.youdao.com/\',
\'User-Agent\': \'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36\',
\'X-Requested-With\': \'XMLHttpRequest\',
}
# 生成表单数据
data_dic = {
\'i\': keyword,
\'from\': \'AUTO\',
\'to\': \'AUTO\',
\'smartresult\': \'dict\',
\'client\': \'fanyideskweb\',
\'salt\': i,
\'sign\': md5_str,
\'ts\': r,
\'bv\': \'5933be86204903bb334bf023bf3eb5ed\',
\'doctype\': \'json\',
\'version\': \'2.1\',
\'keyfrom\': \'fanyi.web\',
\'action\': \'FY_BY_REALTlME\',
}
# 发起网络请求
response = requests.post(url=url, data=data_dic, headers=headers)
print(response.text)