JS滲透之百度翻譯實戰(附帶源碼)
(目的:實現類似于百度翻譯的功能——輸入內容,得到對應的翻譯之后的內容。)

1.參數構造流程
這種提交數據得到響應的的請求,往往參數比較麻煩,所以參數的構造是得到完整請求的關鍵.
先作對比,找出不同的參數
從之前的請求響應中找數據
(1)網頁源代碼中查找
(2)全局請求搜索
JS加載調試,查找生成規律
不變的參數寫固定值,變動的參數的來源在JS中尋找,即JS滲透!
一個動態請求的參數來源只可能有兩個:
一是來自之前的請求響應,二是JS生成。
第一步:先作對比,找出不同的參數(即找到需要進一步分析的參數)!
1.Preserve log選項,如果勾選,即代表不清除上一個頁面請求的數據。比如:在一個網頁里登錄,如果不勾選此選項,由于點擊 登錄之前屬于一個請求;點擊登錄之后屬于另外一個請求。所以點擊之后是沒有你的登錄信息的! 2.Disable cache選項,表示清除緩存,一般都要勾選,防止網頁操作時由于本地緩存的存在,而導致一些預期之外的錯誤! 3.Hide data URLs:可以過濾掉data響應,便于觀察。
通過一個個觀察,我們會發現如圖所示這個響應中包含了翻譯結果,所以目標得到這個響應的URL。接下來,分析URL:
如圖所示,可以發現這個URL發送的是POST請求,所以需要攜帶表單數據。最后一步我們要做的就是:通過一次次翻譯,即一次次的發送請求,觀察表單參數的變化情況,然后破解它并能夠自己構造!
''' from: zh to: en query: 我討厭你 transtype: realtime simple_means_flag: 3 sign: 23824.310817 token: 2df0cc9f53be4e351fc34844056f562b domain: common ''' ''' from: zh to: en query: 我愛你 transtype: enter simple_means_flag: 3 sign: 47194.285547 token: 2df0cc9f53be4e351fc34844056f562b domain: common '''
對比參數分析可知:
from和to參數分別是翻譯內容和翻譯結果的語言;
query參數是翻譯的內容;
transtype參數經多次對比可知有三個值:translang,enter,realtime。分別對應點擊頁面中翻譯按鍵;按回車鍵enter;實時。
simple_means_flag參數發現一直沒有變化,屬于靜態參數;
sign參數是簽名,值是動態的,需要進一步分析!(需要找來源!)
token參數,可能會因為一些操作而變,需要進一步分析!(需要找來源!)
domain參數一直沒有變化,屬于靜態參數。
第二步:獲取第一步分析的動態加載的不同的參數!
獲取的一般思路:
一個動態請求的參數來源只可能有兩個:
一是來自之前的請求響應,二是JS生成。
按照獲取的一般思路,首先,復制token到網頁源碼中查找。會發現token的值就在源碼中(但是,請注意:這個token的值不是不變的,而是會改變的!)!
1.按照獲取的一般思路,首先,復制sign到網頁源碼中查找。會發現無論如何都找不到!
**2.所以,需要改變思路, 在全局請求搜索:(在Sources下使用快捷鍵Ctrl+Shift+f開啟全局搜索框Search) **
觀察之前sign的格式:sign: 47194.285547,所以我們在搜索欄中輸入sign:進行搜索!
然后分析可知第一個的格式跟前面的form表單參數格式相似,所以我們點擊進入此JS文件。
此部分數據格式和form表單中參數格式一模一樣,唯獨sign的值是個y(n)函數,所以,下一步我們要通過打斷點進入此生成sign值的函數:
接下來要做的就很簡單了。我們只需要將此JS函數拿過來單獨運行,一步步調試即可!
本人使用的是python里的PyexeCjs包,此包可以單獨運行JS代碼!
# 安裝 pip install PyexeCjs
編寫python腳本文件,注意:剛剛得到的JS函數放到此腳本文件同級目錄下,此處取名為sign.js。
import execjs def make_execjs_object(): with open('sign.js', 'r') as f: js = f.read() # .compile()方法將代碼編譯為JS代碼 return execjs.compile(js) js_object = make_execjs_object() # .call()函數的第一個參數是JS函數名,第二個參數開始就是JS函數的參數。注意:都是以字符串形式! js_object.call("e","你好")
運行報錯很正常,根據報錯改JS代碼,直到正確運行!
此處報錯i未定義,我們只需要去原JS代碼所在的JS文件里分析即可:
會發現,在此JS函數下面就是定義i的代碼,拿過來即可 !
再次運行,又報錯window未定義,查看sign.js下的JS代碼:
分析可知,此處有個window[1],并不知道其來源。所以,繼續回到原JS代碼所在的JS文件里分析即可
首先,在對應位置打斷點。
然后,重新開始調試開始debug模式,一步步調試,直到運行此斷點下方:(做的目的:這樣可以觀察到window[1]的值,借以分析它!)
觀察可知,window里有許多鍵值,[1]對應的是gtk的值。那么,如何獲取到gtk對應的值呢?
下面,又回到最開始,獲取動態加載的不同的參數(此處為gtk)!
首先,到網頁源碼中查找:
會發現,可以直接查找到,而且和JS文件中的值一模一樣,所以,關于此值的處理方法:我們只需要給此JS函數再傳遞一個參數,再編寫爬蟲文件時,使用正則獲取到此值傳入JS函數即可!
再次運行腳本,會報如下錯:
小拓展:關于JS代碼運行出現——缺少對象類型報錯的原因分析!
在javaScript中,程序調度過程中經常會出現缺少對象錯誤,這里的對象有時候是變量,有時候是函數,有時候可能是對象等等。 缺少對象錯誤經常有以下幾種情況 1.變量沒有定義 使用沒定義的變量時就會出在這種錯誤,這里經常是我們在寫代碼的時候不注意,把就是名寫錯就產生一個新的未定義的變量。 2.函數沒有定義 這種錯誤也經常是因為在調用函數時不小心把函數名寫錯了,就會產生一個未聲明的函數。 3.函數的參數 這個問題可以歸結到第一種情況當中,也就是在函數體內使用實參時的書寫錯誤。 4.對象的生成 javaScript中所操作的一些對象往往是從html文檔中提取的,經常會用到document.getElementById(str)這個函數,所以在調用這個函數的時候也可能會因為函數名或者參數的一些書寫上的錯誤而產生對象錯誤。
按照上面對此類報錯的分析,觀察JS代碼,可知其中有個n()函數是憑空出現的;觀察原JS文件會發現有這個函數:
直接將此函數拿過來即可!
再次運行,完全ok,生成的sign值也和正常運行時一模一樣!
第三步:所有準備工作都已完美完成,最后我們要做的也就是寫爬蟲代碼了!
import re import requests import execjs headers = {'' 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36', } session = requests.Session() session.headers = headers def make_execjs_object(): """ 執行js代碼,為了下面獲得sign值! :return: """ with open('sign.js', 'r') as f: js = f.read() return execjs.compile(js) get_sign = make_execjs_object() def get_token_gtk(): """ 請求初始URL,從響應中提取token,gtk參數。 注意:token需要獲取多次,才能保持穩定不變! :return: """ url='https://fanyi.baidu.com/' for i in range(3): response = session.get(url) token = re.findall("token: '(.*?)'",response.text)[0] gtk = re.findall("window.gtk = '(.*?)'", response.text)[0] print('[%s] token: '% i, token) print('[%s] gtk: '% i, gtk) return token, gtk def translate(query): """ 攜帶參數請求實現翻譯功能的URL,從響應中提取結果! :param query: :return: """ token, gtk = get_token_gtk() sign = get_sign.call('e', query, gtk) url='https://fanyi.baidu.com/v2transapi?from=zh&to=en' form_data = { "from": "zh", "to": "en", "query": query, "transtype": "enter", "simple_means_flag": "3", "sign": sign, "token": token, "domain": "common", } response = session.post(url, data=form_data) result = re.findall('"dst":"(.*?)"', response.text)[0] return result if __name__ == '__main__': input_quety = input('輸入中文:') translate_result = translate(input_quety) print(input_quety + ':' + translate_result)
完全ok!
機器翻譯
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。