一. 破解參數加密
有道翻譯的請求是post,攜帶一系列參數,直接F12刷新進行調試,如下圖所示:
這是一個 post 請求,目標網址是
'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
接下來讓我們看看發送該請求需要攜帶哪些參數
如圖所示,紅色方框里的就是需要攜帶的參數了。
最后看一看返回的數據
顯而易見,返回的數據是json格式的數據。
好了,現在我們可以寫程序進行爬取了
# -*-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("請輸入你需要翻譯的內容: ")
# 請求頭
headers = {
'User-Agent': ua,
'Host': 'fanyi.youdao.com',
'Origin': 'http://fanyi.youdao.com',
'Referer': 'http://fanyi.youdao.com/',
}
# post請求攜帶的參數
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'])
運行后發現報錯了,"{errorCode: 50}"
什么原因呢? 讓我們分析一下。
可以自己 重新來翻譯一下? "問題" 這個詞,然后在看一次此次 post 請求與上一次 post 請求有什么不同之處。
經過調試,我發現 from_data 中的參數有幾個是發生了變化的,分別是 "salt","sign","ts",那么這幾個參數是怎么生存的呢?
經過尋找,發現它們的生存規律在 "http://shared.ydstatic.com/fanyi/newweb/v1.0.17/scripts/newweb/fanyi.min.js" 這個? js 文件中,經過 json 格式化工具(百度)格式化之后,定位到具體的參數生成位置,
// e 為下面 r(t) 中的 t ,即我們所需要翻譯的內容
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) {
// 將我們所要翻譯的內容賦值給 t
var t = e.i,
// 將 t 當作參數傳入 r() 函數中,返回值賦給 i
i = r(t);
n.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
url: "/bettertranslation",
// 這里可以看出 data 就是我們post請求攜帶的參數字典
data: {
// e.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) {}
})
}
從上述代碼中,我們可以得出四個參數的信息: 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 是對? navigator.appVersion(這是個瀏覽器參數,不是字符串"navigator.appVersion")進行 md5 加密,在相同的瀏覽器下,這個值是固定的(沒測試過),所以直接拿F12調試出來的來用就好了。
ts 是時間戳
salt 是 ts 加上一個 0 到 10 的隨機數(包括0,不包括10)
sign 是對?"fanyideskweb" + e + salt + "n%A-rKaT5fb[Gy?;N5@Tj" (這個字符串是會更新的,在js文件里可以找到)這個字符串進行 md5 加密
好了,知道以上信息,我們可以進一步完善我們的代碼了,如下圖:
# -*-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("請輸入你需要翻譯的內容: ")
//生成時間戳 ts
ts = str(time.time() * 1000)
// 通過 ts 加 0-10的隨機整數字符生成 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'])
完成之后再次爬取,發現還是報一樣的錯誤。
納尼!! 再三檢查代碼,沒有發現有寫錯任何地方啊
既然? from_data 沒有寫錯,那么問題可能是出現在了 headers 上了
經過調試,發現每次 headers 都會攜帶 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'
不一樣的地方在于最后的那個 "__rl__test__cookies=" 后面的字符串不一樣,然后去找到它是怎么生成的,最后終于在
"http://shared.ydstatic.com/js/rlog/v1.js" 這個js文件中找到了它
原來它也是時間戳,怪不得看起來有點像
繼續完善代碼
# -*-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("請輸入你需要翻譯的內容: ")
//生成時間戳 ts
ts = str(time.time() * 1000)
// 通過 ts 加 0-10的隨機整數字符生成 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'])
好了,讓我們運行代碼看看
大功告成。
附使用 urllib 庫的代碼
?
# -*-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("請輸入你需要翻譯的內容: ")
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()
# 請求頭
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'
}
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)
總結
用到的知識點:
1. faker庫隨機生成 ua
2. time()函數生成時間戳
3. hashlib庫進行md5加密
4. js基礎知識的掌握
5. requests庫的使用
其中,第四點最為重要
?
二.繞過js加密
代碼這個方法非常簡單,只需要將 url 中的 _o 去掉就可以了,在傳遞的from_data中不再需要上述幾個加密的參數,只需要我們所要翻譯的內容 就可以進行數據獲取了
urllib 庫的爬取代碼如下
# -*-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("請輸入你需要翻譯的內容: ")
# 請求頭
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',
'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庫進行有道翻譯的爬取,來驗證代碼是否正確
最后,歡迎大家提問
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

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