天天看點

爬蟲之js加密破解爬蟲之js加密破解

爬蟲之js加密破解

一:JS加密簡介

​ 我們爬取資料時想要破解JS加密,首先要了解什麼是JS加密,它是如何加密的,了解了它的原理後我們才能迅速,準确的破解它。

(一):JS加密原理

​ JS全稱JavaScript,是一種前端語言。就如同我們學的Python一樣是一門計算機語言,隻不過應用領域不同而已。通過這門語言可以在前端定義函數,進行資料和邏輯的計算,這也是JS能夠加密的重要原因。當我們爬取一些簡單的網站時,首先是向伺服器發送攜帶參數的url請求,伺服器根據我們的請求以及參數直接傳回給我們資料。而進過JS加密的網站會在我們我們發送url請求時,首先對我們url中攜帶的參數在一個JS檔案中進行一系列的運算,然後将運算後的值作為參數代替原本的參數發送到伺服器進行請求。

(二):JS加密破解要點

​ 知道了原理後,我們就明白了破解JS加密的要點:隻要我們弄清了JS檔案處理參數的過程,那麼我們就能在本地用python進行同樣處理,這樣得到的參數就是伺服器想要的參數了,到此我們的JS加密破解就完成了。

二:JS加密破解舉例

(一):爬取有道翻譯的譯文

  1. 我們先在翻譯框中輸入一個待翻譯單詞,以as為例,擷取到它的譯文,借此了解它的參數結構
import requests

# 定義請求頭
headers = {
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Connection": "keep-alive",
    "Content-Length": "236",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Cookie": "[email protected]; JSESSIONID=aaapIu5Rsmjnk55eGXiyx; OUTFOX_SEARCH_USER_ID_NCOO=904567522.0777537; ___rl__test__cookies=1606464861023",
    "Host": "fanyi.youdao.com",
    "Origin": "http://fanyi.youdao.com",
    "Referer":"http://fanyi.youdao.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest"
}

# 定義參數字典
# get請求定義參數時用的是params,而post請求定義參數時用的是data
# data可以從請求頭中獲得,這就是我們發送post請求時攜帶的參數,是我們接下了研究的重點
data = {
    "i": "as",
    "from": "AUTO",
    "to": "AUTO",
    "smartresult": "dict",
    "client": "fanyideskweb",
    "salt": "16064648610367",
    "sign": "f3ef68d97477fa61bcd2d3849b1260f9",
    "lts":" 1606464861036",
    "bv": "85a1eb4c1b6f458fda5e7e81446e33f5",
    "doctype": "json",
    "version": "2.1",
    "keyfrom": "fanyi.web",
    "action": "FY_BY_REALTlME"
}


# 請求有道翻譯
response = requests.post(url="http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule",
                         headers=headers,
                         data=data
                         )

# 将json資料轉換為python類資料,并擷取我們想要的結果
print(response.json()["translateResult"][0][0]["tgt"]) 
           
  1. 我們進行自定義單詞輸入,看看會有什麼結果
import requests

# 定義請求頭
headers = {
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Connection": "keep-alive",
    "Content-Length": "236",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Cookie": "[email protected]; JSESSIONID=aaapIu5Rsmjnk55eGXiyx; OUTFOX_SEARCH_USER_ID_NCOO=904567522.0777537; ___rl__test__cookies=1606464861023",
    "Host": "fanyi.youdao.com",
    "Origin": "http://fanyi.youdao.com",
    "Referer":"http://fanyi.youdao.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest"
}

# 自定義單詞輸入
word = input("請輸入要翻譯的單詞:")

# 定義參數字典
# get請求定義參數時用的是params,而post請求定義參數時用的是data
# data可以從請求頭中獲得,這就是我們發送post請求時攜帶的參數,是我們接下了研究的重點
data = {
    "i": word,
    "from": "AUTO",
    "to": "AUTO",
    "smartresult": "dict",
    "client": "fanyideskweb",
    "salt": "16064648610367",
    "sign": "f3ef68d97477fa61bcd2d3849b1260f9",
    "lts":" 1606464861036",
    "bv": "85a1eb4c1b6f458fda5e7e81446e33f5",
    "doctype": "json",
    "version": "2.1",
    "keyfrom": "fanyi.web",
    "action": "FY_BY_REALTlME"
}


# 請求有道翻譯
response = requests.post(url="http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule",
                         headers=headers,
                         data=data
                         )

# 将json資料轉換為python類資料,并擷取我們想要的結果
print(response.json()["translateResult"][0][0]["tgt"]) # 報錯,得不到資料
           

​ 說明隻改變翻譯單詞是行不通的,我們去看看不同單詞的參數有什麼不一樣

  1. 在翻譯框中重新輸入一個單詞,以hello為例,拿出它的data參數,與as參數對比,尋找出不同點,可自行輸入多個單詞進行對比,能夠更加準确的定義到參數不同點,這裡我就以兩個對比
# as 參數
i: as
from: AUTO
to: AUTO
smartresult: dict
client: fanyideskweb
salt: 16066298991539
sign: eb3e15819f8d3581a0c7eb9ce8f020b5
lts: 1606629899153
bv: 85a1eb4c1b6f458fda5e7e81446e33f5
doctype: json
version: 2.1
keyfrom: fanyi.web
action: FY_BY_REALTlME

# hello 參數
i: hello
from: AUTO
to: AUTO
smartresult: dict
client: fanyideskweb
salt: 16066321109501
sign: 895347ca623f4079fb5f39ae69f5afab
lts: 1606632110950
bv: 85a1eb4c1b6f458fda5e7e81446e33f5
doctype: json
version: 2.1
keyfrom: fanyi.web
action: FY_BY_REALTlME
           

​ 通過兩個不同單詞的參數對比,我們可以發現有以下幾個參數不同:

​ salt:看起來像是時間戳,但不确定

​ sign:看起來像是一串加密數值

​ lts :與salt很像,僅僅是比salt少了一位數

  1. 找到不同參數後,我們就要嘗試去破解它,首先要找到相應的js檔案,搞清楚這些值是經過了怎樣的運算得到的

    破解步驟:

  • 找到相應的js檔案:f12 —> Network —> XHR —> Initiator,如果隻有一個js檔案那麼就肯定是這個檔案了,如果有多個就需要我們一個個去找了。
  • 進去檔案後可先點選下面的{}進行格式整理,然後Ctrl+f打開搜尋框,搜尋 salt
  • 發現有多個salt,這時需要篩選出我們需要的那個salt,我們隻需要單獨的salt單詞,故先排除包含salt的單詞。在剩下的單詞中使用調試模式尋找,即在找到的salt處打一個斷點,然後在翻譯框中随便輸入内容,如果螢幕變暗被鎖定那麼就說明我們找到了salt。
  • 找到後,将js函數剪切下來進行分析
    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 + "]BjuETDhU)zqSxf-=B#7m")
            }
        };
               
  • 我們分析salt的值,它是i的值,分析i的值,i中包含r的值,我們把r的值也進行分析
    # i的值即為salt的值,r比i少一位,即r的值就是lts的值
    i = r + parseInt(10 * Math.random(), 10)
    r = "" + (new Date).getTime()
    
    
    # r分析,得到的是一個時間戳字元串,js中的時間戳機關是毫秒
    # 使用python模仿運算(解密)
    import time
    lts = str(round(time.time * 1000))
    
    # i分析,parseINt為舍去小數取整,Math.random為擷取一個[0,1)之間的随機小數,10代表10進制
    # 整體意思為擷取一個0~9的一個随機數,包括9
    # 使用python模仿運算
    import random
    salt = r + random.randint(0,9)
               
  • 現在隻剩下sign的值了,我們來分析它,可以看出,sign 就是一個字元串的md5加密值
    sign: n.md5("fanyideskweb" + e + i + "]BjuETDhU)zqSxf-=B#7m")
     
     # 字元串由4部分組成,唯一沒有确定的就是e這個變量了,我們将滑鼠放在e上面,就會發現e原來是我們要翻譯的字元串,
     # 使用Python模仿運算
     import hashlib
     # 定義md5加密函數
     def encryption(sign):
     	md5 = hashlib.md5()
     	md5.updata(sign.encode("utf-8"))
     	return md5.hexdigest()
     sign = encryption("fanyideskweb" + word + salt + "]BjuETDhU)zqSxf-=B#7m")
     	
               
  1. 至此,有道翻譯的破解過程已完成,隻需将上面的代碼整合即可,整合代碼如下
import requests
import time
import random
import hashlib

# 定義請求頭
headers = {
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Connection": "keep-alive",
    "Content-Length": "236",
    "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    "Cookie": "[email protected]; JSESSIONID=aaapIu5Rsmjnk55eGXiyx; OUTFOX_SEARCH_USER_ID_NCOO=904567522.0777537; ___rl__test__cookies=1606464861023",
    "Host": "fanyi.youdao.com",
    "Origin": "http://fanyi.youdao.com",
    "Referer":"http://fanyi.youdao.com/",
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest"
}

# 自定義輸入單詞
word = input("輸入單詞:")

# 定義md5加密函數
def encryption(sign):
    # 初始化md5
    md5 = hashlib.md5()
    # 加密
    md5.update(sign.encode("utf-8"))
    # 傳回加密資料
    return md5.hexdigest()

# 擷取lts的值
lts = str(round(time.time() * 1000))

# 擷取salt的值
salt = lts + str(random.randint(0, 9))

# 擷取sign的值
sign = encryption("fanyideskweb" + word + salt + "]BjuETDhU)zqSxf-=B#7m")



# 定義參數字典
data = {
    "i": word,
    "from": "AUTO",
    "to": "AUTO",
    "smartresult": "dict",
    "client": "fanyideskweb",
    "salt": salt,
    "sign": sign,
    "lts": lts,
    "bv": "85a1eb4c1b6f458fda5e7e81446e33f5",
    "doctype": "json",
    "version": "2.1",
    "keyfrom": "fanyi.web",
    "action": "FY_BY_REALTlME"
}

# 請求有道翻譯
response = requests.post(url="http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule",
                         headers=headers,
                         data=data
                         )

# 向将json資料轉換為python類資料,并擷取我們想要的結果
print(response.json()["translateResult"][0][0]["tgt"])


           

(二):爬取百度翻譯的譯文

爬取百度翻譯的譯文相比于有道翻譯難度有所增加,但原理是一樣的,難在它的js運算過程多了一些。

  1. 比較不同單詞的post參數有什麼不同
# 單詞為hello時的參數
from: en
to: zh
query: hello
simple_means_flag: 3
sign: 54706.276099
token: c607abf49334fb1ca7f9987a5d86447c
domain: common

# 單詞為world時的參數
from: en
to: zh
query: world
simple_means_flag: 3
sign: 335290.130699
token: c607abf49334fb1ca7f9987a5d86447c
domain: common
           

​ 經過對比我們可以發現,query和sign不同,而query為我們的輸入值,是以我們隻需要解密sign即可

  1. 找到js中關于sign的加密函數
var f = this
    , n = this.processQuery(n)
    , h = {
    from: p.fromLang,
    to: p.toLang,
    query: n,
    transtype: r,
    simple_means_flag: 3,
    sign: y(n),
    token: window.common.token,
    domain: w.getCurDomain()
    };
           
  1. 分析sign,sign是一個函數的傳回值,我們将滑鼠放在y(n)上,發現函數名稱并不是y,而是e,其實在這裡e函數代表的就是y函數,我們點選進入到e函數中,截取出e函數的代碼。我們需要分析這段js代碼,然後找出它的運算規律。

    但是這段代碼有點兒複雜,而我們需要的僅僅是它的結果,是以我們在這裡建立一個js檔案,讓python去運作這些代碼,我們隻需要得到加密的結果即可

# 建立一個js檔案,指令為sign.js,并将以下代碼放進去

function e(r) {
        var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
        if (null === o) {
            var t = r.length;
            t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
        } else {
            for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
                "" !== e[C] && f.push.apply(f, a(e[C].split(""))),
                C !== h - 1 && f.push(o[C]);
            var g = f.length;
            g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
        }
        var u = void 0
          , l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
        u = null !== i ? i : (i = window[l] || "") || "";
        for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
            var A = r.charCodeAt(v);
            128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
            S[c++] = A >> 18 | 240,
            S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
            S[c++] = A >> 6 & 63 | 128),
            S[c++] = 63 & A | 128)
        }
        for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
            p += S[b],
            p = n(p, F);
        return p = n(p, D),
        p ^= s,
        0 > p && (p = (2147483647 & p) + 2147483648),
        p %= 1e6,
        p.toString() + "." + (p ^ m)
    }
           
  1. 接下來我們就通過python來運作這些代碼,需要下載下傳一個第三方子產品

(1) 下載下傳pyexecjs子產品

pip install pyexecjs
           

​ (2) 建立一個測試檔案,用來測試js代碼,起名為test.py

# 導入子產品
import execjs

# 讀取js檔案
js_content = open("sign.js","r",encoding="utf-8").read()

# 編譯js檔案
js_data = execjs.compile(js_content)

# 執行js檔案
# 第一個參數為要執行的js函數名
# 第二個參數為要執行的js函數中的參數
sign = js_data.call("e","hello")

print(sign)
           

發現錯誤:

​ 第一個錯誤:TypeError: ‘i’ 未定義

​ 解決:我們頁面中找到這一段js函數中的 i,打開調試模式,讓代碼一行一行的向下運作,檢視 i 的值, 當執行完 i 後,我們将滑鼠放在 i 上,可以發現 i 其實就是一個字元串。換不同的單詞進行驗證,發現 i 的值是不變的。故我們在sign.js檔案中對 i 進行定義

# sign.js檔案

function e(r) {

		// 此處對i進行定義
		// ---------------------------------------------
		var i ="320305.131321201" 
		// ---------------------------------------------
		
        var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
        if (null === o) {
            var t = r.length;
            t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
        } else {
            for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
                "" !== e[C] && f.push.apply(f, a(e[C].split(""))),
                C !== h - 1 && f.push(o[C]);
            var g = f.length;
            g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
        }
        var u = void 0
          , l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
        u = null !== i ? i : (i = window[l] || "") || "";
        for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
            var A = r.charCodeAt(v);
            128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
            S[c++] = A >> 18 | 240,
            S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
            S[c++] = A >> 6 & 63 | 128),
            S[c++] = 63 & A | 128)
        }
        for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
            p += S[b],
            p = n(p, F);
        return p = n(p, D),
        p ^= s,
        0 > p && (p = (2147483647 & p) + 2147483648),
        p %= 1e6,
        p.toString() + "." + (p ^ m)
    }
           

​ 第二個錯誤:TypeError: 缺少對象

​ 解決:在js中,對象可能是一個類似于python中的字典,也可能是一個函數對象。是以我們在js代碼中 找到未定義的對象,這個是需要我們一行一行去找的,最終發現未定義的對象為 p = n(p, F)中的n。我 們在頁面中進入到n函數中,将其截取下來放到js檔案中,再次運作test.py檔案。

# sign.js檔案

function e(r) {
		var i ="320305.131321201"  // 此處對i進行定義
        var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
        if (null === o) {
            var t = r.length;
            t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
        } else {
            for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
                "" !== e[C] && f.push.apply(f, a(e[C].split(""))),
                C !== h - 1 && f.push(o[C]);
            var g = f.length;
            g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
        }
        var u = void 0
          , l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
        u = null !== i ? i : (i = window[l] || "") || "";
        for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
            var A = r.charCodeAt(v);
            128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
            S[c++] = A >> 18 | 240,
            S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
            S[c++] = A >> 6 & 63 | 128),
            S[c++] = 63 & A | 128)
        }
        for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
            p += S[b],
            p = n(p, F);
        return p = n(p, D),
        p ^= s,
        0 > p && (p = (2147483647 & p) + 2147483648),
        p %= 1e6,
        p.toString() + "." + (p ^ m)
    }
function n(r, o) {
        for (var t = 0; t < o.length - 2; t += 3) {
            var a = o.charAt(t + 2);
            a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
            a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
            r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
        }
        return r
    }    
           

​ 将運作結果與sign值進行對比,發現測試檔案運作結果即為我們要找的sign的值。這時将測試檔案中的代碼複制到執行檔案中即可。

  1. 最終代碼
import requests
import execjs

# 定義請求頭
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
    "cookie": "BIDUPSID=7D798573C260F654BA4EFE460E859695; PSTM=1606443252; BDORZ=FFFB88E999055A3F8A630C64834BD6D0; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_PREFER_SWITCH=1; SOUND_SPD_SWITCH=1; H_PS_PSSID=; delPer=0; PSINO=1; BDRCVFR[7Wj9V7qhHGf]=E9r8WGTE_ZnTAnzn1fdQhP8; ZD_ENTRY=baidu; BAIDUID=3565866098ABC8C0BF8E4E19805DDEA1:FG=1; BAIDUID_BFESS=3565866098ABC8C0721258A207B135B6:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1606463241,1606464629,1606487357,1606635536; BA_HECTOR=al248l81058085a5qk1fs6lo00q; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1606638236; __yjsv5_shitong=1.0_7_c0ee1fd992c31ae0ae6c1660faf22b1f7dea_300_1606638347832_121.69.97.22_9e5c1475; yjs_js_security_passport=edce489b85bc1c854013aa7ffa198cf269063fb9_1606638349_js",
}

# 自定義輸入單詞
word = input("輸入要翻譯的漢字:")

# 讀檔案
content = open("sign.js", "r", encoding="utf-8").read()

# 編譯
js_data = execjs.compile(content)

# 執行
# 第一個參數代表要執行的js函數
# 第二個參數代表js函數中要傳入的參數
sign = js_data.call("e", word)

print(sign)

# 定義data參數
# from參數為"zh",to為"en"時為中譯英,互換則為英譯中
data = {
    "from": "zh",
    "to": "en",
    "query": word,
    "simple_means_flag": "3",
    "sign": sign,
    "token": "c607abf49334fb1ca7f9987a5d86447c",
    "domain": "common"
}

# 通路url
response = requests.post(
    url="https://fanyi.baidu.com/v2transapi?from=en&to=zh",
    headers=headers,
    data=data
)

print(response.json()["trans_result"]["data"][0]["dst"])