難度: ★☆☆☆☆ 1星
一、目標
目標網站:
這算是一個列表頁,展示了一些小區,然后單擊小區跳轉到小區詳情,但是跳轉鏈接被加密了,是通過JS算出來的:

本篇文章的目標就是破解這個加密。
二、分析
上一小節的圖里可以看到,在單擊鏈接的時候綁定了一個事件reurl,在開發者工具的console上輸入reurl並回車:

拿到代碼:
function reurl(a) {
a.href = "/item/" + recode(a.id)
}
可以看到在這里修改了鏈接的地址,用到了鏈接里的一個id屬性:
<a id="2714" style="cursor:pointer" onclick="reurl(this)" target="_blank" title="清樾園">清樾園</a>
同時id的解密還依賴了recode,同樣的套路拿到它的代碼:
function recode(a) {
var n = nscaler(a);
var c = SetObjNum(String(a).length);
var d = SetObjNum(String(a).length);
n = parseInt(n) + parseInt(d);
var b = $("#iptstamp").val();
b = nscaler(b.toString());
return c + "-" + n + "-" + d + "-" + b
}
這個方法中依賴了兩個方法和一個dom元素,先看nscaler,用同樣的方法從console跟進去拿到它的代碼:
function nscaler(a) {
var b = "";
var ar = String(a).split('');
$.each(ar, function (i, e) {
switch (e) {
case "0":
b += "0";
break;
case "1":
b += "2";
break;
case "2":
b += "5";
break;
case "3":
b += "8";
break;
case "4":
b += "6";
break;
case "5":
b += "1";
break;
case "6":
b += "3";
break;
case "7":
b += "4";
break;
case "8":
b += "9";
break;
case "9":
b += "7";
break
}
});
return b
}
從邏輯上看,這個方法是將字符串使用一個映射表映射為一個新的值:
{
0: 0,
1: 2,
2: 5,
3: 8,
4: 6,
5: 1,
6: 3,
7: 4,
8: 9,
9: 7,
}
然后是SetObjNum,從console跟進去拿到源碼,注意到跟進去的時候tab的標題是VMxxx格式的,說明可能是eval定義的:
function SetObjNum(n) {
var a = "";
for (var i = 0; i < n; i++) a += Math.floor(Math.random() * 10);
return a
}
這個方法就是生成一個隨機數,然后是$("#iptstamp").val();,在頁面源代碼:
view-source:http://60.173.254.126/
中搜索iptstamp可以找到,這就是服務器返回的一個時間戳:

至此,所有邏輯已經捋清楚,接下來就是編碼實現。
三、編碼實現
#!/usr/bin/env python3
# encoding: utf-8
"""
@author: CC11001100
"""
import random
import requests
from bs4 import BeautifulSoup
def crawl():
url = "http://60.173.254.126/"
html = requests.get(url).text
doc = BeautifulSoup(html, features="html.parser")
iptstamp = doc.select_one("#iptstamp")["value"]
r = {}
for x in doc.select("a[id][onclick][title][style]"):
id = x["id"]
link = "http://60.173.254.126/item/" + recode(id, iptstamp)
title = x["title"]
r[title] = link
return r
def recode(s, iptstamp):
n = nscaler(s)
c = set_obj_num(len(n))
d = set_obj_num(len(n))
n = int(n) + int(d)
b = nscaler(iptstamp)
return str(c) + "-" + str(n) + "-" + str(d) + "-" + str(b)
def set_obj_num(n):
r = 0
for _ in range(0, n):
r += int(random.random() * 10)
return r
def nscaler(s):
mapping = {
0: 0,
1: 2,
2: 5,
3: 8,
4: 6,
5: 1,
6: 3,
7: 4,
8: 9,
9: 7,
}
result = 0
for x in s:
result = result * 10 + mapping[int(x)]
return str(result)
if __name__ == "__main__":
print(crawl())
運行效果:

經驗證無誤。
倉庫:
請注意爬蟲文章具有時效性,本文寫於2020-11-25日。
