第一次寫技術(shù)文章盒让,有點(diǎn)小緊張泪幌,小興奮。這兩天想著好好運(yùn)用一下剛學(xué)到的requests和bs4來爬蟲,網(wǎng)上找了個小爬蟲項(xiàng)目,就是爬蟲實(shí)現(xiàn)有道翻譯片部。一開始以為很簡單,結(jié)果斷斷續(xù)續(xù)用了挺長時間霜定,主要是有道的反爬蟲機(jī)制在提升档悠,所以參考的那篇博客寫的時候可能有道還沒有用什么反爬蟲吧,所以經(jīng)過自己的搗鼓以及參考了第二個博客現(xiàn)在終于實(shí)現(xiàn)了望浩,還是很開心站粟,謝謝自己堅(jiān)持下來,學(xué)到了不少東西曾雕,和大家分享一下吧。
首先說明一下用到的工具:火狐瀏覽器的Web開發(fā)者的network工具助被,用它我們可以清楚看到我們在有道上查一個單詞或者詞語的時候發(fā)出和收到的HTTP/HTTPS請求和響應(yīng)內(nèi)容剖张,這個是我們實(shí)現(xiàn)爬蟲的基礎(chǔ),用來我們構(gòu)造請求頭以及確定我們用get方法還是post方法揩环,在這里呢通過看請求頭發(fā)現(xiàn)查詢用的是post方法搔弄,那么呢,我們還需要這個工具來構(gòu)造我們的提交內(nèi)容丰滑,這里是整個爬蟲能不能實(shí)現(xiàn)顾犹,也是破解有道反爬蟲的關(guān)鍵倒庵,會在下面詳細(xì)說!l潘ⅰG姹Α!浑玛!
我們先看一下我查一個單詞用火狐的network工具得到的內(nèi)容吧
箭頭1處绍申,是我們構(gòu)建爬蟲的URL,2處我們得到使用的方法是Post,再通過3確定要提交的是表單顾彰,我們根據(jù)請求頭的格式構(gòu)造我們自己的請求頭极阅,4這里我們構(gòu)建請求頭時要特別注意,每次查詢時Cookie的值都不同涨享,下面細(xì)講
上圖是我們構(gòu)造表單內(nèi)容需要的格式筋搏,箭頭5,6這里就是反爬蟲的機(jī)制厕隧,也是我們代碼能否實(shí)現(xiàn)的關(guān)鍵奔脐,也下面講如何確定salt、sign的值栏账。
現(xiàn)在開始介紹如何確定構(gòu)造cookie帖族,salt,以及sign的值吧挡爵,使用的工具依然是network竖般,它的堆棧跟蹤,如下圖
我們點(diǎn)箭頭指的鏈接跳到下圖:
然后為了更好的研究把箭頭指的內(nèi)容我們用站長工具h(yuǎn)ttp://tool.chinaz.com/tools/jsformat.aspx來更好的顯示茶鹃。
搜索到salt涣雕,可以看到下面一段js代碼
t.translate = function(e, t) {
? ? ? ? T = u("#language").val();
? ? ? ? var n = b.val(),
? ? ? ? r = "" + ((new Date).getTime() + parseInt(10 * Math.random(), 10)),
? ? ? ? o = u.md5(S + n + r + D),
? ? ? ? a = n.length;
? ? ? ? if (L(), w.text(a), a > 5e3) {
? ? ? ? ? ? var l = n;
? ? ? ? ? ? n = l.substr(0, 5e3),
? ? ? ? ? ? o = u.md5(S + n + r + D);
? ? ? ? ? ? var c = l.substr(5e3);
? ? ? ? ? ? c = (c = c.trim()).substr(0, 3),
? ? ? ? ? ? u("#inputTargetError").text("有道翻譯字?jǐn)?shù)限制為5000字,“" + c + "”及其后面沒有被翻譯!").show(),
? ? ? ? ? ? w.addClass("fonts__overed")
? ? ? ? } else w.removeClass("fonts__overed"),
? ? ? ? u("#inputTargetError").hide();
? ? ? ? f.isWeb(n) ? i() : s({
? ? ? ? ? ? i: n,
? ? ? ? ? ? from: _,
? ? ? ? ? ? to: C,
? ? ? ? ? ? smartresult: "dict",
? ? ? ? ? ? client: S,
? ? ? ? ? ? salt: r,
? ? ? ? ? ? sign: o,
? ? ? ? ? ? doctype: "json",
? ? ? ? ? ? version: "2.1",
? ? ? ? ? ? keyfrom: "fanyi.web",
? ? ? ? ? ? action: e || "FY_BY_DEFAULT",
? ? ? ? ? ? typoResult: !1
? ? ? ? },
? ? ? ? t)
? ? },
? ? t.showResult = a
}),
可以看出salt闭翩,sign的值分別為r挣郭,o,在上面我已經(jīng)加粗顯示疗韵,r就是系統(tǒng)當(dāng)前時間戳加上一個1到10之間的隨機(jī)整數(shù)兑障,o是一個獲取S + n + r + D字符串的md5值(這個可以百度一下),所以python代碼中我們需要用到time蕉汪,random以及hashlib(獲取S + n + r + D字符串的md5值)這些庫流译。S的值可以看到對應(yīng)的是請求報文中的client值fanyideskweb,n是查詢的內(nèi)容者疤,r就是salt福澡,D我們也可以通過查看js腳本找到它對應(yīng)的值為ebSeFb%=XZ%T[KZ)c(sy!
這樣之后我們的表單就可以構(gòu)建好了,但我們在查詢不同內(nèi)容的時候驹马,請求頭里的cookie也是不同的革砸,所以我們還需要找到cookie值的構(gòu)造規(guī)律除秀,這個是在v1.js這個腳本中找到的如下圖
同樣的,我們用站長工具搜索Cookie找到如下代碼:
可以看到cookie最后一串?dāng)?shù)字其實(shí)就是系統(tǒng)當(dāng)前的時間戳算利。
好嘍册踩,找到salt、sign笔时、Cookie后我們就已經(jīng)要成功了棍好,可以附上我的代碼嘍,不知道怎么把代碼很好的展示出來允耿,我就直接粘貼過來吧借笙。。较锡。對了业稼,還有一件事情要說,就是URL的值我是就直接用的請求頭里的URL的蚂蕴,只要把salt低散、sign和Cookie成功構(gòu)造好,就不會出現(xiàn)網(wǎng)上的那些錯誤骡楼,也不需要去掉_o
import requests
from bs4 import BeautifulSoup
import json
import time
import random
import hashlib
def crawl_youdao():
??? while True:
??????? content =raw_input('請輸入要查詢的單詞/詞語(輸入0退出翻譯):')
??????? d = content
??????? if content == '0':
??????????? print('歡迎下次使用!')
??????????? break
??????? url = 'http://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule '
??????? ctime=int(time.time()*1000)#H酆拧!鸟整!
??????? headers = {
??????????? 'Accept': 'application/json, text/javascript, */*; q=0.01',
??????????? 'Accept-Encoding':'gzip, deflate',
??????????? 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
??????????? 'Cache-Control': 'no-cache',
??????????? 'Connection': 'keep-alive',
??????????? 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
??????? #R鳌!篮条!
??????????? 'Cookie':'YOUDAO_MOBILE_ACCESS_TYPE=1; OUTFOX_SEARCH_USER_ID=-1289760786@10.168.8.76; OUTFOX_SEARCH_USER_ID_NCOO=939708194.3484184; _ntes_nnid=3261dca1448d041f16596bf4942976dd,1524295653112; JSESSIONID=aaaWj8T4yP2lIcfjqeSlw; ___rl__test__cookies='+str(ctime),
??????????? 'Host': 'fanyi.youdao.com',
??????????? 'Pragma': 'no-cache',
??????????? 'Referer': 'http://fanyi.youdao.com/',
??????????? 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0',??
??????????? 'X-Requested-With': 'XMLHttpRequest'
??????????? }
??????? salt=str(ctime+random.randint(1,10))#5芡贰!涉茧!
??????? sign = hashlib.md5("fanyideskweb" + content + salt + "ebSeFb%=XZ%T[KZ)c(sy!").hexdigest()#8昂蕖!0樗ā伦连!
??????? data={
??????????? 'from':'AUTO',
??????????? 'to':'AUTO',
??????????? 'smartresult':'dict',
??????????? 'client':'fanyideskweb',
??????????? 'doctype':'json',
??????????? 'version':'2.1',
??????????? 'keyfrom':'fanyi.web',
??????????? 'action':'FY_BY_REALTIME',
??????????? 'typoResult':'true',
??????????? 'i':content,
??????????? 'salt': salt,
??????????? 'sign':sign?????
??????? }
??????? res = requests.post(url,params =data, headers=headers)
??????? soup = BeautifulSoup(res.text,'lxml')
??????? jd = json.loads(soup.text)
??????? #print soup.text
??????? #print jd
??????? print('翻譯結(jié)果:')
???
??????? for translate in jd['smartResult']['entries']:
?????????? print(translate)
??????? print('\n')
if __name__=='__main__':
??? crawl_youdao()
然后然后就是看看我的程序運(yùn)行結(jié)果吧,終于實(shí)現(xiàn)了钳垮,好開心啊除师,開心到飛起~~~,寫出來和大家分享一下我內(nèi)心的喜悅~~~~~
特別感謝:https://blog.csdn.net/shadkit/article/details/79174948