點擊上方關(guān)注 前端技術(shù)江湖,一起學(xué)習(xí),天天進(jìn)步
應(yīng)工作需要爬過各種各樣的航空公司網(wǎng)站,大到B2B平臺,小到東南亞某某航空官網(wǎng),從最初使用webdriver+selenium爬蟲到現(xiàn)在利用http請求解析html,經(jīng)歷過各種各樣的問題,webdriver+selenium這種辦法雖然萬能,而且可以用JS寫解析腳本方便調(diào)試,但是用久了才發(fā)現(xiàn)這玩意不管是效率還是穩(wěn)定性都非常差,放到服務(wù)器上動不動就掛掉,兩三天就需要重啟一次。后面頭說讓我們改用發(fā)http請求(我第一次接觸項目的時候就在想為什么不直接用發(fā)http請求這種方式,我猜他也是第一次接觸爬蟲這個技術(shù)領(lǐng)域,沒什么經(jīng)驗。而我,本來是招JAVA進(jìn)的公司,后來JAVA、JS、Python寫了個遍,emmm... 沒事,反正技多不壓身 ^_^),這種方式穩(wěn)定且快,但是用Python編寫解析腳本的時候你就知道進(jìn)行調(diào)試有多煩,雖然可以用PyQuery或者BeautifulSoup這種解析庫,但是還是不如寫JS腳本在瀏覽器里調(diào)試來得舒服。進(jìn)入爬蟲主題
要爬取的官網(wǎng):https://www.jcairlines.com
接口地址:https://www.jcairlines.com/TicketSale/FlightQuery/QuerySeat
目標(biāo):根據(jù)參數(shù)爬取對應(yīng)的航班信息
請求信息:

響應(yīng)結(jié)果:

接口測試
從上面的第一張圖可以看到有一個類似加密過的參數(shù):HashCode,而其他的都是根據(jù)需要進(jìn)行直接填充
{"DepartureIataCode":"TPE","ArrivalIataCode":"PNH","FlightDate":"2018-08-24","RouteIndex":"0","TravelType":"OW","HashCode":"8b112088f6966ea42507d0daff86a1d1"}下面將這個請求的完整信息放到Postman中跑一下,看看結(jié)果:

可以看到是沒有問題的,能拿到結(jié)果,下面我們準(zhǔn)備把HashCode去掉再請求一遍

emmm... 直接不響應(yīng)!!!
好吧,搞定這個問題就需要破解這個加密參數(shù)是怎么來的
正式破解
【逆向思維】這個肯定是Ajax請求之前生成的,那就用關(guān)鍵字找這個Ajax請求, 在Chrome中開發(fā)者模式,找到這網(wǎng)站的所有Source

【關(guān)鍵字】"QuerySeat" 一大堆js文件一個一個找吧,運氣很好,第一個就是,可以清楚的看到“POST”一詞,那這一定就是一個Ajax請求咯,這里有一個技巧,一般情況下,服務(wù)器會對靜態(tài)資源進(jìn)行壓縮,所以需要format才能看個大概


這樣可以閱讀代碼了,然后輕松找到設(shè)置HashCode的地方,然后打一個斷點,隨便查一條航線的數(shù)據(jù),如下圖。

單步執(zhí)行走到這一步,有些眉目了,執(zhí)行到了encode指向的匿名函數(shù)這,里面代碼看似應(yīng)該是各種加密函數(shù),不用讀懂它,因為目標(biāo)只是執(zhí)行它,得到相應(yīng)的結(jié)果就行了

繼續(xù)單步:

繼續(xù)...

上圖中重要的源碼:
return e = OOO0.excess.indexOf("Chrome") >= 0 ? "cv3sdf@#$f3" : OOO0.excess.indexOf("Firefox") >= 0 ? "df23Sc@sS" : "vdf@s4df9sd@s2"返回到上層,沒錯和我想的一樣,當(dāng)前瀏覽器是Chrome,返回的是 cv3sdf@#$f3

繼續(xù)...

繼續(xù)...

繼續(xù)...

最終找到了這個匿名函數(shù),復(fù)制encode所指向的函數(shù),然后隨便取一個名字,方便調(diào)用,另外,在另一個窗口中打開Console粘貼代碼,如下圖:

調(diào)用...(報錯了)

替換成對應(yīng)的字符串繼續(xù)...

重新調(diào)用注入到Console 的encode函數(shù),調(diào)用,得到結(jié)果!!!

對比最開始用Postman請求的地方,結(jié)果也一致!!!
還沒有完,這里只是得到了js腳本,所以還需嵌入到Python代碼中使用,常規(guī)方式有兩種:使用Python第三方類庫js2py和PyV8這兩個都是能都執(zhí)行js的Python類庫,但是我還是推薦使用js2py,因為PyV8安裝十分繁瑣,具體使用我就不再贅述,網(wǎng)上有很多的教程和Case。
最后需要交代的:“sfei#@%%”這的到底是哪來的,也沒有尋根,我就直接告訴答案,其實這個值就在當(dāng)前的網(wǎng)頁中,是一個js變量,且是一個固定值,這也是我不想尋根的原因,意義不大。另外在使用http爬蟲的時候headers里面的內(nèi)容也必須和HashCode相匹配,什么意思呢,之前代碼出現(xiàn)過通過瀏覽器種類,生成不同的字符串,也就是說具體HashCode是和瀏覽器有關(guān),所以在構(gòu)造headers時需要填寫對應(yīng)的User-Agent,不然服務(wù)器進(jìn)行校驗的時候還是不會響應(yīng)的,可以猜測服務(wù)器中也有一段功能相同的代碼,它根據(jù)請求參數(shù)和headers中User-Agent進(jìn)行加密計算,得到HashCode以此來驗證請求的HashCode是否合法。
總結(jié)
前端加密還是能夠破解出來的,關(guān)鍵在于鎖定JS加密源碼位置,并且提取出有用的加密代碼,只要有使用過js的同學(xué)問題都不大。還有很多小細(xì)節(jié)得注意,服務(wù)器需要對請求做進(jìn)一步驗證,方式其實和前端是一樣的以此來判斷請求是否合法,至少這個網(wǎng)站是如此。
The End
歡迎自薦投稿到《前端技術(shù)江湖》,如果你覺得這篇內(nèi)容對你挺有啟發(fā),記得點個 「在看」哦
點個『在看』支持下 