python爬蟲入門 ✦ 百度翻譯

此博客僅爲我業餘記錄文章所用,發佈到此,僅供網友閱讀參考,如有侵權,請通知我,我會刪掉。

打鐵趁熱,姊妹篇傳送門:python爬蟲入門 ✦ 某道翻譯

1.本文思路

1.先從抓包裏面Network—XHR裏面的formdata表單分析,需要獲取的參數爲sign和token。
2.複製sign或token關鍵字在右上角的search搜索,抓取相關的JS文件
3.將找到的 生成sign或token的函數代碼 直接保存到本地文件,利用execjs模塊執行js代碼,進行調試,從而找出規律
4.通過分析得出 sign和token的值在網頁源代碼可以請求得到。

1.1 分析url

本次文章鏈接爲 aHR0cHMlM0EvL2ZhbnlpLmJhaWR1LmNvbS8=(base64解密即可)
(1) 在某度翻譯頁面,點擊F12—Network—XHR,然後在輸入框輸入 student(任意輸入),查看抓包到的數據,可以看到一個名爲v2transapi的包,點擊它,查看Preview。確定了這個是我們最終需要獲取的數據包。下面就着手去獲取它。
在這裏插入圖片描述
(2) 接下來我們的移動到headers這裏,可以看到響應內容的url,該請求方法爲post,下面的畫框的Form_Data就是我們所需要的分析的表單內容啦。
在這裏插入圖片描述
在這裏插入圖片描述
(3) 來分析一下 student和teacher的Form_Data表單。
通過比對兩組表單數據,sign和token(token雖然不變,但是也找出來最好)是我們所需要獲取的數據。query則爲我們輸入需要的翻譯的單詞,接下來我們看一下如果獲取sign,token這兩個參數。

from: en	## student
to: zh
query: student
transtype: realtime
simple_means_flag: 3
sign: 767469.1005276
token: 3d154702e04333770e2c6be7c28b0d53
from: en	## teacher
to: zh
query: teacher
transtype: enter
simple_means_flag: 3
sign: 384259.81458
token: 3d154702e04333770e2c6be7c28b0d53

1.2 獲取js

(1) 點擊該頁面右上角,然後點擊search,會彈出下圖這個界面。然後再在搜索框輸入關鍵字 sign:,選擇彈出的第一個。最後點擊畫紅色框框的花括號,(它的作用是將代碼格式化,變得好看。)
在這裏插入圖片描述

(2) 因爲代碼很長,很難看懂。這個時候只有選擇打斷點 來分析一下。
可以看到,js代碼很長。 這裏的sign = 函數m(a),在下面劃紅框處,打上兩個斷點,然後再輸入框輸入任意單詞,查看現象。看到我們的函數值m(a)中的a就是我們所輸入的單詞
在這裏插入圖片描述
(3) 將鼠標輕輕移動到sign: m(a)這裏,可以看到會彈出一個 **f e(r)**的函數,鼠標左鍵點擊它。然後會跳轉到該js函數所在的代碼行。
在這裏插入圖片描述
(4) 仔細看一下這個圖片畫框的地方, 然後對比一下前面的 student 中的 sign:767469.1005276,下圖畫框的中間那個 “.” 對應的就是 sign的值中間的 "."
在這裏插入圖片描述
(5) 可是js代碼超長,看不懂。這個時候我們就需要將 與 sign相關的代碼塊複製下來,保存到本地。
在這裏插入圖片描述

1.3 解析js

(1) 將前面的那一串js代碼保存爲js格式的文件。
在這裏插入圖片描述
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
!!!!!
這個時候,解析js代碼的 execjs模塊要登場了!下面的代碼是execjs的簡單使用。

import execjs

# 打開剛纔保存的baidu.js的文件
with open('baidu.js', 'r') as f:
    js = f.read()

# 創建對象
js_data = execjs.compile(js)

# eval的作用是將字符串當成表達式來執行
sign = js_data.eval('e("student")')	#e是js代碼的函數e,student爲輸入的單詞
print(sign)

(2) ??? 報錯了?? 看了報錯內容爲 i未定義。這個時候就去 剛纔保存的baidu.js裏面找原因。
在這裏插入圖片描述
(3) 找 i,找 i, 找i。。因爲是i報錯了。!!!
看到 i了。這裏的 U = i = window[ l],而這個 l又等於i = “” “”+ String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107)。。這個時候將這一串編碼代碼複製到F12—source裏面看一下是什麼。
在這裏插入圖片描述
(4) 可以看到,我們複製過來的一串長長的編碼代碼,解碼後爲 gtk 所以我們的U = i = window[ gtk], 這個時候去網頁源代碼搜索一下window[ gtk]。在這裏插入圖片描述
(5) 可以看到window[ gtk]爲一串長長的數字320305.131321201,現在我們將這一串數字複製到 baidu.js裏面
在這裏插入圖片描述
(6) 因爲U = i = window[ gtk]=‘320305.131321201’,所以直接就將這串數字賦值給U
在這裏插入圖片描述
(7) 再次執行我們的代碼,嗯。有成功打印結果了!!!!!這一串打印出來的數字是不是很熟悉呢。。返回前面看一下,是不是和我們的 student的Form_Data裏面的sign值一樣呢!!好,那現在我們就成功解決了這個sign了,接下來就是獲取token了。

from: en	## student
to: zh
query: student
transtype: realtime
simple_means_flag: 3
sign: 767469.1005276
token: 3d154702e04333770e2c6be7c28b0d53

在這裏插入圖片描述
(8) 再次回到js代碼,看到token的值爲 window.common.token。好傢伙,我們就這一串代碼去網頁源代碼搜索一下看看。
在這裏插入圖片描述
(9) 看到token了。到了現在,我們的js分析已經完成了。代碼也相當於完成99%了!
在這裏插入圖片描述

2.完整代碼

import re
import execjs
import requests


class BaiuSpider(object):
    def __init__(self):
        self.base_url = 'https://fanyi.baidu.com'
        self.translate = 'https://fanyi.baidu.com/v2transapi'
        self.headers = {
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
            'accept-encoding': 'gzip, deflate, br',
            'accept-language': 'zh-CN,zh;q=0.9',
            'cache-control': 'max-age=0',
            'cookie': 'cookie填寫自己的',
            'referer': 'https://fanyi.baidu.com/',
            'upgrade-insecure-requests': '1',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
        }

    def get_token_gtk(self):
        res = requests.get(self.base_url, headers=self.headers).text
        token = re.findall("window.*?token: '(.*?)'", res, re.S)
        gtk = re.findall("window.gtk = '(.*?)';</script>", res, re.S)
        print(gtk[0], token[0])
        return token[0], gtk[0]

    def get_sign(self, word, token):
        with open('baidu.js', 'r') as f:
            js = f.read()
        js_data = execjs.compile(js)
        sign = js_data.eval('e("{}","{}")'.format(word, token))
        return sign

    def main(self, word, fro, to):
        token, gtk = self.get_token_gtk()
        sign = self.get_sign(word, gtk)
        form_data = {
            'from': fro,
            'to': to,
            'query': word,
            'transtype': 'realtime',
            'simple_means_flag': '3',
            'sign': sign,
            'token': token
        }
        res = requests.post(self.translate, data=form_data, headers=self.headers).json()
        # print(res)
        print(res['trans_result']['data'][0]['dst'])


if __name__ == '__main__':
    spider = BaiuSpider()
    choice = input("1.英譯漢  2.漢譯英:")
    word = input("請輸入你要翻譯的單詞:")
    if choice == '1':
        fro, to = 'en', 'zh'
    elif choice == '2':
        fro, to = 'zh', 'en'

    spider.main(word, fro, to)

文章很長,難免有出錯的地方,懇請各位爲我指正錯誤。
有不懂的地方歡迎在下方留言或一起討論。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章