---------------------------------------------------------------------
python版本:3.6
測試日期:2020-03-22
聯系郵箱:betterWL@hotmail.com
---------------------------------------------------------------------
1 分析
——
不同的網站請求數據的方式可能不一樣,有靜態的、動態的,還有的可能有各種反爬蟲機制保護。
所以用到的爬蟲方法也不一樣,在想着爬取之前我們要先對網站進行分析
有道翻譯web版url = http://fanyi.youdao.com/
1.1 動態or靜態?
顯然數據是動態生成的,因為當我們隨便輸入一個詞來翻譯
右鍵查看網頁源代碼時,搜索剛才翻譯的“你好”查不到關鍵字,所以數據肯定時動態生成的。
1.2 過濾有效數據包
打開chrome自帶的檢查工具(F12)——NetWork,由於動態的數據請求基本都是Ajax來做的,所以我們直接過濾XHR
在翻譯頁面點一下翻譯按鈕,可以看到檢查工具中多了一個數據包,查看Response選項可以看到返回的是json格式的數據,並且帶有翻譯后的結果——'hello'
確定這條數據包就是我們要的數據包后,就要分析最重要的屬性的了——Headers
1.3分析數據包Headers
一步一步來,我們先確定真正請求數據的url,和請求的方式
url = http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule
請求方式 = POST
與GET請求不同,POST請求的參數不在Query String中,而是在Form Data中。(所以它請求數據前后url並不發生變化,所以可以通過查看點擊翻譯按鈕url並不發生變化判斷是POST請求。)
Form Data可以在Headers下最下方看到:
進行了多次翻譯操作,比對這些參數,可以發現:
i ---------> 要翻譯的源字串
ts、salt、sign ---------> 每次動態變化的
這其實就是有道設置的反爬機制,要破解它就要搞定s、salt、sign這三個參數是我們重點要搞定的,
搞定了他們三個,直接調用requests.post()就可以了
2 反爬蟲
——
上面我們說了 ts、salt、sign 這三個參數是動態生成的,既然是動態的,我們就必須找到一種方法來知道他是怎么生成的才能對其進行破解。
2.1 動態參數生成的方法
這種隨機的數據產生的方法通常只有兩種:
一是通過請求服務器傳回一些莫名其妙的值,這個我們肯定不能去破解,因為我們根本不知道數據生成的邏輯;
二是通過本地的js文件來生成,這種情況我們可以找到生成的方法,也就有機會進行破解。
那么如何判斷這些加密的參數到底是從服務器返回的還是本地生成的呢?
其實很簡單,還是要看數據包的信息——Initiator,分析請求源。這里有兩個js文件,我懷疑是translate這個動作對應的fanyi.min.js是生成參數的js文件。
(Whatever,只有兩個js,你挨個試也很簡單可以發現哪個對)
點擊后面的超鏈接,打開對應的js文件,復制代碼到js格式化的網站,例如:http://edit.qqe2.com/
將格式化好代碼復制到一個編輯器(notepad++、sublime都可以)
如果有關於ts、salt、sign的生成方法應該就有相關的代碼,進而可知應該會有相關的參數叫ts、salt、sign(命名習慣)
搜索之后,恰好找到具體的生成方法 (●ˇ∀ˇ●)
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 + "Nw(nmmbP%A-r6U3EUn]Aj") } };
整理了一下得到:
(1)網站采用的是md5加密 (2)ts = "" + (new Date).getTime() -----> 單位為毫秒的時間 (3)salt = "" + (new Date).getTime() + parseInt(10 * Math.random(), 10) -----> ts后連接一個[1,10]的整數
(4)sign = n.md5("fanyideskweb" + e + i + "@6f#X3=cCuncYssPsuRUE") -----> e為要翻譯內容,i=ts,其余為固定字串
得到了動態參數,也就得到了Form Data,也就可以開始編寫我們的代碼啦, <( ̄︶ ̄)↗[GO!]
3 代碼書寫
# -*- encoding: utf-8 -*-, ''' @File : youdao.py, @Time : 2020/03/21 17:39:40, @Author : bAdblocks , @Version : 1.0, @Contact : betterWL@hotmail.com, ''' # here put the import lib import requests import time import random import hashlib import json url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule' headers = { "Cookie": "OUTFOX_SEARCH_USER_ID=1721894360@59.111.179.141; _ntes_nnid=28c86721ce2c2392d0b4bc1c066195c2,1562810189644; OUTFOX_SEARCH_USER_ID_NCOO=1717529083.05212; P_INFO=qducst_xmt@163.com|1572920094|0|other|00&99|shd&1572744638&mail163#shd&null#10#0#0|&0|mail163|qducst_xmt@163.com; JSESSIONID=aaadMecWfzOYVgeMhs8dx; ___rl__test__cookies=1584780646068", "Referer": "http://fanyi.youdao.com/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36", } key = input('請輸入需要翻譯的文字:') #長度小於5000 # ts,salt,sign 的計算方法見fanyi.min.js ts = str(time.time() * 1000) salt = ts + str(random.randint(1,10)) sign = hashlib.md5(('fanyideskweb' + key + salt + 'Nw(nmmbP%A-r6U3EUn]Aj').encode('utf-8')).hexdigest() DataForm = { "i": key, "from": "AUTO", "to": "AUTO", "smartresult": "dict", "client": "fanyideskweb", "ts": ts,# 動態獲取 "salt": salt, # 動態獲取 "sign": sign,# 動態獲取 "bv": "70244e0061db49a9ee62d341c5fed82a",# 與jquery的版本有關 "doctype": "json", "version": "2.1", "keyfrom": "fanyi.web", "action": "FY_BY_CLICKBUTTION" } r = requests.post(url, data=DataForm, headers=headers) result_json = json.loads(r.text) # print(result_json) if (result_json['errorCode'] == 40): print('抱歉,不認識這個詞') exit(40) result = result_json['translateResult'][0][0]['tgt'] print('翻譯的結果是:' + result)