利用python爬虫(案例8)--今天就是吃X我也要搞到有道
學習筆記
備注:這個Blog也是part14
爬取有道
寫個案例,我想要破解有道翻譯(http://fanyi.youdao.com/)接口,抓取翻譯結果。
一開始,我還以為寫這個不是很麻煩,因為2年前玩網爬的時候,最先寫的小案例就是爬取翻譯結果。但是現在,我重新寫一遍,不知道為啥,研究了半天,心力交瘁,可能是人老了。
爬取步驟
①獲取要爬取的有道翻譯URL地址(http://fanyi.youdao.com/)
②在有道頁面中翻譯單詞,抓取數據包
③查看,并解析FROM表單
④敲python代碼,輸入要翻譯的內容,發送post請求
⑤得到翻譯結果
熟悉抓包
在正式開始抓包之前,我們先熟悉一下怎么抓包
備注:抓包(packet capture)就是將網絡傳輸發送與接收的數據包進行截獲、重發、編輯、轉存等操作,也用來檢查網絡安全。抓包也經常被用來進行數據截取等。
在Chrome瀏覽器中,進入抓包的網站(比如:有道), 開啟網絡抓包(右鍵打開審查元素–>點擊Network–>點擊All),與網站進行交互(比如:在有道中翻譯兔子一詞):
圖片中,被紅框框起來的部分,就是我們和有道交互的過程中產生的數據包。我們要進行網絡抓包,就是要從這么一大堆數據包里,找到有用的數據包。
我們再來分析一下各個選項:
【Headers選項】可以查看基本請求信息、我們提交的請求頭、響應頭和查詢參數。
如果該數據包是因為我們發送了POST請求而抓到的,那么它的Headers里會出現FROM表單信息:
【preview】選項可以進行預覽。我們通過預覽,可以判斷該數據包里有沒有包含我們想要的數據(預覽的數據經過了格式化):
【response】選項提供給我們,沒有經過任何修飾的網站響應(網站響應的源碼):
正式開始抓包
我們打開有道翻譯后,右鍵打開審查元素–>點擊Network–>點擊XHR(我們要的數據包主要在這里)–>在有道翻譯的頁面中,輸入Bunny, book, pen–>獲取數據包:
查看數據包的頭部信息:
可以看到,我們向 http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule發送請求,請求方式是POST請求。如果我們發送POST請求,則Headers中一定會有FORM表單數據(FROM Data),而服務端則會對我們發送的FROM表單進行驗證,如果表單驗證不通過,我們拿不到想要的返回結果。
解析FROM表單
現在我們仔細研究一下,這些FROM表單數據:
i:Bunny from:AUTO to:AUTO smartresult:dict client:fanyideskweb salt:15874435880336 sign:9010a72e07b45d70c18b3bc640006e27 ts:1587443588033 bv:cda24c3e62de8f471433417161b17a55 doctype:json version:2.1 keyfrom:fanyi.web action:FY_BY_REALTlME可以看到,參數i對應的應該是我們要翻譯內容,但是其他一堆堆的參數是啥呢???尤其是下面這些參數:
salt:15874435880336 sign:9010a72e07b45d70c18b3bc640006e27 ts:1587443588033 bv:cda24c3e62de8f471433417161b17a55這一堆堆的數字,看的眼花,好像毫無頭緒啊!
現在咋整呢?
我們之前不是抓了3個數據包么,那么咱就把每個數據包中FROM表單里的參數值都瞧上一瞧。看一看哪些參數的參數值沒有變化,那么我們就不處理它,哪些參數的參數值有變化,那我們就針對它。
我們看看 book和pen所對應的FROM表單:
i:book from:AUTO to:AUTO smartresult:dict client:fanyideskweb salt:15874437157104 sign:a4f482196c44b53e9f8dea18f18dd446 ts:1587443715710 bv:cda24c3e62de8f471433417161b17a55 doctype:json version:2.1 keyfrom:fanyi.web action:FY_BY_REALTlME i:pen from:AUTO to:AUTO smartresult:dict client:fanyideskweb salt:15874437391707 sign:f22542cea9aad0e1c1ca53ccc6093772 ts:1587443739170 bv:cda24c3e62de8f471433417161b17a55 doctype:json version:2.1 keyfrom:fanyi.web action:FY_BY_REALTlME對比這3個FROM表單,我們把參數值一樣的參數去掉,不一樣的留下:
i:pen salt:15874437391707 sign:f22542cea9aad0e1c1ca53ccc6093772 ts:1587443739170我們需要仔細研究一下這些參數的產生方式,或者說我們怎么才能獲取這些參數值。
我們已經知道,第一個參數i,它對應的是要翻譯的內容。
那其他參數呢,比如salt、sign、ts
當我們訪問有道翻譯網站時,服務端會給予我們響應,在響應中有很多JS文件,則salt、sign、ts這些參數的值,就是由這些JS文件生成的。所以,我們想要得到這些參數值,就要找到這些JS文件。
怎么找到這些JS文件呢?
我們可以刷新一下頁面,點擊審查元素–>Network–>JS,來尋找JS文件:
我們看到了一堆JS文件。
那這些文件里面,哪些使我們想要的JS文件呢?
我們可以在這些JS文件中,搜索From表單里出現的參數名。先搜索salt看看能得到些什么吧:
我們得到了一個JS文件,這個文件中有salt參數,我們在這個文件中繼續查找有沒有FROM表單里的其他參數(比如sign和ts)
我們在這個JS文件中, 找到了FROM表單里的參數ts、bv、salt、sign, 看看這些代碼(雖然看不懂),貌似是對參數進行某種md5加密, 還有生成隨機數,貌似還有時間戳?
這些是啥啊…喵的, 煩!
哎。。不管,好不容易有點頭緒,我們先把這些語句copy下來:
t = n.md5(navigator.appVersion) r = "" + (new Date).getTime() i = r + parseInt(10 * Math.random(), 10);ts: r, bv: t, salt: i, sign: n.md5("fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj")copy這些JS語句有啥用呢?
為的就是按照這些js語句的意思,用python的語法把FROM表單里的參數值重現出來。 呵呵!簡單粗暴。
那么我們如何弄明白這些JS語句的意思呢?
進行測試啊!來吧,拿起我們的小手手,在Console中一行一行代碼的研究這些JS語句是啥意思。
navigator.appVersion語句生成的東西和我們的User-Agent好像啊。我們驗證一下:
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36石錘了!navigator.appVersion語句可以生成User-Agent中Mozilla/后面的東西。這就是為啥bv參數不變的原因,因為我發起請求時的User-Agent一直沒變,所以用User-Agent進行md5加密得來的bv參數也不會變。
"" + (new Date).getTime()語句貌似可以拿到時間戳。
看來parseInt(10 * Math.random(), 10)語句貌似可以生成0到9的隨機數
好了,更關鍵的來了!現在我想要在Console中測試代碼"fanyideskweb" + e + i + "Nw(nmmbP%A-r6U3EUn]Aj",這貌似只是簡單的字符串拼接啊,有啥可看的。
是簡單的拼接沒錯,但是我它喵的不知道e是啥,這該咋辦!?
看那一坨坨的JS代碼,把e找出來?…對不起,我有點暈,臣妾做不到…那咋整?那就,斷點調試吧…咋調試呢?
我們在如下圖所示的8378行打一個斷點,并在有道頁面里輸入一些要翻譯的內容,比如English:
神奇的事情發生了!我們的屏幕上跳出了我想要的答案:e = “English”
通過斷點調試,我們知道了,這個e所代表的的就是我想要翻譯的內容。
敲代碼啦!
那么我們做了那么多現在可以敲python代碼了么?
可以!但咱是先別爬,咱們先把FROM表單里salt、sign、ts參數值,用python重現一下…MD…保持微笑.JPG
用python重現FROM表單參數值的代碼:
import time import random from hashlib import md5 ts = str(int(time.time()*1000)) salt = ts + str(random.randint(0,9))s = md5() e = input('輸入要翻譯的內容:') sign = "fanyideskweb" + e + salt + "Nw(nmmbP%A-r6U3EUn]Aj" s.update(sign.encode()) #update的參數為byte數據類型 md5_sign = s.hexdigest()現在可以爬了么???
不好意思,我還想介紹一下requests.post方法。
requests.post方法
請求有很多類別,比如有GET、POST、HEAD、PUT等等。現在,我們就是要用python的requests.post方法向服務端發起POST請求。一般,當我們向網站提交一定的信息,想得到反饋(比如,想要注冊賬號,英漢翻譯)時,就要用到POST請求。
- 語法
爬蟲啦
好了,現在我們開始爬吧.
python代碼:
# -*- coding: utf-8 -*-import requests import time import random from hashlib import md5 import jsonclass YoudaoSpider:def __init__(self):self.url = ' http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule'self.proxy = ['{}://117.88.176.93:3000','{}://117.88.177.153:3000','{}://60.188.77.31:3000']self.headers = {'Accept':'application/json, text/javascript, */*; q=0.01','Accept-Language':'zh-CN,zh;q=0.9','Connection':'keep-alive','Content-Length':'255','Content-Type':'application/x-www-form-urlencoded; charset=UTF-8','Cookie':'OUTFOX_SEARCH_USER_ID=-144954992@61.190.196.18; OUTFOX_SEARCH_USER_ID_NCOO=645870110.9638431; _ntes_nnid=75e99ed4fe9cecbb947a8df8ea8b8885,1526958441068; P_INFO=m18155501928; _ga=GA1.2.45220094.1586593751; JSESSIONID=aaa5TmtwK5mCi7b8j-Agx; SESSION_FROM_COOKIE=unknown; ___rl__test__cookies=1587469540366','Host':'fanyi.youdao.com','Origin':'http://fanyi.youdao.com','Referer':'http://fanyi.youdao.com/','User-Agent':'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'}def get_parameter(self, word):ts = str(int(time.time()*1000))salt = ts + str(random.randint(0,9))s = md5()sign = "fanyideskweb" + word + salt + "Nw(nmmbP%A-r6U3EUn]Aj"s.update(sign.encode())#update的參數為byte數據類型sign = s.hexdigest()return salt,sign,tsdef post_data(self, word):salt,sign,ts = self.get_parameter(word)formdata = {'i':word,'from':'AUTO','to':'AUTO','smartresult':'dict','client':'fanyideskweb','salt':salt,'sign':sign,'ts':ts,'bv':'cda24c3e62de8f471433417161b17a55','doctype':'json','version':'2.1','keyfrom':'fanyi.web','action':'FY_BY_CLICKBUTTION'}proxy = random.choice(self.proxy)proxies = {'http':proxy.format('http'),'https':proxy.format('https')}html_json = requests.post(url = self.url,data = formdata,headers = self.headers,proxies = proxies).json()#print(type(html_json))result = html_json['translateResult'][0][0]['tgt']print('翻譯結果:', result)def main(self):word = input('輸入要翻譯的內容:')self.post_data(word)if __name__ == '__main__':start = time.time()spider = YoudaoSpider()spider.main()end = time.time()print('執行時間:%.2f' % (end-start))控制臺輸出:
輸入要翻譯的內容:垂耳兔 翻譯結果: The loppy eared rabbit 執行時間:7.91后記:寫了這篇案例導致我想學CSS、JS和數據結構了,但還要復試。呵呵,說好的復試之前絕不寫案例呢?辣雞!
總結
以上是生活随笔為你收集整理的利用python爬虫(案例8)--今天就是吃X我也要搞到有道的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 测量重力的仪器是什么
- 下一篇: 《复杂》读书笔记(part1)--一些思