web端的有道翻譯,在以前是直接能夠爬的。也就是說只要獲取到了他的接口,你就能夠肆無忌憚的使用他的接口進行翻譯而不須要支付任何費用。那麼自從有道翻譯推出他的API服務的時候,就對這個接口作一個反爬蟲機制(若是你們都能無償使用到他的翻譯接口,那他的API服務怎麼賺錢)。這個反爬蟲機制在爬蟲領域算是一個很是經典的技術手段。那麼他的反爬蟲機制原理是什麼?如何破解?接下來帶你們一探究竟。
web
1、正常爬取一個網站的步驟json
若是你要爬取他的翻譯接口,這個流程仍是不能少的。首先咱們打開有道翻譯的連接:http://fanyi.youdao.com/。而後在頁面中右鍵->檢查->Network項。這時候就來到了網絡監聽窗口,之後你在這個頁面中發送的全部網絡請求,都會在Network這個地方顯示出來。接着咱們在翻譯的窗口輸入咱們須要翻譯的文字,好比輸入hello。而後點擊自動翻譯按鈕,那麼接下來在下面就能夠看到瀏覽器給有道發送的請求,這裏截個圖看看:瀏覽器
在上圖,咱們能夠看到發送了不少的網絡請求,這裏咱們點擊第一個網絡POST請求進行查看:服務器
能夠看到與一個Request URL,這個url是請求連接地址網絡
查看服務器的回覆包Responsesession
而且,如今咱們再回到Headers
的地方,而後滾動到最下面,能夠看到有一個Form Data
的地方,這個下面展現了許多的數據,這些數據就是你在點擊翻譯的時候瀏覽器給服務器發送的數據:dom
固然如今的Header 裏的From Data數據內容不止這些,還多了tv等字段ide
對其中幾個比較重要的數據進行解釋:工具
i
:須要進行翻譯的字符串,這個地方咱們輸入的是hello。salt
:加密用到的鹽。這個是咱們破解有道反爬蟲機制的關鍵點。sign
:簽名字符串。也是破解反爬蟲機制的關鍵點Python3
自帶的urllib
,相關代碼以下: 1 # 導入須要的庫 2 import urllib.request 3 import urllib.parse 4 import json 5 6 # 等待用戶輸入須要翻譯的單詞 7 content = input('請輸入須要翻譯的單詞:') 8 9 # 有道翻譯的url連接 10 url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=null' 11 12 # 發送給有道服務器的數據 13 data = {} 14 15 # 須要翻譯的文字 16 data['i'] = content 17 # 下面這些都先按照咱們以前抓包獲取到的數據 18 data['from'] = 'AUTO' 19 data['to'] = 'AUTO' 20 data['smartresult'] = 'dict' 21 data['client'] = 'fanyideskweb' 22 data['salt'] = '1500349255670' 23 data['sign'] = '997742c66698b25b43a3a5030e1c2ff2' 24 data['doctype'] = 'json' 25 data['version'] = '2.1' 26 data['keyfrom'] = 'fanyi.web' 27 data['action'] = 'FY_BY_CLICKBUTTON' 28 data['typoResult'] = 'true' 29 30 # 對數據進行編碼處理 31 data = urllib.parse.urlencode(data).encode('utf-8') 32 33 # 建立一個Request對象,把url和data傳進去,而且須要注意的使用的是POST請求 34 request = urllib.request.Request(url=self.url, data=data, method='POST') 35 # 打開這個請求 36 response = urllib.request.urlopen(request) 37 # 讀取返回來的數據 38 result_str = response.read().decode('utf-8') 39 # 把返回來的json字符串解析成字典 40 result_dict = json.loads(result_str) 41 42 # 獲取翻譯結果 43 print('翻譯的結果是:%s' % result_dict)
只是爲了顯示做用----學習基本爬蟲流程。學習
咱們運行這個文件後,當咱們輸入的是hello的時候,咱們能夠獲得哈羅的這個正確的翻譯結果。而當咱們輸入其餘須要翻譯的字符串的時候,好比輸入i love you,那麼就會獲得一個錯誤代碼{"errorCode":50}。這就奇怪了,有道詞典不可能只能翻譯一個英文單詞吧(開始變的貪得無厭 --)。而這個,就是有道詞典的反爬蟲機制。接下來咱們就來破解有道詞典的反爬蟲機制。
咱們能夠屢次的進行翻譯,而且每次翻譯後都去查看翻譯的時候發送的這個網絡請求,比較每次翻譯時候發送的Form Data的值。咱們注意到,Form Data在每次發送網絡請求的時候,只有i和salt以及sign這三個是不一樣的,其餘的數據都是同樣的,這裏我用hello和world兩個單詞翻譯時候Form Data的數據進行比較:
圖中的Form Data也證明了我剛剛所說的,就是除了i、salt以及sign是不同的。其他都是同樣的。而i不同是很正常的。由於i表明的是要翻譯的字符串,這個不一樣是很正常。而salt和sign這兩個東西不同,是怎麼產生的呢?這裏咱們能夠分析一下,這兩個值在每次請求的時候都不同,只有兩種狀況:第一是每次翻譯的時候,瀏覽器會從有道服務器獲取一下這兩個值(返回包裏面是否有GET到??)。這樣能夠達到每次翻譯的時候值不一樣的需求。第二是在本地,用JS代碼按照必定的規則生成的。那麼咱們首先來看第一個狀況,咱們能夠看到在每次發送翻譯請求的時候,並無一個請求是專門用來獲取這兩個值的:
第一種狀況涼涼...不慌,咱們還有法二 hh
因此就能夠排除第一種狀況。就只剩下一種可能,那就是在本地本身生成的,若是是在本地本身生成的,那麼規則是什麼呢?這裏咱們點擊網頁,查看網頁源代碼,查找全部的JS
文件,咱們找到那個fanyi.js
:(如今的有道代碼會用各類混淆的詞彙來掩飾這個js源代碼,還不是爲了避免讓你爬數據,不過認真找仍是能找到的)
而後點擊這個文件,跳轉到這個源文件中,而後全選全部的代碼,複製下來,再打開站長工具:http://tool.chinaz.com/Tools/jsformat.aspx
。把代碼複製進去後,點擊格式化:
將數據拷貝到notepad++ 或 sublime,打開,而後搜索salt
,能夠找到相關的代碼:
這裏咱們就能夠發現全部的值的生成原理了。這裏來作個簡介:
d:表明的是須要翻譯的字符串。
f:當前時間的時間戳加上0-10的隨機字符串。
u:一個常量——fanyideskweb。
c:一個常量——rY0D^0'nM0}g5Mm1z%1G4。
salt:就是f變量,時間戳。
sign:使用的是u + d + f + c的md5的值。
知道salt和sign的生成原理後,咱們就能夠寫Python代碼,來對接他的接口了,如下是相關代碼:
1 import urllib.request 2 3 import urllib.parse 4 import json 5 import time 6 import random 7 import hashlib 8 9 content = input('請輸入須要翻譯的句子:') 10 11 url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=https://www.google.com/' 12 13 data = {} 14 15 u = 'fanyideskweb' 16 d = content 17 f = str(int(time.time()*1000) + random.randint(1,10)) 18 c = 'rY0D^0\'nM0}g5Mm1z%1G4' 19 20 sign = hashlib.md5((u + d + f + c).encode('utf-8')).hexdigest() 21 22 data['i'] = content 23 data['from'] = 'AUTO' 24 data['to'] = 'AUTO' 25 data['smartresult'] = 'dict' 26 data['client'] = 'fanyideskweb' 27 data['salt'] = f 28 data['sign'] = sign 29 data['doctype'] = 'json' 30 data['version'] = '2.1' 31 data['keyfrom'] = 'fanyi.web' 32 data['action'] = 'FY_BY_CLICKBUTTON' 33 data['typoResult'] = 'true' 34 35 data = urllib.parse.urlencode(data).encode('utf-8') 36 request = urllib.request.Request(url=url,data=data,method='POST') 37 response = urllib.request.urlopen(request) 38print(response.read().decode('utf-8'))
還在學習破解中...但願有大佬破解出來能夠分享分享
像以上這種,經過用JS
在本地生成隨機字符串的反爬蟲機制,在爬蟲的時候是常常會遇到的一個問題。主要學習的是一種思路。之後再碰到這種問題的時候知道該如何解決。這樣本篇文章的目的也就達到了。
另外說明一下如今的有道就連爬取一個單純單詞用這個方法都不行了 ,有道使用了更爲複雜的反爬蟲機制,等待學習中...
最後附上大佬的博客地址:https://blog.csdn.net/nunchakushuang/article/details/75294947