爬蟲實戰2_有道翻譯sign破解
目標url 有道翻譯
- 打開網站輸入要翻譯的內容,一一查找network發現數據返回json格式,紅框就是我們的翻譯結果
- 查看headers,發現返回結果的請求是post請求,且攜帶一大堆form_data,一一理下一表單數據
- i:要翻譯的數據
- from、to:from to 表示從哪國語言翻譯到哪國語言
- smartresult、doctype:返回結果的形式以字典形式
- client、keyfrom、action:區分客戶端類型
- salt、sign、ts、bv:看起來不太友善,好像是反爬蟲參數
- 觀察ts參數為13整數字元串,大概率是當前時間戳取整
- salt比ts多出一位
- sign和bv都為32位字元串,可以推斷為經過MD5加密的字元串
- 使用瀏覽器的search功能,發現sign藏在一個js文件中,搜索找到並點擊
- 經過一番查找,發現這四位老鐵是不是挺眼熟,沒錯,這個函數就是這四個參數的生成演算法(js加密參數一般都是用客戶端比如.py的參數參數生成演算法和伺服器端的參數生成演算法比較,不是用參數直接比較,這點要注意)
既然已經找到,那我們就用python改寫一個這段生成加密參數的js程式碼,我們把js程式碼複製到本地以方便改寫Python程式碼
define("newweb/common/service", ["./utils", "./md5", "./jquery-1.7"], function(e, t) {
var n = e("./jquery-1.7");
e("./utils");
e("./md5");
var r = function(e) {
var t = n.md5(navigator.appVersion) # navigator.appVersion就是瀏覽器版本資訊,User-Agent
, 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") # 這邊的最後一個子串看起來像隨機生成的(容易誤導),可以在js程式碼裡面打斷點多試幾遍發現是常量
}
};
def get_sign(self, key_word):
user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
# ts 為當前時間戳
ts = str(round(time()))
# salt 為ts拼接1-9之間的一個隨機整數
salt = ts + str(randint(1 ,9))
# bv browser version 就是User-Agent進過md5加密的數據
bv = hashlib.md5(bytes(user_agent, encoding='utf-8')).hexdigest()
# sign 由四部分組成,起始和結尾的數據都是固定的,中間兩個參數分別對應要翻譯的對象和 salt
sign = hashlib.md5(bytes('fanyideskweb' + key_word + salt + 'Nw(nmmbP%A-r6U3EUn]Aj', encoding='utf-8')).hexdigest()
self.post_data['salt'] = salt
self.post_data['sign'] = sign
self.post_data['ts'] = ts
self.post_data['bv'] = bv
return self.post_data
- 接下來完事具備,我們就把我們的蜘蛛完善一下
#!/usr/bin/env python
# !@software: PyCharm
# !@coding:
# !@time: 2020/4/22 11:52
# !@author: xiaoma
import requests
from random import randint,sample
from time import time
import hashlib
class FanyiSpider(object):
def __init__(self, key_word):
self.key_word = key_word
self.base_url = '//fanyi.youdao.com/'
self.post_data = {
'i': self.key_word,
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'salt': '',
'sign': '',
'ts': '',
'bv': '',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_CLICKBUTTION'
}
self.headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36',
'Referer': '//fanyi.youdao.com/'
}
self.session = requests.session()
def get_sign(self, key_word):
user_agent = 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'
# ts 為當前時間戳
ts = str(round(time()))
# salt 為ts拼接1-9之間的一個隨機整數
salt = ts + str(randint(1 ,9))
# bv browser version 就是User-Agent進過md5加密的數據
bv = hashlib.md5(bytes(user_agent, encoding='utf-8')).hexdigest()
# sign 由四部分組成,起始和結尾的數據都是固定的,中間兩個參數分別對應要翻譯的對象和 salt
sign = hashlib.md5(bytes('fanyideskweb' + key_word + salt + 'Nw(nmmbP%A-r6U3EUn]Aj', encoding='utf-8')).hexdigest()
self.post_data['salt'] = salt
self.post_data['sign'] = sign
self.post_data['ts'] = ts
self.post_data['bv'] = bv
return self.post_data
def run(self): # 主要實現邏輯
# 1. 發送get請求
get_res = self.session.get(self.base_url, headers=self.headers)
# 2. 獲取加密參數
post_data = self.get_sign(self.key_word)
# print(post_data)
# 3. 發送post,獲取響應
post_res = self.session.post(self.base_url+'translate_o', headers=self.headers, data=post_data) # 注意:翻譯的base_url和get請求的base_url有不一樣的地方,記得拼接
# 4. 解析數據
print(post_res.json().get('translateResult')[0][0]['tgt'])
if __name__ == '__main__':
key_word = input("請輸入想要翻譯的內容>>>").strip()
youdao = FanyiSpider(key_word)
youdao.run()