目錄
- 1. 實體描述
- 2. 技術要點
- 2.1 有道詞典這樣的 JS 混淆加密應該怎么破
- 3. 代碼實作
1. 實體描述
在平時編程的程序中,會經常在網上翻譯一些單詞,本文使用Python制作一款翻譯小工具,不僅可以自己用,還可以嵌入到程式當中,運行程式,效果如下圖所示,在文本框輸入英文或中文,單擊 翻譯 按鈕即可翻譯,并將翻譯內容顯示在下面的文本框中,單擊 保存 按鈕將輸入內容和翻譯內容保存到文本檔案中以便日后復習,單擊 清空 按鈕,將清除文本框中的內容,

2. 技術要點
利用 requests 模塊獲取 有道詞典web 頁面的 post 資訊,獲取需要的內容,通過 tkinter 模塊生成視窗界面,使用檔案讀寫方法將內容保存到文本檔案中,
2.1 有道詞典這樣的 JS 混淆加密應該怎么破
嘿嘿嘿,本文需要說說一些爬蟲程序中需要斗智斗勇的事情了,這次咱們就來說說關于一些 JS 混淆加密的事,所謂 JS ,就是 JavaScript,一種前端的腳本語言,一般情況下每個網站都需要 JS 來做一些資料互動,頁面渲染等一些異步操作,當然,對于反爬的人來說,JS 的用處還可以用來對一些資料進行加密,
今天咱們就以有道詞典這個在線翻譯的網站為例,看看他們是如何加密請求資料的,以及筆者是如何通過 Python 模擬請求從而獲得關鍵資料的,
點擊 此處 打開有道翻譯的網站:

輸入中文然后點擊翻譯按鈕就會翻譯出來英文,比如:

接著我們打開開發者工具,按下 F12 來抓一下資料,當我們點擊翻譯的時候,可以看到有了一個請求:

點進去看可以發現,POST 請求的地址是:
http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule

我們再來看一下請求過去攜帶的引數是啥:

可以看到,還是需要挺多引數的,其中的 i 就是我們要翻譯的內容,那簡單啊~想要得到翻譯后的資料,那么我們直接把請求頭和所需引數的值復制一下,然后用 requests 請求一波不就搞定了?運行一波,回傳的是錯誤碼,

我們再點多幾次翻譯按鈕,然后就可以看到有多次請求,

可以發現,每一次的請求中的 salt、sign、lts、bv 引數是會一直變化的,


我們回到 NetWork ,我們看到 Initiator 這一欄,可以看到它請求到了 fanyi.min.js:1 這個 js 檔案,

我們就點 fanyi.min.js:1 進去看看,牛的一比,直接看不懂…還好,左下角有一個 {} ,可以點一下,發現有驚喜,直接幫我們把壓縮的 js 代碼格式化,

牛逼不,行號都給我們顯示出來了,不過到了這里,依然懵逼,我們還是不知道怎么拿到 salt、sign、lts、bv 這些引數的值…咋辦?恩,Chrome 瀏覽器的打斷點功能在這個時候就要派上用場,那么如何使用斷點功能呢,我們看到 Chrome 的右邊是這樣的:

看到這個 XHR/fetch BreakPoints 沒,在這里我們可以添加 url ,根據請求這個 url 打斷點,而我們要打的斷點就是一開始獲取到的請求 url :
http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
點擊 XHR/fetch BreakPoints 右邊的 + 號,然后把鏈接復制進去:

這時候再點擊翻譯按鈕,突然,你的螢屏一灰,表示好事將近,我們成功打上了斷點,也就是說,現在我們可以在請求之前做一些騷操作,

這時候我們將右邊的 Call Stack 展開,點 t.translate 進去:

這些,就是我們在點擊翻譯按鈕之后,會呼叫到 js 里面的方法,從這里下手,來尋找引數是被如何加密的,


3. 代碼實作
用Python制作mini翻譯器的具體步驟如下:
- 首先安裝
requests模塊,使用pip命令安裝,命令如下:pip install --user -i http://pypi.douban.com/simple --trusted-host pypi.douban.com requests - 匯入相關模塊,代碼如下,
import tkinter as tk import requests import time import hashlib import random - 定義翻譯函式,代碼如下,
def get_ts(): """ 獲取時間戳 :return: 時間 """ return str(int(time.time() * 1000)) def get_bv(): """ 獲取app版本 并通過md5加密 :return: 加密后的字串 """ navigator_appVersion = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3' \ '904.108 Safari/537.36' m = hashlib.md5() m.update(navigator_appVersion.encode('utf-8')) return m.hexdigest() def get_salt(ts): return str(ts) + str(int(random.random() * 10)) def get_sign(salt): str1 = text1.get() # 定義一個變數,用來接收輸入文本框的值 str_data = 'fanyideskweb' + str1 + salt + ']BjuETDhU)zqSxf-=B#7m' m = hashlib.md5() m.update(str_data.encode('utf-8')) return m.hexdigest() def get_form_data(): str1 = text1.get() # 定義一個變數,用來接收輸入文本框的值 ts = get_ts() salt = get_salt(ts) form_data = { 'i': str1, 'from': 'AUTO', 'to': 'AUTO', 'smartresult': 'dict', 'client': 'fanyideskweb', 'salt': str(salt), 'sign': get_sign(salt), 'ts': ts, 'bv': get_bv(), 'doctype': 'json', 'version': '2.1', 'keyfrom': 'fanyi.web', 'action': 'FY_BY_CLICKBUTTION', } return form_data # 定義翻譯函式 def translate(): url = "http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule" headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36', 'Referer': 'http://fanyi.youdao.com/', 'Cookie': 'OUTFOX_SEARCH_USER_ID_NCOO=173326173.72226533; OUTFOX_SEARCH_USER_ID="-1202396372@10.108.160.18"; DICT_UGC=be3af0da19b5c5e6aa4e17bd8d90b28a|; JSESSIONID=abcAjF-mxbKFQ_48uyLpx; __guid=204659719.1682486053682624500.1597281254731.5474; monitor_count=2; ___rl__test__cookies=1597285713766' } response = requests.post(url=url, data=get_form_data(), headers=headers) if response.status_code == 200: result = response.json() translate_result = result['translateResult'][0][0]['tgt'] text2.delete(1.0, "end") # 清空輸出文本框 text2.insert('end', translate_result) # 將翻譯結果添加到輸出文本框中 - 定義寫入文本
txt的函式,代碼如下,# 定義寫入文本txt的函式 def write(): f1 = open('translate.txt', 'a+') f1.write(text1.get() + ',' + text2.get(0.0, tk.END)) - 定義清空文本框的函式,代碼如下,
# 定義清空文本框的函式 def delete(): text1.delete(0, "end") # 從第一行清除到最后一行 text2.delete(1.0, "end") - 視窗界面設計,代碼如下,
if __name__ == '__main__': window = tk.Tk() # 創建window視窗 window.wm_attributes("-topmost", 1) # 置頂 window.title("AmoXiang mini翻譯器") # 定義視窗名稱 window.resizable(width=False, height=False) # 決定框體大小是否能夠調整 text1 = tk.Entry(window, width=80, bg='whitesmoke') # 在表單上添加一個輸入文本框,并設定尺寸和顏色 text2 = tk.Text(window, height=18, bg='lightgrey') # 在表單上添加一個輸出文本框,并設定尺寸和顏色 text1.grid(row=0, sticky="W", padx=1) text2.grid(row=1) # 添加一個按鈕,用于觸發翻譯功能 t_button = tk.Button(window, text='翻譯', relief=tk.RAISED, width=8, height=1, font='宋體', bg='red', fg='white', command=translate) # 添加一個按鈕,用于觸發清空輸入文本框 button1 = tk.Button(window, text='保存', font='宋體', relief=tk.RAISED, width=8, height=1, command=write) # 添加一個按鈕,用于觸發清空輸出文本框 button2 = tk.Button(window, text='清空', font='宋體', relief=tk.RAISED, width=8, height=1, command=delete) # 添加背景圖片 image_file = tk.PhotoImage(file='amo.gif') label = tk.Label(window, image=image_file) # 完成界面布局,設定各個控制元件的位置 t_button.grid(row=0, column=1, padx=2) button1.grid(row=0, column=2, padx=2) button2.grid(row=0, column=3, padx=2) label.grid(row=1, column=1, columnspan=3) tk.mainloop()
至此今天的案例就到此結束了,筆者在這里宣告,筆者寫文章只是為了學習交流,以及讓更多學習Python基礎的讀者少走一些彎路,節省時間,并不用做其他用途,如有侵權,聯系博主洗掉即可,撰寫不易,請大家手留余香~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/219460.html
標籤:其他
上一篇:Python 實作文字聊天室
