写在前面
参考文献来自csdn梦想橡皮擦,本次尝试的是网易有道词典的接口,这类教程网上有很多,但大多过时了,也不敢确定本文的有效性能保持多久,所以记录代码的同时,一并记录下方法。有道的反爬原理是生成本地随机变量进行验证,如果不能摸清随机变量的生成规则,就只能收到{'errorcode':'50'},另外,有道对请求头也有一定要求。
用到的包
#发起网页请求
import requests
#对字符进行md5加密
import hashlib
#获取时间戳
import time
#生成随机数
import random
获取随机变量
#translate为要翻译的内容
def generate_salt_sign(translate):
#在浏览器控制台(F12-Console)中输入"navigator.appVersion"
app_version = "5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36"
#对上面获取到的内容进行md5加密
bv = hashlib.md5(app_version.encode(encoding='utf-8')).hexdigest()
#获取当前时间戳,乘以1000,然后取整
lts = str(int(1000 * time.time()))
#lts加上0-10的一个随机字符
salt = lts + str(random.randint(0,10))
#sign为一个常量+要翻译的内容+salt+一个常量,然后进行md5加密
sign = hashlib.md5(("fanyideskweb" + translate + salt + "]BjuETDhU)zqSxf-=B#7m").encode(encoding='utf-8')).hexdigest()
return salt,sign,lts,bv
请求参数
def params():
#空字典(Form Data)
data = {}
#要翻译的内容
translate = 'hello'
data['i'] = translate
#默认值
data['from'] = 'AUTO'
data['to'] = 'AUTO'
data['smartresult'] = 'dict'
#"fanyideskweb"即为上面的第一个常量
data['client'] = 'fanyideskweb'
#获取变量并存入字典
data['salt'],data['sign'],data['lts'],data['bv'] = generate_salt_sign(translate)
#以下皆为默认值
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['action'] = 'FY_BY_REALTlME'
data['typoResult'] = 'false'
#时间戳的整数类型,用于构造Cookie
temp = int(data['lts'])
return data,temp
主要函数
def tran():
#有道的接口url地址
url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
#获取参数字典
data,temp = params()
#构造请求头,Cookie末尾的字符串为当前时间戳减5
headers = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Connection': 'keep-alive',
'Content-Length': str(len(data)),
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Cookie': 'OUTFOX_SEARCH_USER_ID=-263132750@10.108.160.101; JSESSIONID=aaaN1fFGaN7vmh3Msh_xx; OUTFOX_SEARCH_USER_ID_NCOO=914767987.7880249; ___rl__test__cookies={}'.format(temp - 5),
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
#发起post请求
result = requests.post(url = url,headers = headers,data = data)
#输出获取的内容,可以使用json模块将其格式化
print(result.text)
查找对应参数
本站对于图片的支持不是很好,我在这里简单口述一下方法,首先打开有道,F12打开开发者工具,选择Network-All,然后输入一些内容进行翻译,Network会自动刷新,选择Name
translate_o?smartresult=dict&smartresult=rule
点击Preview,即可看到翻译的内容,点击Headers,往下翻,即可看到Request Headers和Form Data,这就是我们发起post请求时传递的内容,有一部分是定值,主要变化的是salt、sign、lts这三项。接下来找到上述文件的Initiator属性,鼠标悬停,选择t.translate,点进去,再点点击左下角的{}对文本格式化,可以看到函数变得有规律了,这里记录着Form Data里的内容,可有几项仍然隐藏着,按CTRL+F打开搜索,查询var r = function,应该会匹配到两项,其中一个就记录着salt,sign,lts以及bv的生成规则(要注意sign的最后一个参数,如果跟本文不一样则进行替换),这是一个JavaScript函数,解析后可以发现正是上面generate_salt_sign函数的内容,使用python复现规则也不难。
代码的优化
实际上并不需要完全传递headers和data,删减尝试后对代码进行简化:
import requests
import hashlib
import time
import random
def generate_salt_sign(translate):
lts = str(int(1000 * time.time()))
salt = lts + str(random.randint(0,10))
sign = hashlib.md5(("fanyideskweb" + translate + salt + "]BjuETDhU)zqSxf-=B#7m").encode(encoding='utf-8')).hexdigest()
return salt,sign
def params():
data = {}
translate = input('请输入要翻译的内容:')
data['i'] = translate
data['client'] = 'fanyideskweb'
data['salt'],data['sign'] = generate_salt_sign(translate)
data['keyfrom'] = 'fanyi.web'
return data
def tran():
url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule"
data = params()
headers = {
'Cookie': 'OUTFOX_SEARCH_USER_ID=-263132750@10.108.160.101;',
'Referer': 'http://fanyi.youdao.com/',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
}
result = requests.post(url = url,headers = headers,data = data)
print(result.text)
if __name__ == '__main__':
tran()
其他问题
如果把接口url里面的"_o"去掉,则很容易就能获得返回的内容,但翻译的效果似乎会差一些。