聲明:本文僅作技術交流,嚴禁用於任何非法用途(如有冒犯,請聯系我刪除此文)
自從開始js逆向后就停不下來,有閑時就想去看看別人的網站,既見多識廣,又享受解出來時的快樂。這次看的是市場份額發展飛快的拼多多手機版網頁
1.模塊作用
本demo目的是爬取http://mobile.yangkeduo.com/search_result.html?search_key=%E5%AD%A6%E7%94%9F%E6%96%87%E5%85%B7%E7%94%A8%E5%93%81%E7%AC%94通過xhr異步響應回來的信息。如下圖示例:
2.思路解析
1)需要參數尋找
首先說明:圖下這個url如果按照 首頁–打字–搜索 的步驟話會出現很多參數,但有效參數其實就只有search_key一個。所以我把其他多余的都刪了,這樣比較精簡(為啥說這個,因為后面有用)
行,我們還是來看看目標url的情況吧,如下圖:
headers沒啥說的,都挺正常。然后看params里面主要就是list_id、flip、anti_content三個參數不知道咋得出來的了
2)list_id、flip
仔細找一會兒的話會發現這倆參數其實是在主頁里面的
這個id名為__NEXT_DATA__的script標簽下一看起來就非常可疑,這個標簽下就有list_id和flip
3)anti_content
在找到了list_id和flip后就只剩一個anti_content參數了,是不是感覺勝利在望了?其實pdd在js上就只有這一個反爬措施而已。
行, 那就開始吧。
(1)找入口
將鼠標懸浮到加載過的js后能看到很長一串,一般都是隨便點一個,然后進去用上下棧慢慢找。
pdd的這個js是真的不好找,因為是異步執行的,調用上下棧能看到的參數是以異步前后分開的,所以耐心特別重要了。當然不是純看參數,有時候也可以搜,或者看看代碼英文對應的大概意思。
比如到這里的時候,這個getAntiContent那不就明擺着了嗎?然后讀一下riskController啥意思?不就是風險控制嗎。這連anti_content的大概意思都懂了,然后再看看到了case 4的情況:
這個時候我們需要的anti_content已經出來,那么就意味着在case 0到case 4之間他已經加密完成了,接下來就再一次在case 0到case 4之間一直按F11觀察情況了。然后按着按着就來到了這個js文件:
js文件名就叫RiskControl,這不明擺着么,不要猶豫,猶豫就會白給。然后多按幾下F11,這就是入口了:
ps:看了這么多的js,我感覺pdd的難度其實就在找入口這里,找入口花了我2個多小時,因為promise這個東西畢竟不太熟,還去補了一下,附上我當前補promise語法的網址:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
(2)逆js吧
先說一下:pdd的js用了N多語法丑化的混淆方式,其目的就是為了增大你的代碼閱讀量。當解起來的時候會出現很多開發中不可能出現的zz調用,但是我覺得這種來回調用在上下棧面前形同虛設,他故意為之,我們習慣就行。
舉個例子:上圖中的 t[g(“0xf2”, “1(8m”)](yt) 這個函數其實等於 yt()
行,我們直接就進入yt()吧,如下圖(yt太長,我截部分圖分兩張):
總說一下吧,yt()最后的return就是我們需要的anti_content,然后解的途中有兩個重要的節點,我標記出來了。
1的目的是獲取初始化參數r;
2的目的是以r為基礎參數,產生最后需要轉換成字符串的數組s。
然后中間的其他步驟都可以直接運行,比較簡單。
第一步:r
然后開始這個長的不行的3目運算符吧:
拉通看,他就是一個apply改變this對象,然后把生成的這些拼成一個數組,只是有mt,at,it,ut,ct,ft,ht,wt,lt,dt,_t,pt,xt。 13個變量,所以看起來很長,比較難看。語法本身挺簡單的,我覺得還行。
調用方式都一樣,就選一個看吧(就選這個ut吧):
一開始我說了進入主頁的url有用,其實用處就在ut這里了。由於他運行時自執行了init,而我摳的時候沒有(因為會用到好多window對象,所以就自己加上),所以我們需要逐個將上面13個變量附上data值。
首先進入ut.pack()會在這里,他分為兩部,再init一下,然后返回下面那一串。上面這個ut[g(“0x7a”, “KX$#”)]就是Init。L表示"data", q表示“href”, M表示"port", N表示window對象, j表示“location”。這個自己造就可以了----我這樣搞的:
把href_data定義在了全局最后以參數形式來改變值,因為不可能每次都請求一樣的東西吧。
然后是這個 rt([][E](l.es(“kf”), l.es(this[L][q]), l.es(this[L][M])))。這個時候需要去找這個l對象的生成地方。
然后隨便選個函數點過去,就是下圖了,從260行到651行的大函數里,自執行的匿名函數就是l產生的過程:
然后ut就可以運行完成了。沒啥跨作用域的問題,非常簡單。
就這樣逐個完成這些變量,最后r就出來了,整個過程沒啥難度,耐心即可。
然后一路向下都到第二個重點節點沒什么困難,除了這個h:
多點幾下就能知道,其實它簡單得一匹,我把它簡化了摳出來:
ps:途中有一個點我沒去搞明白它的意義, 就是下圖這個setTimeout,這里安個定時器是干啥的?知道的大佬可以講一下它的作用:
第二步:o
后面都差不多,我就只說一下幾個比較重要的函數吧。
點擊o[n[g(“0xd2”, “6Muc”)]],進入這個函數:
然后差啥補啥,比較麻煩的就是這個e.deflateInit2()
我就只截比較麻煩的地方了:Z(t),X(t)到這個a._tr_init(n),這里都是把函數所在的這個大函數截出來,自執行后綁定給一個變量就像一開始那個l對象一樣,就不再說了
這個l對象 new出來了,然后就下一步push一下吧:
其實這里也是一樣的操作方式,到這個e.deflate(s, o)的生成方式也是一樣的,雖然它這個函數很長,但是有點耐心就可以了。
如果第二步這個s生成了,基本就完了。
代碼可以參考我的antiContent_Js.py
3.檢測一下結果
先請求一下主頁
然后獲取主頁的list_id和flip,這里其實這個req_params就是除了flip和anti_content之外所有的參數了,非常方便,都不用自己寫了
然后就開始請求吧,這里有一個veriyAuthToken是第二個我沒有深入研究的地方,猜一下可能是pdd新加入的手機登錄或者驗證碼機制的校驗吧?有知道它作用的大佬可以點明一下。
這里我就只爬3頁試試了,一是因為我們只是學習一下別人的代碼,只解js,不搞服務器;二是爬多了肯定會出現手機驗證和圖片驗證碼的問題。
flip的值是根據上一頁返回回來的flip值來確定的,所以和anti_content一樣,每次都要變。不過好像就是20\40\60\80的等差規律吧,手動寫也可以。
最后把數據暫時到json文件里吧
出來了,應該沒有問題。
ps:發現一件有趣的事,我查看了一下,pdd的價格體系是按分計的啊,真是100個飛機呢,哈哈
4.總結
- 整個anti_content的破解,從開始找入口到解出來用了1天半,其中,大半天都用在了無用功上。因為我當時覺得第一步的r變量生成實在太簡單,沒有跨作用域,沒有特別的語法,很容易,然后膨脹了,想用逐個摳函數的方式解決第二步的o變量。最后不知道是那一步摳錯了,結果不對,導致重來。如果先搞清楚作用域的話,只花了2個小時就搞定了o,所以想起了高中數學老師的一句話:慢即是快啊;
- 以前解異步js比較少,通過pdd熟悉了一下promise的運作方式;
- 在我解的js中這個js的難度只能算中等(稍偏下吧)
附上github傳送門:https://github.com/634739726/pdd_yangkeduo_spider
最后,再次聲明,不要瞎搞請求,歡迎技術交流
來自:https://blog.csdn.net/weixin_44472296/article/details/92181707