一. 破解參數(shù)加密
有道翻譯的請(qǐng)求是post,攜帶一系列參數(shù),直接F12刷新進(jìn)行調(diào)試,如下圖所示:
這是一個(gè) post 請(qǐng)求,目標(biāo)網(wǎng)址是
'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
接下來(lái)讓我們看看發(fā)送該請(qǐng)求需要攜帶哪些參數(shù)
如圖所示,紅色方框里的就是需要攜帶的參數(shù)了。
最后看一看返回的數(shù)據(jù)
顯而易見(jiàn),返回的數(shù)據(jù)是json格式的數(shù)據(jù)。
好了,現(xiàn)在我們可以寫程序進(jìn)行爬取了
# -*-coding:utf-8-*-
__Author__ = "Mr.D"
__Date__ = '2019\5\26 0026 16:50'
from faker import Faker
import requests
ua = Faker().user_agent()
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
key = input("請(qǐng)輸入你需要翻譯的內(nèi)容: ")
# 請(qǐng)求頭
headers = {
'User-Agent': ua,
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
}
# post請(qǐng)求攜帶的參數(shù)
from_data = {
'i': key,
'from': 'UTO',
'to': 'UTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': 15588802331547,
'sign': 3e91f2d8788201c03bfa0a672b116998,
'ts': 1558880233154,
'bv': '5504a5c7c19867a06038cf79d29f756a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
response = requests.post(url, headers=headers, data=from_data).json()
print(response)
print(response['translateResult'][0][0]['tgt'])
運(yùn)行后發(fā)現(xiàn)報(bào)錯(cuò)了,"{errorCode: 50}"
什么原因呢? 讓我們分析一下。
可以自己 重新來(lái)翻譯一下? "問(wèn)題" 這個(gè)詞,然后在看一次此次 post 請(qǐng)求與上一次 post 請(qǐng)求有什么不同之處。
經(jīng)過(guò)調(diào)試,我發(fā)現(xiàn) from_data 中的參數(shù)有幾個(gè)是發(fā)生了變化的,分別是 "salt","sign","ts",那么這幾個(gè)參數(shù)是怎么生存的呢?
經(jīng)過(guò)尋找,發(fā)現(xiàn)它們的生存規(guī)律在 "http://shared.ydstatic.com/fanyi/newweb/v1.0.17/scripts/newweb/fanyi.min.js" 這個(gè)? js 文件中,經(jīng)過(guò) json 格式化工具(百度)格式化之后,定位到具體的參數(shù)生成位置,
// e 為下面 r(t) 中的 t ,即我們所需要翻譯的內(nèi)容
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 + "n%A-rKaT5fb[Gy?;N5@Tj")
}
};
t.recordUpdate = function(e) {
// 將我們所要翻譯的內(nèi)容賦值給 t
var t = e.i,
// 將 t 當(dāng)作參數(shù)傳入 r() 函數(shù)中,返回值賦給 i
i = r(t);
n.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
url: "/bettertranslation",
// 這里可以看出 data 就是我們post請(qǐng)求攜帶的參數(shù)字典
data: {
// e.i 就是我們所要翻譯的內(nèi)容
i: e.i,
client: "fanyideskweb",
salt: i.salt,
sign: i.sign,
ts: i.ts,
bv: i.bv,
tgt: e.tgt,
modifiedTgt: e.modifiedTgt,
from: e.from,
to: e.to
},
success: function(e) {},
error: function(e) {}
})
}
從上述代碼中,我們可以得出四個(gè)參數(shù)的信息: ts,bv,salt,sign,他們分別為
ts: "" + (new Date).getTime(),
bv: n.md5(navigator.appVersion),
salt: ts + parseInt(10 * Math.random(), 10),
// e為所需要翻譯的字符串, i 即salt
sign: n.md5("fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj")
分析一波:
bv 是對(duì)? navigator.appVersion(這是個(gè)瀏覽器參數(shù),不是字符串"navigator.appVersion")進(jìn)行 md5 加密,在相同的瀏覽器下,這個(gè)值是固定的(沒(méi)測(cè)試過(guò)),所以直接拿F12調(diào)試出來(lái)的來(lái)用就好了。
ts 是時(shí)間戳
salt 是 ts 加上一個(gè) 0 到 10 的隨機(jī)數(shù)(包括0,不包括10)
sign 是對(duì)?"fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj" (這個(gè)字符串是會(huì)更新的,在js文件里可以找到)這個(gè)字符串進(jìn)行 md5 加密
好了,知道以上信息,我們可以進(jìn)一步完善我們的代碼了,如下圖:
# -*-coding:utf-8-*-
__Author__ = "Mr.D"
__Date__ = '2019\5\26 0026 16:50'
import time
from faker import Faker
import random
import hashlib
import requests
ua = Faker().user_agent()
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
key = input("請(qǐng)輸入你需要翻譯的內(nèi)容: ")
//生成時(shí)間戳 ts
ts = str(time.time() * 1000)
// 通過(guò) ts 加 0-10的隨機(jī)整數(shù)字符生成 salt
salt = ts + str(random.randint(0, 10))
the_str = "fanyideskweb" + key + salt + "n%A-rKaT5fb[Gy?;N5@Tj"
// md5加密生成 sign
md5 = hashlib.md5()
md5.update(the_str.encode('utf-8'))
sign = md5.hexdigest()
headers = {
'User-Agent': ua,
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
}
from_data = {
'i': key,
'from': 'UTO',
'to': 'UTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': salt,
'sign': sign,
'ts': ts,
'bv': '5504a5c7c19867a06038cf79d29f756a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
response = requests.post(url, headers=headers, data=from_data).json()
print(response)
print(response['translateResult'][0][0]['tgt'])
完成之后再次爬取,發(fā)現(xiàn)還是報(bào)一樣的錯(cuò)誤。
納尼!! 再三檢查代碼,沒(méi)有發(fā)現(xiàn)有寫錯(cuò)任何地方啊
既然? from_data 沒(méi)有寫錯(cuò),那么問(wèn)題可能是出現(xiàn)在了 headers 上了
經(jīng)過(guò)調(diào)試,發(fā)現(xiàn)每次 headers 都會(huì)攜帶 cookie ,而且 cookie 的值每次都不一樣
'Cookie': 'OUTFOX_SEARCH_USER_ID=559238864@10.168.8.61; OUTFOX_SEARCH_USER_ID_NCOO=2061523511.1027195; _ga=GA1.2.1151109878.1551536968; _ntes_nnid=24fe647fc20f952c4040b25650f75604,1553001083850; JSESSIONID=aaaJIa27BLmlI96aStZRw; ___rl__test__cookies=1558881656766'
不一樣的地方在于最后的那個(gè) "__rl__test__cookies=" 后面的字符串不一樣,然后去找到它是怎么生成的,最后終于在
"http://shared.ydstatic.com/js/rlog/v1.js" 這個(gè)js文件中找到了它
原來(lái)它也是時(shí)間戳,怪不得看起來(lái)有點(diǎn)像
繼續(xù)完善代碼
# -*-coding:utf-8-*-
__Author__ = "Mr.D"
__Date__ = '2019\5\26 0026 16:50'
import time
from faker import Faker
import random
import hashlib
import requests
ua = Faker().user_agent()
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
key = input("請(qǐng)輸入你需要翻譯的內(nèi)容: ")
//生成時(shí)間戳 ts
ts = str(time.time() * 1000)
// 通過(guò) ts 加 0-10的隨機(jī)整數(shù)字符生成 salt
salt = ts + str(random.randint(0, 10))
the_str = "fanyideskweb" + key + salt + "@6f#X3=cCuncYssPsuRUE"
// md5加密生成 sign
md5 = hashlib.md5()
md5.update(the_str.encode('utf-8'))
sign = md5.hexdigest()
headers = {
'User-Agent': ua,
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
'Cookie': 'OUTFOX_SEARCH_USER_ID=559238864@10.168.8.61; OUTFOX_SEARCH_USER_ID_NCOO=2061523511.1027195; _ga=GA1.2.1151109878.1551536968; _ntes_nnid=24fe647fc20f952c4040b25650f75604,1553001083850; JSESSIONID=aaaJIa27BLmlI96aStZRw; ___rl__test__cookies=' + ts
}
from_data = {
'i': key,
'from': 'UTO',
'to': 'UTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': salt,
'sign': sign,
'ts': ts,
'bv': '5504a5c7c19867a06038cf79d29f756a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
response = requests.post(url, headers=headers, data=from_data).json()
print(response)
print(response['translateResult'][0][0]['tgt'])
好了,讓我們運(yùn)行代碼看看
大功告成。
附使用 urllib 庫(kù)的代碼
?
# -*-coding:utf-8-*-
__Author__ = "Mr.D"
__Date__ = '2019\5\26 0026 18:07'
import urllib.request
import urllib.parse
import json
import time
import random
import hashlib
from faker import Faker
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
ua = Faker().user_agent()
key = input("請(qǐng)輸入你需要翻譯的內(nèi)容: ")
ts = str(time.time() * 1000)
salt = ts + str(random.randint(0, 10))
the_str = "fanyideskweb" + key + salt + "@6f#X3=cCuncYssPsuRUE"
md5 = hashlib.md5()
md5.update(the_str.encode('utf-8'))
sign = md5.hexdigest()
# 請(qǐng)求頭
headers = {
'User-Agent': ua,
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
'Cookie': 'OUTFOX_SEARCH_USER_ID=559238864@10.168.8.61; OUTFOX_SEARCH_USER_ID_NCOO=2061523511.1027195; _ga=GA1.2.1151109878.1551536968; _ntes_nnid=24fe647fc20f952c4040b25650f75604,1553001083850; JSESSIONID=aaaJIa27BLmlI96aStZRw; ___rl__test__cookies=' + ts
}
# 表單數(shù)據(jù)
from_data = {
'i': key,
'from': 'UTO',
'to': 'UTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': salt,
'sign': sign,
'ts': ts,
'bv': '5504a5c7c19867a06038cf79d29f756a',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
from_data = urllib.parse.urlencode(from_data).encode('utf-8')
request = urllib.request.Request(url, from_data, headers)
response = urllib.request.urlopen(request).read().decode("utf-8")
target = json.loads(response)
result = target['translateResult'][0][0]['tgt']
print(result)
總結(jié)
用到的知識(shí)點(diǎn):
1. faker庫(kù)隨機(jī)生成 ua
2. time()函數(shù)生成時(shí)間戳
3. hashlib庫(kù)進(jìn)行md5加密
4. js基礎(chǔ)知識(shí)的掌握
5. requests庫(kù)的使用
其中,第四點(diǎn)最為重要
?
二.繞過(guò)js加密
代碼這個(gè)方法非常簡(jiǎn)單,只需要將 url 中的 _o 去掉就可以了,在傳遞的from_data中不再需要上述幾個(gè)加密的參數(shù),只需要我們所要翻譯的內(nèi)容 就可以進(jìn)行數(shù)據(jù)獲取了
urllib 庫(kù)的爬取代碼如下
# -*-coding:utf-8-*-
__Author__ = "Mr.D"
__Date__ = '2019\5\26 0026 18:07'
import urllib.request
import urllib.parse
import json
from faker import Faker
// 去掉_o
url = 'http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule'
ua = Faker().user_agent()
key = input("請(qǐng)輸入你需要翻譯的內(nèi)容: ")
# 請(qǐng)求頭
headers = {
'User-Agent': ua,
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
}
# 表單數(shù)據(jù)
from_data = {
'i': key,
'from': 'UTO',
'to': 'UTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_REALTlME'
}
from_data = urllib.parse.urlencode(from_data).encode('utf-8')
request = urllib.request.Request(url, from_data, headers)
response = urllib.request.urlopen(request).read().decode("utf-8")
target = json.loads(response)
result = target['translateResult'][0][0]['tgt']
print(result)
?
在看完上面的代碼之后,可以自己嘗試著寫出使用第二種方法和requests庫(kù)進(jìn)行有道翻譯的爬取,來(lái)驗(yàn)證代碼是否正確
最后,歡迎大家提問(wèn)
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
