破解有道翻譯反爬蟲機制


破解有道翻譯反爬蟲機制

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:簽名字符串。也是破解反爬蟲機制的關鍵點。

其他的數據類型暫時就不怎么重要了,都是固定寫法,我們后面寫代碼的時候直接鞋子就可以了。到現在為止,我們就可以寫一個簡單的爬蟲

二、破解反爬蟲機制:

我們可以多次的進行翻譯,並且每次翻譯后都去查看翻譯的時候發送的這個網絡請求,比較每次翻譯時候發送的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代碼,來對接他的接口了,以下是相關代碼:

from urllib import request,parse
# import requests
import json,time,random
import hashlib
def md5_jiami(str_data):
    md5_obj = hashlib.md5()
    sign_bytes_data = str_data.encode('utf-8')
    # 調用update()函數,來更新md5_obj值
    md5_obj.update(sign_bytes_data)
    # 返回加密后的str
    sign_str = md5_obj.hexdigest()
    return sign_str

def youdao(word):
    url='http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'
    salt = int(time.time() * 1000 + random.randint(0, 10))
    salt_str = str(salt)
    D = "ebSeFb%=XZ%T[KZ)c(sy!"
    S = "fanyideskweb"
    sign_str = S + word + salt_str + D
    # 調用加密的方法
    sign_md5_str = md5_jiami(sign_str)

    # print(salt)
    data={
        'i': word,
        'from': 'AUTO',
        'to': 'AUTO',
        'smartresult': 'dict',
        'client': 'fanyideskweb',
        'salt': salt_str,
        'sign': sign_md5_str,
        'doctype': 'json',
        'version': '2.1',
        'keyfrom': 'fanyi.web',
        'action': 'FY_BY_REALTIME',
        'typoResult': 'false',
    }
    new_data = parse.urlencode(data)
    headers = {
        # 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
        'Accept': 'application/json, text/javascript, */*; q=0.01',
        #'Accept-Encoding': 'gzip, deflate',
        'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
        'Connection': 'keep-alive',
        #'Content-Length': '223',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Cookie': 'OUTFOX_SEARCH_USER_ID=-493176930@10.168.8.63; OUTFOX_SEARCH_USER_ID_NCOO=38624120.26076847; SESSION_FROM_COOKIE=unknown; JSESSIONID=aaabYcV4ZOU-JbQUha2uw; ___rl__test__cookies=1534210912076',
        'Host': 'fanyi.youdao.com',
        'Origin': 'http://fanyi.youdao.com',
        'Referer': 'http://fanyi.youdao.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest',

    }
    req = request.Request(url=url,data=bytes(new_data,'utf-8'),headers=headers,method="POST")
    content = request.urlopen(req).read().decode('utf-8')
    strs_datas = json.loads(content)
    # print(strs_datas)
    print(strs_datas['translateResult'][0][0]['tgt'])
    # print(strs_datas['smartResult']['entries'])
    strings = ''
    for i in strs_datas['smartResult']['entries']:
        strings+=i
    print(strings)
if __name__ == '__main__':
    youdao(input("請輸入"))
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM