python爬虫简单js逆向(破译js)
python爬虫简单js逆向(破译js)内容简介一、找到包含所需数据的ajax数据包二、通过浏览器工具进行关键字定位三、分析相关js文件,找出具体实现方式1、getApiKey()函数2、encryptApiKey()函数3、encryptTime()函数4、comb()函数5、查找不一致的原因...
注:本文为转载,转载自思不歌qwq
目录
python爬虫简单js逆向案例
由于学习任务需要用爬虫获取数据,学习了python爬虫的基础知识。
但是在开始写爬虫程序的时候就出现了问题,现将解决方式记录如下。
内容简介
需求:爬取某金融区块链网站 https://www.oklink.com/btc/tx-list的数据。
出现问题:爬取数据首先需要发送请求,得到响应数据 。通过网页分析可知,需要获取的数据来自ajax动态加载,所以我选择通过向ajax的 url 发送请求得到响应数据。请求的请求头中参数是需要解决的首要问题。但是请求到数据的ajax请求头中包含类似如下动态变化且加密的参数
xapiKey:LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3MTk0ODY0MDUwNzA2Mjk=
解决办法:通过分析浏览器请求到的相关js文件,得到x-apiKey的生成函数,并用python复写(可以不用复写,通过调用python中相关的js库也可执行js代码)。
一、找到包含所需数据的ajax数据包
1.打开网站,快捷键Ctrl+shift+I打开浏览器工具,选择Network->XHR,刷新网页,可以看到只有一个请求数据包:
2.打开之后可以找到请求的url:
https://www.oklink.com/api/explorer/v1/btc/transactionsNoRestrict?t=1608475589424&limit=20&offset=0
3.对ajax的url中参数的解释:
1. get请求
2. t=1608475589424 为 时间戳
3. limit=20 为每页的交易数量
4. offset=0 为每页的起始交易位置
4.在下面可以找到请求头中包含的参数:
5.其中的x-apiKey就是请求头中的加密参数,而且每次刷新都会变化。
x-apiKey: LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3MTk1ODY3MDA1MzExODU=
二、通过浏览器工具进行关键字定位
1.在右上方找到Search:
2.输入:x-apiKey,查询到三个结果,如图
3.可以看到第三个js文件后包含header,打开它。
这里可以点击下面的 {} 将代码格式化:
4.按快捷键Ctrl+F再次在该js文件里面查找x-apiKey
定位到x-apiKey之后,将相关联的代码段取出:
function(t, e, n) {
"use strict";
n(115),
n(57),
n(20),
n(60);
function r(t, e) {
for (var n = 0; n < e.length; n++) {
var r = e[n];
r.enumerable = r.enumerable || !1,
r.configurable = !0,
"value"in r && (r.writable = !0),
Object.defineProperty(t, r.key, r)
}
}
var o = new (function() {
function t() {
!function(t, e) {
if (!(t instanceof e))
throw new TypeError("Cannot call a class as a function")
}(this, t),
this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
}
return function(t, e, n) {
e && r(t.prototype, e),
n && r(t, n)
}(t, [{
key: "encryptApiKey",
value: function() {
var t = this.API_KEY
, e = t.split("")
, n = e.splice(0, 8);
return t = e.concat(n).join("")
}
}, {
key: "encryptTime",
value: function(t) {
var e = (1 * t + 1111111111111).toString().split("")
, n = parseInt(10 * Math.random(), 10)
, r = parseInt(10 * Math.random(), 10)
, o = parseInt(10 * Math.random(), 10);
return e.concat([n, r, o]).join("")
}
}, {
key: "comb",
value: function(t, e) {
var n = "".concat(t, "|").concat(e);
return window.btoa(n)
}
}, {
key: "getApiKey",
value: function() {
var t = (new Date).getTime()
, e = this.encryptApiKey();
return t = this.encryptTime(t),
this.comb(e, t)
}
}]),
t
}())
, i = window.utils.ont
, c = Object.assign({}, i);
c.interceptors.request.use(function(t) {
return t.url.indexOf("api/explorer/v1") > -1 && (t.headers.common["x-apiKey"] = o.getApiKey()),
t
});
e.a = c
}
三、分析相关js文件,找出具体实现方式
很明显,x-apiKey是变量o通过调用getApiKey()函数得到
t.headers.common["x-apiKey"] = o.getApiKey()
1、getApiKey()函数
找到函数定义:
key: "getApiKey",
value: function() {
var t = (new Date).getTime()
, e = this.encryptApiKey();
return t = this.encryptTime(t),
this.comb(e, t)
}
- 变量 t 是获得当前时间,变量 e 是调用encryptApiKey()得到的;
- 之后将变量 t 作为参数传递给encryptTime()函数 ,得到新的变量 t ;
- 最后将变量 t 和变量 e 作为参数传递给comb()函数,获得最终返回值x-apiKey。
2、encryptApiKey()函数
key: "encryptApiKey",
value: function() {
var t = this.API_KEY
, e = t.split("")
, n = e.splice(0, 8);
return t = e.concat(n).join("")
}
1.变量 t 是一个固定字符串,从上面可以找到
this.API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
2.变量 e 是 对变量 t 进行切片,得到 t 里的每个字符,变量 n 得到 e 里的前8个字符,即:
"a", "2", "c", "9", "0", "3", "c", "c"
3.最后的变量 t 是 将 e 去掉 n 部分并在后面接上 n ,得到新的字符串返回值
"-b31e-4547-9299-b6d07b7631aba2c903cc"
该值即为getApiKey()函数中comb()函数的 e 参数。
3、encryptTime()函数
key: "encryptTime",
value: function(t) {
var e = (1 * t + 1111111111111).toString().split("")
, n = parseInt(10 * Math.random(), 10)
, r = parseInt(10 * Math.random(), 10)
, o = parseInt(10 * Math.random(), 10);
return e.concat([n, r, o]).join("")
}
-
t 是传入的当前时间(13位的时间戳),经过字符串处理交给e;
-
变量 n , r , o 是产生的0-10的一个随机整数,并结合 e 生成新的关于当前时间和3个随机数的新字符串,比如
"2", "7", "1", "9", "4", "9", "2", "4", "3", "8", "8", "9", "9"]
该值即为getApiKey()函数中comb()函数的 t 参数。
4、comb()函数
key: "comb",
value: function(t, e) {
var n = "".concat(t, "|").concat(e);
return window.btoa(n)
}
1.变量 n 为传入参数 t 和 e 处理后得到
2719492921233667|-b31e-4547-9299-b6d07b7631aba2c903cc
2.window.btoa(n)为base64加密函数,得到加密后的 n
MjcxOTQ5MzI5ODc0MjA2NXwtYjMxZS00NTQ3LTkyOTktYjZkMDdiNzYzMWFiYTJjOTAzY2M=
3.对比浏览器请求头中的x-apiKey
LWIzMWUtNDU0Ny05Mjk5LWI2ZDA3Yjc2MzFhYmEyYzkwM2NjfDI3MTk0ODc1Mzk0ODMwOTE=
可以看到有较为明显的不一致
5、查找不一致的原因
1.将在浏览器中得到的x-apiKey通过base64解码得到
-b31e-4547-9299-b6d07b7631aba2c903cc|2719487539483091
2.而通过上述过程得到的加密前的字符串是
2719492921233667|-b31e-4547-9299-b6d07b7631aba2c903cc
3.可以轻易观察到,我们自己生成的加密前的数据和正确的数据的区别是 " | " 前后的字符串顺序;
4.经过修改顺序,得到正确结果。
6、将上述js代码改写成python代码
# 获取动态变化且加密的x-apiKey
def get_x_apikey():
# API_KEY固定字符串
API_KEY = "a2c903cc-b31e-4547-9299-b6d07b7631ab"
Key1 = API_KEY[0:8]
Key2 = API_KEY[8:]
# 交换API_KEY部分内容
new_Key = Key2 + Key1
# 获取当前时间,毫秒级
cur_time = round(time.time() * 1000)
# 处理获得的时间
new_time = str(1 * cur_time + 1111111111111)
# 生成三个0-9的随机整数
random1 = str(random.randint(0, 9))
random2 = str(random.randint(0, 9))
random3 = str(random.randint(0, 9))
# 再次处理时间字符串
cur_time = new_time + random1 + random2 + random3
# 将包含API_KEY和时间串的内容合并
this_Key = new_Key + '|' + cur_time
# 转码
n_k = this_Key.encode('utf-8')
# base64加秘
x_apiKey = base64.b64encode(n_k)
# 将加密后的x_apiKey返回
return str(x_apiKey, encoding='utf8')
至此就成功解决了这个js逆向的工作。
更多推荐
所有评论(0)