难度: ★☆☆☆☆ 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日。