通过python 来抓取有道翻译的内容
第一步:
先打开有道翻译的网页:http://fanyi.youdao.com/
第二步:
通过按F12,进入调试模式,找到Network→XHR,就可以找到请求翻译的接口,如下图:
image.png第三步:
点开Name底下的链接,如果Name底下为空的话,证明你没有请求翻译,在网页上请求一下翻译就出来了,点开就可以看见请求的链接,请求方式,请求头,以及请求的参数,如下图:
image.png image.png如上,这些信息都是我们python请求需要用到的,有了这些信息,就可以编写我们的python代码了。
第四步:
编写相应的python代码。
首先,可以看到请求方式是post请求,那么我们就先写post请求方法:
import requests
def post(url,header=None,data=None):
if header is None:
header = {
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
}
result = requests.post(url,header,data)
return result.text
然后,通过我们得到的请求的url,请求的参数,请求的头部,就可以编写我们的请求的方法:
def getTranslate(data):
salt = get_salt()
jsonStr = post(
url='<http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule>',
headers = {
'Cookie': 'OUTFOX_SEARCH_USER_ID=1389460813@123.125.1.12',
'Referer': '<http://fanyi.youdao.com/>',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OSX10_14_2) AppleWebKit/537.36(KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
},data=json.dumps({
'i':data,
'from':'zh-CHS',
'to':'en',
'smartresult':'dict',
'client':'fanyideskweb',
'salt':'15901129623685',
'sign':'7ebd4fe242ddf38339c8cc2ef09875bb',
'ts':'1590110946423',
'bv':'8abdac95d8a218e4fd5735f7cd2ab169',
'doctype':'json',
'version':'2.1',
'keyfrom':'fanyi.web',
'action':'FY_BY_REALTlME'
},ensure_ascii=False))
print(jsonStr)
调用方法后,会看到返回的是{"errorCode":50}
证明我们请求的接口没有成功,参数和请求头都没问题,那么我们翻翻反爬虫手册:https://www.jianshu.com/p/ea6f47ad2042
从而判断出,是有道翻译接口通过加密方式阻止了访问,导致访问失败。分析Form Data,发现salt,sign,ts这三个参数是动态变化的,那问题就出在这三个参数身上,通过请求网页发现,每次都调用了fanyi.min.js这个js,很有可能就是通过js加密方式。我们找到这个js,吧里面的内容复制出来,通过js解析网站:https://tool.oschina.net/codeformat/js
找到了js的关键代码:
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 + "Nw(nmmbP%A-r6U3EUn]Aj")
}
};
t.recordUpdate = function(e) {
var t = e.i,
i = r(t);
n.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
url: "/bettertranslation",
data: {
i: e.i,
client: "fanyideskweb",
salt: i.salt,
sign: i.sign,
ts: i.ts,
bv: [i.bv](<http://i.bv/>),
tgt: e.tgt,
modifiedTgt: e.modifiedTgt,
from: e.from,
to: [e.to](<http://e.to/>)
},
success: function(e) {},
error: function(e) {}
})
}
可以看出关键代码:
r = "" + (new Date).getTime(),
i = r + parseInt(10 * Math.random(), 10);
ts: r,
salt: i,
sign: n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")
那我们通过编写python相关方法去替换着三个值就行了,方法如下:
def get_salt():
import time, random
salt = int(time.time() * 1000) + random.randint(0, 10)
return salt
def get_md5(v):
import hashlib
md5 = hashlib.md5() # md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来
md5.update(v.encode('utf-8')) # 要对哪个字符串进行加密,就放这里
value = md5.hexdigest() # 拿到加密字符串
return value
def get_sign(key, salt):
sign = 'fanyideskweb' + key + str(salt) + 'n%A-rKaT5fb[Gy?;N5@Tj'
sign = get_md5(sign)
return sign
def get_ts(self):
# 根据当前时间戳获取ts参数
s = int(time.time() * 1000)
return str(s)
然后就可以编写完整的程序了:
import requests
import json
import hashlib
import random
import time
def get(url,header=None,data=None):
if header is None:
header = {
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
}
result = requests.get(url,header,data)
return result.text
def post(url,header=None,data=None):
if header is None:
header = {
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"
}
result = requests.post(url,header,data)
return result.text
def get_salt():
import time, random
salt = int(time.time() * 1000) + random.randint(0, 10)
return salt
def get_md5(v):
import hashlib
md5 = hashlib.md5() # md5对象,md5不能反解,但是加密是固定的,就是关系是一一对应,所以有缺陷,可以被对撞出来
md5.update(v.encode('utf-8')) # 要对哪个字符串进行加密,就放这里
value = md5.hexdigest() # 拿到加密字符串
return value
def get_sign(key, salt):
sign = 'fanyideskweb' + key + str(salt) + 'n%A-rKaT5fb[Gy?;N5@Tj'
sign = get_md5(sign)
return sign
def get_ts(self):
# 根据当前时间戳获取ts参数
s = int(time.time() * 1000)
return str(s)
from urllib import request,parse
def youdao(key):
# 请求地址
url = '<http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule>'
salt = get_salt()
# 请求体
data = {
"i": key,
"from": "AUTO",
"to": "AUTO",
"smartresult": "dict",
"client": "fanyideskweb",
"salt": str(salt), ### 很长的随机串,防止用字典反推
"sign": get_sign(key, salt), ## 签名:js加密
"doctype": "json",
"version": "2.1",
"keyfrom": "fanyi.web",
"action": "FY_BY_REALTIME",
"typoResult": "false"
}
# 数据编码
data = parse.urlencode(data).encode()
headers = {
'Cookie': 'OUTFOX_SEARCH_USER_ID=1389460813@123.125.1.12',
'Referer': '<http://fanyi.youdao.com/>',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OSX10_14_2) AppleWebKit/537.36(KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
req = request.Request(url=url, data=data, headers=headers)
rsp = request.urlopen(req)
html = rsp.read().decode()
print(html)
if __name__ == '__main__':
youdao('你好')
运行结果如下图:
image.png
网友评论