爬蟲實戰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()
Tags: