1. 程式人生 > >Python(4) 用Python破解有道翻譯反爬蟲機制

Python(4) 用Python破解有道翻譯反爬蟲機制

web端的有道翻譯,在之前是直接可以爬的。也就是說只要獲取到了他的介面,你就可以肆無忌憚的使用他的介面進行翻譯而不需要支付任何費用。那麼自從有道翻譯推出他的API服務的時候,就對這個介面做一個反爬蟲機制(如果大家都能免費使用到他的翻譯介面,那他的API服務怎麼賺錢)。這個反爬蟲機制在爬蟲領域算是一個非常經典的技術手段。那麼他的反爬蟲機制原理是什麼?如何破解?接下來帶大家一探究竟。

一、正常的爬蟲流程:

如果你要爬取他的翻譯介面,這個流程還是不能少的。首先我們開啟有道翻譯的連結:http://fanyi.youdao.com/。然後在頁面中右鍵->檢查->Network項。這時候就來到了網路監聽視窗,以後你在這個頁面中傳送的所有網路請求,都會在Network

這個地方顯示出來。接著我們在翻譯的視窗輸入我們需要翻譯的文字,比如輸入hello。然後點選自動翻譯按鈕,那麼接下來在下面就可以看到瀏覽器給有道傳送的請求,這裡截個圖看看:


01.png

在上圖,我們可以看到傳送了很多的網路請求,這裡我們點選第一個網路請求進行檢視:


02.png

可以看到,我們在點選自動翻譯的時候,傳送的請求就是上圖中Request URL的那個URL,然後我們再點選那個Response,我們可以看到返回的結果:


03.png

並且,現在我們再回到Headers

的地方,然後滾動到最下面,可以看到有一個Form Data的地方,這個下面展示了許多的資料,這些資料就是你在點選翻譯的時候瀏覽器給伺服器傳送的資料:


04.png

對其中幾個比較重要的資料進行解釋:

  • i:需要進行翻譯的字串,這個地方我們輸入的是hello。
  • salt:加密用到的鹽。這個是我們破解有道反爬蟲機制的關鍵點,後面會講到。
  • sign:簽名字串。也是破解反爬蟲機制的關鍵點。

其他的資料型別暫時就不怎麼重要了,都是固定寫法,我們後面寫程式碼的時候直接鞋子就可以了。到現在為止,我們就可以寫一個簡單的爬蟲,去呼叫有道翻譯的介面了。這裡我們使用的網路請求庫是Python3

自帶的urllib,相關程式碼如下:

# 匯入需要的庫
import urllib.request
import urllib.parse
import json

# 等待使用者輸入需要翻譯的單詞
content = input('請輸入需要翻譯的單詞:')

# 有道翻譯的url連結
url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=null'

# 傳送給有道伺服器的資料
data = {}

# 需要翻譯的文字
data['i'] = content
# 下面這些都先按照我們之前抓包獲取到的資料
data['from'] = 'AUTO'
data['to'] = 'AUTO'
data['smartresult'] = 'dict'
data['client'] = 'fanyideskweb'
data['salt'] = '1500349255670'
data['sign'] = '997742c66698b25b43a3a5030e1c2ff2'
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['action'] = 'FY_BY_CL1CKBUTTON'
data['typoResult'] = 'true'

# 對資料進行編碼處理
data = urllib.parse.urlencode(data).encode('utf-8')

# 建立一個Request物件,把url和data傳進去,並且需要注意的使用的是POST請求
request = urllib.request.Request(url=self.url, data=data, method='POST')
# 開啟這個請求
response = urllib.request.urlopen(request)
# 讀取返回來的資料
result_str = response.read().decode('utf-8')
# 把返回來的json字串解析成字典
result_dict = json.loads(result_str)

# 獲取翻譯結果
print('翻譯的結果是:%s' % result_dict)

我們執行這個檔案後,當我們輸入的是hello的時候,我們可以得到哈羅的這個正確的翻譯結果。而當我們輸入其他需要翻譯的字串的時候,比如輸入i love you,那麼就會得到一個錯誤程式碼{"errorCode":50}。這就奇怪了,有道詞典不可能只能翻譯一個英文單詞吧。而這個,就是有道詞典的反爬蟲機制。接下來我們就來破解有道詞典的反爬蟲機制。

二、破解反爬蟲機制:

我們可以多次的進行翻譯,並且每次翻譯後都去檢視翻譯的時候傳送的這個網路請求,比較每次翻譯時候傳送的Form Data的值。我們注意到,Form Data在每次傳送網路請求的時候,只有isalt以及sign這三個是不同的,其他的資料都是一樣的,這裡我用helloworld兩個單詞翻譯時候Form Data的資料進行比較:


05.png
06.png

圖中的Form Data也證實了我剛剛所說的,就是除了isalt以及sign是不一樣的。其餘都是一樣的。而i不一樣是很正常的。因為i代表的是要翻譯的字串,這個不同是很正常。而saltsign這兩個東西不一樣,是怎麼產生的呢?這裡我們可以分析一下,這兩個值在每次請求的時候都不一樣,只有兩種情況:第一是每次翻譯的時候,瀏覽器會從有道伺服器獲取一下這兩個值。這樣可以達到每次翻譯的時候值不同的需求。第二是在本地,用JS程式碼按照一定的規則生成的。那麼我們首先來看第一個情況,我們可以看到在每次傳送翻譯請求的時候,並沒有一個請求是專門用來獲取這兩個值的:


07.png

所以就可以排除第一種情況。就只剩下一種可能,那就是在本地自己生成的,如果是在本地自己生成的,那麼規則是什麼呢?這裡我們點選網頁,檢視網頁原始碼,查詢所有的JS檔案,我們找到那個fanyi.js


08.png

然後點選這個檔案,跳轉到這個原始檔中,然後全選所有的程式碼,複製下來,再開啟站長工具:http://tool.chinaz.com/Tools/jsformat.aspx。把程式碼複製進去後,點選格式化:


09.png

然後把格式化後的程式碼,複製下來,用sublime或者pycharm開啟都可以,然後搜尋salt,可以找到相關的程式碼:


10.png

這裡我們就可以發現所有的值的生成原理了。這裡來做個簡介:

  • d:代表的是需要翻譯的字串。
    • f:當前時間的時間戳加上0-10的隨機字串。
    • u:一個常量——fanyideskweb
    • c:一個常量——rY0D^0'nM0}g5Mm1z%1G4
    • salt:就是f變數,時間戳。
    • sign:使用的是u + d + f + cmd5的值。

知道saltsign的生成原理後,我們就可以寫Python程式碼,來對接他的介面了,以下是相關程式碼:

import urllib.request

import urllib.parse
import json
import time
import random
import hashlib

content = input('請輸入需要翻譯的句子:')

url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule&sessionFrom=https://www.google.com/'

data = {}

u = 'fanyideskweb'
d = content
f = str(int(time.time()*1000) + random.randint(1,10))
c = 'rY0D^0\'nM0}g5Mm1z%1G4'

sign = hashlib.md5((u + d + f + c).encode('utf-8')).hexdigest()

data['i'] = content
data['from'] = 'AUTO'
data['to'] = 'AUTO'
data['smartresult'] = 'dict'
data['client'] = 'fanyideskweb'
data['salt'] = f
data['sign'] = sign
data['doctype'] = 'json'
data['version'] = '2.1'
data['keyfrom'] = 'fanyi.web'
data['action'] = 'FY_BY_CL1CKBUTTON'
data['typoResult'] = 'true'

data = urllib.parse.urlencode(data).encode('utf-8')
request = urllib.request.Request(url=url,data=data,method='POST')
response = urllib.request.urlopen(request)

print(response.read().decode('utf-8'))

寫在最後:

像以上這種,通過用JS在本地生成隨機字串的反爬蟲機制,在爬蟲的時候是經常會遇到的一個問題。希望通過以上的講解,能為大家提供一種思路。以後再碰到這種問題的時候知道該如何解決。這樣本篇文章的目的也就達到了。如果您想深入學習Python爬蟲和資料分析。可以看下這個課程,講解很仔細,你一定不會失望的:21天搞定Python分散式爬蟲