python攜程爬蟲之逆向混淆js
前言
那些年攜程工程師在程式碼裡下的毒-反爬與反反爬的奇技淫巧
知乎上面的專欄,寫出了逆向找到攜程的Eleven
引數來偽裝瀏覽器傳送ajax,獲取攜程的酒店房型列表。然而文章並沒有給出全部的思路,我們獲取到的頁面內容內容是醬紫的:
所以沒辦法,只能自己擼出來,看看到底是怎麼加密的。
DEBUG
首先還是檢視ajax請求網址時
http://hotels.ctrip.com/Domestic/tool/AjaxHote1RoomListForDetai1.aspx?psid=&MasterHotelID=441351&hotel=441351&EDM=F&roomId=&IncludeRoom=&city=2&showspothotel=T&supplier=&IsDecoupleSpotHotelAndGroup=F&contrast=0&brand=0&startDate=2017-08-28&depDate=2017-08-29&IsFlash=F&RequestTravelMoney=F&hsids=&IsJustConfirm=&contyped=0&priceInfo=-1&equip=&filter=&productcode=&couponList=&abForHuaZhu=&defaultLoad=T&TmFromList=F&eleven=c4350e460862b69d9d76724e1325a0a54ef23c2e0648636c855a329418018a85&callback=CASuBCgrghIfIUqemNE&_=1503884369495
$.ajax(o, {
onsuccess: function(e) {
window[n](e.responseText)//
},
onerror: function() {
window[n] = void 0,
r()
}
}
而執行函式的時候傳入的引數就是我們剛剛ajax得到的的json內容。我們打上斷點後可以發現e.responseText
為訪問頁面得到的json轉化而成字串。
而window[n]
方法就在上方
window[n] = function(e) {
window[ n] = void 0;
var i = ["T", "F", "e", "s", "M", "a", "g", "r", "o", "B", "u", "l", "y", "m", "f", "t"];
e = $.parseJSON(e),
null == e ? r() : (hotelDomesticConfig.cas.Pretty && e["0|2|3|15|4|2|3|3|5|6|2|1|7|8|13|9|10|15|15|2|7|14|11|12".split("|").map(function(e) {
return i[e]
}).join("")].slice(-9999).indexOf(" ") !== -1 ? e.html = "" : !l && hotelDomesticConfig.cas.decrypt && (e.html = t(e.ComplexHtml, e.ASYS, e.html)),
s(e)),
$('script[src="' + o + '"]').remove()
}
我們在return i[e]
和 $('script[src="' + o + '"]').remove()
處打上斷點。執行的時候直接跳過了return i[e]
,我們再看一下各變數的值。
e
原本為傳入的e.responseText
的值,既字串,如今變成了一個物件,瀏覽一下他的屬性。發現有一個html的屬性,內容如下:
↵<div class="htl_room_table J_roomTable">↵
<table border="0" cellspacing="0" cellpadding="0" summary="詳情頁酒店房型列表" id="J_RoomListTbl">↵
<tr>↵
<th class="col1" style="padding-left:10px;">房型</th>↵
<th class="col2"></th>↵
<th class="col3">床型</th>↵
<th class="col5">寬頻</th>↵
<th class="col_person">入住人數</th>↵
</i><p>沒有符合條件的房型,您可以減少當前篩選項或<a id="J_ShowAllRoomList" href="javascript:void(0);">檢視全部房型</a>!</p></td>↵</script>
由於太長我沒有吧全部程式碼放出來。可以看出,這裡就是我們想要的結果。
於是我排查了window[n]
裡的每一個句子,找到了(e.html = t(e.ComplexHtml, e.ASYS, e.html)
,其中e.ComplexHtml
以及e.ASYS
就是ajax
得到的兩個奇形怪狀的欄位,
跳轉到t
函式。
function t(e, t, o) {
var i = "";
if ("function" != typeof NODEJS)
return "";
if ("undefined" == typeof e)
return "";
if (!e)
return "";
try {
i = NODEJS(e, t)
} catch (n) {
i = ""
}
return i
}
return i
的時候,i
已經是html的字串了。所以我們可以判斷就是在方法名為NODEJS
之中完成的解密。
NODEJS = function(n, t) {
var r, o, e = "1", i = void 0 == e[0], c = i ? [] : "";
for (r = 0; r < n.length; r++)
o = t.charAt(n.charAt(r).charCodeAt(0) - 21760).charAt(0),
i ? c.push(o) : c += o;
return c = i ? c.join("") : c
}
把上面的函式e.ComplexHtml
和e.ASYS
丟到node
中執行,結果出來的就是html的字串。
撒花完結
##總結
寫了個python版本的,丟:
def decrypt(n, t):
c = ""
for i in n:
try:
o = t[ord(i) - 21760]
except:
o = ""
c = c + o
return c